In previous posts I've covered different ways of creating and populating view models. Thus far I've only focused on presenting data from the server within a view. But what if I were posting a populated model back to the controller? Well, I could use a view model for that too. The nice thing about MVC is that I don't have to. The default model binder will bind to any type with matching properties. This means that we can create a clear separation around the direction the data travels. We can differentiate between data we display in the view and data we pass back to the server. In this post I'll discuss an alternative approach to passing data back to the server. The Command Pattern.
The theory
The command pattern is a pattern within a compound pattern known as CQRS. This stands for Command Query Responsibility Segregation. The pattern builds on the idea that we can use a different model to read data than we use to update data. For an MVC application, this means we split the way we handle query data from the way we handle command data. Data heading towards the view from the domain is query data. We've queried it from a data source and encapsulate it within a view model. Data heading towards the domain from the view is command data. We encapsulate this within a command. We then use a command handler to execute that command. The handler handles pulling the data out of the command and updating it within the domain.
For more detailed discussions around CQRS, Event Sourcing and DDD in general, take a look at Daniel Whittaker’s blog
The Players
public abstract class Command
{
}
public interface ICommandHandler<in TCommand>
where TCommand : Command
{
void Execute(TCommand command);
}
public interface ICommandHandler<in TCommand, out TReturn>
where TCommand : Command
{
TReturn Execute(TCommand command);
}
The command pattern I discuss here differs somewhat from the Gang of Four Command Pattern. The main difference is that here the handler contains the execute method. The command itself is just a dumb collection of properties. We should use it exactly like we use a view model. We could add an Execute()
method to the command itself, but let’s keep the command simple.
A Practical Example
In this example we’ll focus on a trimmed down form. This form has a DropDownList
and a TextBox
. Here it is:
Even in this small example we've got some data that is display-specific. We could just use a view model for both display and update purposes. If we did that here we’d have to ignore the display data when performing the update. No big deal if it’s only 1 or 2 properties. But what if the form is long and complex? What if the page has a lot of display logic? We can ignore all of that if we use commands and handlers for our update pipeline. It doesn't even need to be there.
Here’s the ViewModel for our example:
public class EditUserViewModel
{
public string UserId { get; set; }
public string FullName { get; set; }
public string EmailAddress { get; set; }
public IEnumerable<string> AgeRanges { get; set; }
public string SelectedAgeRange { get; set; }
}
Here’s the associated Command:
public class EditUserCommand : Command
{
public string UserId { get; set; }
public string EmailAddress { get; set; }
public string SelectedAgeRange { get; set; }
}
Even in this small example, you can see that we're ignoring some of the view model properties. We're just interested in the ones we'll be updating.
Let’s add a handler for this command. Inside the handler, we’re going to find the user by id and update its properties. We’ll then pass it to a UserService
for saving. I'm not focusing on the UserService
in this article. Let's just assume we have one and it talks to a data store somewhere.
public class EditUserCommandHandler : ICommandHandler<EditUserCommand>
{
private readonly IUserService userService;
public EditUserCommandHandler(IUserService userService)
{
this.userService = userService;
}
public void Execute(EditUserCommand command)
{
var user = userService.FindById(command.UserId);
user.EmailAddress = command.EmailAddress;
user.AgeRange = command.SelectedAgeRange;
userService.Update(user);
}
}
Now that we have our command and handler, let’s hook everything up within a Controller. Our UserController
has Edit actions for getting and posting our user data. For the Get action, we’re going to use a factory to create our view model. If you missed my earlier articles on using factories, here’s a recap:
public class UserController : Controller
{
private readonly IViewModelFactory<string, EditUserViewModel> editUserViewModelFactory;
private readonly ICommandHandler<EditUserCommand> editUserCommandHandler;
public UserController(IViewModelFactory<string, EditUserViewModel> editUserViewModelFactory, ICommandHandler<EditUserCommand> editUserCommandHandler)
{
this.editUserViewModelFactory = editUserViewModelFactory;
this.editUserCommandHandler = editUserCommandHandler;
}
public ActionResult EditUser(string userId)
{
var model = editUserViewModelFactory.Create(userId);
return View(model);
}
[HttpPost]
public ActionResult EditUser(EditUserCommand command)
{
editUserCommandHandler.Execute(command);
return RedirectToAction("EditUser", command.UserId);
}
}
For the Post action, we're going to let the default model binder work its magic. We're passing an EditUserCommand
into the Action instead of an EditUserViewModel
. Our command has UserId
, EmailAddress
and SelectedAgeRange
properties just like the view model. Because of this the model binder creates an EditUserCommand
with those properties populated. We can then pass that straight over to the handler to execute it.
Brucey Bonuses
This is a simple example at the moment. More than likely we would have validation in a real application. We might also want to display a success or error message to the user once the handler has executed. I'll leave validation for another article. It's trivial to recreate the view model if validation fails though.
[HttpPost]
public ActionResult EditUser(EditUserCommand command)
{
if (!ModelState.IsValid)
{
var model = editUserViewModelFactory.Create(command.UserId);
return View(model);
}
editUserCommandHandler.Execute(command);
return RedirectToAction("EditUser", command.UserId);
}
Notice that we're not re-mapping the values from the command to the view model. The default model binder remembers them all for us.
As far as displaying a message in the view goes, we can use TempData
for that. Here's an article explaining just how to do that:
Wrapping up
We've covered a lot here, so let's recap:
- We've looked at CQRS, an approach for splitting our read data from our update data.
- To enable this in MVC, we've implemented the Command pattern.
- We've created an
EditUserCommand
and EditUserCommandHandler
to update our user data.
- We've passed the command to the post action of our controller and executed it via the handler.
- We've also looked at repopulating our view via the factory if we have validation errors.
View original article