受欢迎的博客标签

Simplify your controllers with the Command Pattern and MediatR

Published

https://jonhilton.net/2016/06/06/simplify-your-controllers-with-the-command-pattern-and-mediatr/

https://beckjin.com/2020/07/19/aspnet-mediatr/

 

So you want to keep your controllers thin even as your application becomes more and more complicated. You’re concerned that your controllers are getting bloated and you’ve heard people talk about the command pattern as one possible solution. But you don’t know how the command pattern would fit into your app. How many commands should you have? Do you need separate commands every time you want to change a field in your database? Focus on features One of the nice things about the command pattern is that you can pause thinking about your implementation, and focus on your user’s interactions. Let’s say you are creating a site where users can register and log in. If you take these actions and turn them into commands you’ll end up with; RegisterUserLogIn When you focus on creating commands like these, you can stay focused on the feature in question and defer all those niggling questions about service layers, fat controllers, where to put your code etc. That’s not to say you shouldn’t consider the architecture of your app, but if you focus on the feature first, you can prove the feature works before getting bogged down with other (more technical) concerns. Hello MediatR The good news is, implementing the command pattern is simple, especially if you use Jimmy Bogard’s MediatRto send commands from your ASP.NET MVC/WebAPI controllers. With MediatR you start by creating a simple C# class to represent your command. 1 2 3 4 5 6 public class RegisterUser : IRequest<bool> {     public string EmailAddress { get; set; }     public string FirstName { get; set; }     public string LastName { get; set; } } The bool type parameter indicates the response type meaning in this case running this command will return a bool. Then in your controller action you can “send” this command using MediatR. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class UserController : Controller {     private readonly IMediator _mediator;       public UserController(IMediator mediator)     {         _mediator = mediator;     }       [HttpPost]     public ActionResult Register(RegisterUser registerUser)     {         bool registered = _mediator.Send(registerUser);         return View();     } } Points to note: Clean separation of concerns. You don’t need to pull repositories, services etc into your controller because all you need is the Mediator itself Model Binding has automatically populated the command object (RegisterUser) based on the values passed in the HTTP request This ensures your controllers stay bloat-free; focused entirely on handling requests and forwarding them on to your business logic. So how do you actually handle this command? Simple, create a handler of course! 1 2 3 4 5 6 7 8 public class RegisterUserHandler : IRequestHandler<RegisterUser, bool> {     public bool Handle(RegisterUser message)     {         // save to database         return true;     } } And that’s it. You now have a simple controller action which sends the command and a handler to handle it. Finally if you need multiple handlers to react to the same message you should take a look at MediatR notifications..