ASP.NET MVC - 视图模型和Command模式的正确用法 [英] ASP.NET MVC - Proper usage of View Model and Command pattern

查看:127
本文介绍了ASP.NET MVC - 视图模型和Command模式的正确用法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经写了一段时间的ASP.NET MVC应用程序,我发现他们是使用命令模式的好地方:我们再present每一个用户请求一个指令 - 一组输入则params的 - 然后该命令被处理(处理包括验证和其他域逻辑),并将结果发送回给用户。

I've been writing ASP.NET MVC applications for some time and I found them to be a good place for using the command pattern: we represent every user request as a command - a set of input params - then this command is processed (processing includes validation and other domain logic) and the result is sent back to the user.

我一直用我的应用程序的另一件事是视图模型。我发现他们是将数据传递到视图比使用域对象作为模型或填充的ViewData / ViewBag更便捷的方式。

Another thing I've been using in my applications is view models. I found them to be a more convenient way of passing data to the view than using domain objects as models or filling ViewData/ViewBag.

这2个概念,工作带来极大的分离所显示来自用户输入和其处理用户数据,但他们并不十分赞同在ASP.NET MVC。

These 2 concepts work great for separating data that is shown to the user from user input and its handling, but they don't 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 look through products and can order a product by providing their name and email address:

class ProductViewModel 
{
    public ProductViewModel(int id) { /* init */ }
    public int Id { get; set; }
    public string Name { get; set; }
    // a LOT of other properties (let's say 50)
}

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() { /* validate, save to DB, send email, etc. */ }
}

在通过教程看,所以我见过的人认为这样做的几种方法。

When looking through tutorials and SO I've seen people suggest several ways of doing this.

控制器:

[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);
}

查看:

@using (Html.BeginForm())
{
    @Html.Hidden("ProductId", Model.Id)
    @Html.TextBox("Name")
    @Html.TextBox("Email")
    <input type="submit" value="Place order" />
}

赞成:视图模型以及指令相互分离,在 HttpPost 方法看起来干净

Pros: view model and command are separated from each other, the HttpPost method looks clean

缺点:我不能使用便捷HTML佣工像 @ Html.TextBoxFor(型号=&GT; model.Email),我可以'T使用客户端验证(见我的其他问题

Cons: I can't use convenient HTML helpers like @Html.TextBoxFor(model => model.Email), I can't use client validation (see my other question)

我们复制编号名称电子邮件在一起他们从验证命令属性视图模型

We copy Id, Name and Email together with their validation attributes from command to 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),名称的验证电子邮件在视图模型(它应该在命令,其中域逻辑的其余部分所在做),型号为POST参数(见下文)

Cons: copying of properties seems inconvenient (what if I have 50 of them?), validation of Name and Email in view model (it should be done in command where the rest of the domain logic resides), model as a POST parameter (see below)

我们让命令的属性视图模型

控制器:

[HttpPost]
public ActionResult Product(ProductViewModel viewModel)
{
        var command = viewModel.Command;
        if (ModelState.IsValid)
        // ...
}

查看:

@Html.TextBoxFor(m => m.Command.Email)
...

赞成:所有选项的利弊1走

缺点:视图模型应该只包含数据即的显示的的用户(和命令不显示),模型参数POST(见下文)

Cons: view model should only contain data that is displayed to the user (and command is not displayed), model as POST parameter (see below)

-

我不喜欢什么选项2和3是我们使用视图模型作为一个POST方法的参数。这种方法是为处理用户输入(仅2场+ 1隐藏在这种情况下)和模型包含50,我永远不会在这个方法中使用,这将永远是空的更多的属性。且不说有必要创建视图模型一个空的构造只是为每个POST请求创建大型视图模型对象时,处理这个POST请求和不必要的内存消耗。

What I don't like about options 2 and 3 is that we use a view model as a POST method parameter. This method is meant for handling user input (only 2 fields + 1 hidden in this case) and the model contains 50 more properties that I'll never use in this method and that will always be empty. Not to mention the necessity to create an empty constructor for the view model just to handle this POST request and the unnecessary memory consumption when creating large view model objects for every POST request.

我的问题是,(这就像最长问题不断,我知道):是有一个秘密的选项4 作为正确使用命令和视图模型具有所有的利弊没有其他的人的利弊?还是我多心而这些缺点都不是重要的,可以忽略不计?

My question is (that's like the longest question ever, I know): is there a secret Option 4 for properly using commands and view models that has all of the pros and none of the cons of the other ones? Or am I being paranoid and these cons are not that important and can be ignored?

推荐答案

似乎是唯一体面的方式去是使用局部视图渲染的形式和使用 OrderProductCommand 作为视图模型。

Seems like the only other decent way go is to use a partial view for rendering the form and use OrderProductCommand as the view model.

Product.cshtml:

@model ProductViewModel
...
@Html.Partial("Product_OrderForm", new OrderProductCommand { ProductId = Model.Id })
...

Product_OrderForm.cshtml:

@model OrderProductCommand
...
@using (Html.BeginForm("Product", "Home"))
{
    @Html.HiddenFor(cmd => cmd.ProductId)
    @Html.TextBoxFor(cmd => cmd.Name)
    @Html.TextBoxFor(cmd => cmd.Email)
    <input type="submit" value="Place order" />
}
...

这样就没有必要创建视图模型和业务对象之间的数据映射,可以留在控制器code干净的,因为它是在选项1

[HttpGet]
public ActionResult Product(int id)
{
    return View(new ProductViewModel(id));
}

[HttpPost]
public ActionResult Product(OrderProductCommand command)
{
    // process command...
}

这篇关于ASP.NET MVC - 视图模型和Command模式的正确用法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆