I wrote ASP.NET MVC applications for some time, and I found them a good place to use the command template: we present each user request as a command - a set of input parameters - then this command is processed (processing includes verification and other domain logic), and the result is sent back to the user.
Another thing I used in my applications is view models. I found this to be a more convenient way to pass data to a view than using domain objects as models or populating a ViewData / ViewBag.
These 2 concepts are great for separating data that is displayed to the user from user input and its processing, but they do not quite agree with each other in ASP.NET MVC.
Let's say I want to use commands and view models when developing a simple web store where users browse products and can order a product by specifying their name and email address:
class ProductViewModel
{
public ProductViewModel(int id) { }
public int Id { get; set; }
public string Name { get; set; }
}
class OrderProductCommand
{
public int ProductId { get; set; }
[Required(ErrorMessage = "Name not specified")]
public string Name { get; set; }
[Required(ErrorMessage ="E-Mail not specified")]
public string Email { get; set; }
public CommandResult Process() { }
}
When viewing textbooks, etc. I have seen people suggest several ways to do this.
Option 1
Controller:
[HttpGet]
public ActionResult Product(int id)
{
return View(new ProductViewModel(id));
}
[HttpPost]
public ActionResult Product(OrderProductCommand command)
{
if (ModelState.IsValid)
{
var result = command.Process();
if(result.Success)
return View("ThankYou");
else
result.CopyErrorsToModelState(ModelState);
}
return Product(command.Id);
}
View:
@using (Html.BeginForm())
{
@Html.Hidden("ProductId", Model.Id)
@Html.TextBox("Name")
@Html.TextBox("Email")
<input type="submit" value="Place order" />
}
Pros : the model and the viewing command are separate from each other, the method HttpPost
looks clean
Cons : I cannot use convenient HTML helpers such as @Html.TextBoxFor(model => model.Email)
, I cannot use client validation (see my other question )
Option 2
Id
, Name
Email
command
viewModel
.
:
[HttpPost]
public ActionResult Product(ProductViewModel viewModel)
{
var command = new OrderProductCommand();
command.Id = viewModel.Id;
command.Name = viewModel.Name;
command.Email = viewModel.Email;
if (ModelState.IsValid)
}
:
@Html.TextBoxFor(m => m.Email)
...
: 1
: (, 50?), Name
Email
( command
, ), POST (. )
3
command
viewModel
.
:
[HttpPost]
public ActionResult Product(ProductViewModel viewModel)
{
var command = viewModel.Command;
if (ModelState.IsValid)
}
:
@Html.TextBoxFor(m => m.Command.Email)
...
: 1
: , ( command
), POST (. )
-
2 3, , POST. ( 2 + 1), 50 , . POST POST.
(, , -, ): 4 , ? , ?