【问题标题】:Using view models in ASP.NET MVC 3在 ASP.NET MVC 3 中使用视图模型
【发布时间】:2011-07-15 11:12:28
【问题描述】:

我对查看模型比较陌生,并且在使用它们时遇到了一些问题。这是我想知道最佳做法的一种情况......

我将视图所需的所有信息放入视图模型中。这是一个例子——请原谅任何错误,这是我头脑中的代码。

public ActionResult Edit(int id)
{
    var project = ProjectService.GetProject(id);

    if (project == null)
        // Something about not found, possibly a redirect to 404.

    var model = new ProjectEdit();
    model.MapFrom(project); // Extension method using AutoMapper.

    return View(model);
}

如果屏幕只允许编辑一个或两个字段,当视图模型返回时,它会丢失相当多的数据(应该如此)。

[HttpPost]
public ActionResult Edit(int id, ProjectEdit model)
{
    var project = ProjectService.GetProject(id);

    if (project == null)
        // Something about not found, possibly a redirect to 404.

    try
    {
        if (!ModelState.IsValid)
            return View(model) // Won't work, view model is incomplete.

        model.MapTo(project); // Extension method using AutoMapper.
        ProjectService.UpdateProject(project);
        // Add a message for the user to temp data.

        return RedirectToAction("details", new { project.Id });
    }
    catch (Exception exception)
    {
        // Add a message for the user to temp data.

        return View(model) // Won't work, view model is incomplete.
    }
}

我的临时解决方案是从头开始重新创建视图模型,从域模型重新填充它,将表单数据重新应用到它,然后照常进行。但这使得视图模型参数有些毫无意义。

[HttpPost]
public ActionResult Edit(int id, ProjectEdit model)
{
    var project = ProjectService.GetProject(id);

    if (project == null)
        // Something about not found, possibly a redirect to 404.

    // Recreate the view model from scratch.
    model = new ProjectEdit();
    model.MapFrom(project); // Extension method using AutoMapper.

    try
    {
        TryUpdateModel(model); // Reapply the form data.

        if (!ModelState.IsValid)
            return View(model) // View model is complete this time.

        model.MapTo(project); // Extension method using AutoMapper.
        ProjectService.UpdateProject(project);
        // Add a message for the user to temp data.

        return RedirectToAction("details", new { project.Id });
    }
    catch (Exception exception)
    {
        // Add a message for the user to temp data.

        return View(model) // View model is complete this time.
    }
}

有没有更优雅的方式?

编辑

两个答案都是正确的,所以如果可以的话,我会奖励他们两个。不过,我向 MJ 点头,因为经过反复试验,我发现他的解决方案是最精简的。

我仍然可以使用助手,Jimmy。如果我将需要显示的内容添加到视图包(或视图数据)中,就像这样......

ViewBag.Project= project;

然后我可以执行以下操作...

@Html.LabelFor(model => ((Project)ViewData["Project"]).Name)
@Html.DisplayFor(model => ((Project)ViewData["Project"]).Name)

有点小技巧,在某些情况下它需要用System.ComponentModel.DisplayNameAttribute 装饰域模型,但我已经这样做了。

我很想打电话...

@Html.LabelFor(model => ViewBag.Project.Name)

但动态会导致表达式出现问题。

【问题讨论】:

  • 你可以在这里查看:prodinner.codeplex.com 了解 asp.net mvc 中的最佳实践(包括视图模型)

标签: c# asp.net-mvc-3 viewmodel automapper


【解决方案1】:

经过一些反复试验(也就是编码,然后讨厌它)学习,我目前首选的方法是:

我使用视图模型来绑定输入字段。因此,在您的情况下,如果您的视图仅编辑两个字段,那么您的视图模型将只有两个属性。对于填充视图所需的数据(下拉列表、标签等),我使用动态 ViewBag。

我相信显示视图(即填充视图需要显示的任何内容)和捕获发布的表单值(绑定、验证等)是两个独立的问题。而且我发现将填充视图所需的数据与从视图发回的数据混合起来会变得混乱,并且经常会准确地创建您的情况。我不喜欢被传递的部分填充的对象。

我不确定 Automapper(用于将域对象映射到动态 ViewBag)如何发挥作用,因为我没有使用它。我相信它有一个可以工作的 DynamicMap 方法?将发布的强类型 ViewModel 自动映射到 Domain 对象上应该不会有任何问题。

【讨论】:

  • 忽略 AutoMapper - 仅当您遇到映射对象的问题时,仅显示视图模型在您使用 MVC 模板化帮助程序 (Html.DisplayFor) 时非常有用。
  • 我喜欢这样的声音,因为我的视图模型只会反映我想要返回的内容,因此会变得更精简。正如 Jimmy 所说,我会失去 Html.DisplayFor,但这可以通过我自己的一些 HtmlHelper 扩展来弥补。我现在不喜欢视图模型的“税收”——这种方法的好处是可以稍微减少它。
【解决方案2】:

如果我理解正确,您的视图模型可能看起来与您的域实体非常相似。您提到视图模型可以返回大部分为空,因为只有某些字段是可编辑的。

假设您有一个视图,其中只有几个字段可用于编辑(或显示),这些是您应该在视图模型中提供的唯一字段。我通常为每个视图创建一个视图模型,让控制器或服务处理用户的输入,并在执行一些验证后将其映射到域实体。

Here 是一个关于视图模型最佳实践的主题,您可能会觉得有用。

编辑:您还可以在 Edit/POST 操作中接受不同于 Edit/GET 操作所提供的视图模型。我相信只要模型绑定器可以解决这个问题,这应该可以工作。

【讨论】:

  • 这还有一个额外的好处,就是让我的视图模型更精简。但是只显示数据到哪里去了?您是否将域模型对象(或 DTO)放在 ViewData/ViewBag 中来处理?
  • @Adam:我可能应该重新陈述我的答案。您显示的数据也应该包含在您的视图模型中。
  • @Adam:查看我的更新答案。您的编辑/发布操作只能包含可编辑字段
  • 这意味着需要重新创建 GET 视图模型(如果我希望用户看到他们更改了什么,则需要将表单数据应用到它),然后在出现无效数据时再次显示视图或例外。类似于我的问题中的最后一个操作方法,但在绝对需要之前可能不会重新创建 GET 视图模型。
  • @Adam:是的,没错。此外,当服务器端验证失败时,您必须重新创建 GET 视图模型。然而,像 AutoMapper 这样的工具使这更容易。
猜你喜欢
  • 1970-01-01
  • 2011-10-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-30
  • 1970-01-01
相关资源
最近更新 更多