ASP.NET MVC - 如何使用View Models

lit*_*rva 36 asp.net-mvc viewmodel

假设我有一个允许编辑用户详细信息的页面,所以我有一个像这样的ViewModel:

public class UserViewModel {
    public string Username { get; set; }
    public string Password { get; set; }
    public int ManagerId { get; set; }
    public string Category { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

所以在我的EditUser操作中,我可以通过模型绑定器传回它,然后我可以将其映射到域模型:

public ActionResult EditUser(UserViewModel user) {
    ...
Run Code Online (Sandbox Code Playgroud)

但是,显示表单的页面还需要详细信息,例如管理器和类别列表,以提供这些字段的下拉列表.它还可能会在侧边栏中显示其他用户的列表,以便您可以在正在编辑的不同用户之间切换.

那么我有另一个视图模型:

public class ViewUserViewModel {
    public UserViewModel EditingUser { get; set; }
    public IEnumerable<SelectListItem> Managers { get; set; }
    public IEnumerable<SelectListItem> Categories { get; set; }
    public IEnumerable<SelectListItem> AllUsers { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

这是正确的方法吗?它们都是View Models吗?如果是这样,我是否应该使用命名约定,以便区分类似模型的虚拟机和仅包含页面数据的虚拟机?

我错了吗?

Chr*_*att 94

"视图模型"只是一种模式.关于名称并没有什么神奇之处,但通常传递给视图的任何类(无论是为了简单地显示数据还是为了表单提交的目的)都被称为"视图模型"并给出一个名称FooViewModel或者FooVM表示它是一部分那个"视图模型"模式.

我不想对你过于哲学,但我认为对游戏模式的一些参考将会有所帮助.ASP.NET MVC显然足以鼓励MVC(模型 - 视图 - 控制器)架构模型.在MVC中,Model是所有应用程序业务逻辑的容器.Controller负责处理请求,获取模型,使用该模型呈现View并返回响应.这似乎是很多责任,但实际上框架在幕后处理大部分内容,因此控制器通常(并且应该)对代码非常轻松.他们负责将所有内容连接起来的最低限度的功能.最后,View负责创建允许用户与模型中的数据交互的UI层.它不对数据本身负责,也不应该对它负责(ViewData/ViewBag在这里是一个非常大的违规行为,至少与开发人员在实践中最终使用的方式一样多).

因此,这意味着您的应用程序逻辑的大部分应该在您的模型中,并且通常这是一件好事.但是,由于模型是应用程序数据的避风港,因此通常会将其保存在数据库或类似数据库中.这会产生一些利益冲突,因为您现在需要在应该保留哪些数据和仅为了显示目的而存在哪些数据之间开始平衡.

这就是视图模型的用武之地.MVVM(模型 - 视图 - 视图模型)是一种与MVC有些相似的模式,它可以识别单模型到规则 - 所有方法中的固有问题.我不会在这里详细介绍,因为MVC不使用这种模式.但是,大多数ASP.NET MVC开发人员都选择了MVVM的View Model.您最终得到的是数据库支持的实体(传统模型),然后通常是许多不同的视图模型,它们代表不同状态下的实体.这允许您的模型包含与持久性相关的业务逻辑,而视图模型包含与显示,创建和更新该模型相关的业务逻辑.

我已经偏离了一点,但是长期和短期是你正在做的事情是完全可以接受的.事实上,这是一个很好的做法.根据应用程序的需要创建尽可能多的视图模型,并使用它们实际存储视图所需的数据和业务逻辑.(包括SelectLists之类的内容.您的控制器和视图都不需要知道如何创建SelectList下拉列表.)

  • 关于这个主题的最佳解释.你应该把它放在博客上!+1 (6认同)

Mar*_*usz 20

我如何在快捷方式中这样做:

  1. 为页面上的每个表单创建单独的ViewModel类,然后使用PartialViews渲染这些类@{Html.RenderPartial("PartialName", Model.PartialModel);}.
  2. 如果页面包含html metas之类的内容,我会为metas创建单独的类,并将其放在页面上的部分中.
  3. 休息案例如"我应该把它放在分开的班级吗?" 是你的判断.

因此,例如,您有一个页面,其中包含某种登录/注册栏或弹出窗口.

public class SomePageViewModel
{
    public RegisterBarVM Register { get; set; }
    public LoginBarVM LoginBar { get; set; }

    public MetasVM Metas { get; set; }
    public string MaybePageTitle { get; set;}
    public string MaybePageContent { get; set;}

    [HiddenInput(DisplayValue = false)]
    public int IdIfNeeded { get; set; }

    public IEnumerable<SelectListItem> SomeItems {get; set;}
    public string PickedItemId { get;set; }
}

public class RegisterBarVM
{
    public string RegisterUsername {get;set;}
    public string RegisterPassword {get;set;}
    //...
}

public class LoginBarVM
{
    public string LoginUserame {get;set;}
    public string LoginPassword {get;set;}
    //...
}

//cshtml
@model yourClassesNamespace.SomePageViewModel
@{
    Html.RenderPartial("LoginBar", Model.LoginBar); //form inside
    Html.RenderPartial("RegisterBar", Model.RegisterBar); //form inside

    using(Html.BeginForm())
    {
        @Html.EditorFor(m => m.IdIfNeeded)
        @Hmtl.EditorFor(m => m.MaybePageTitle)
        @Hmtl.EditorFor(m => m.MaybePageContent)

        @Hmtl.DropDownListFor(m => m.PickedItemId, new SelectList(Model.SomeItems))

        <input type="submit" value="Update" />
    }
}

@section Metas {
    @{Html.RenderPartial("Meatas", Model.Metas}
}
Run Code Online (Sandbox Code Playgroud)

关于编辑器模板Brad Wilsons博客,只需google或查找有关显示/编辑器模板和HtmlHelpers的堆栈资源.它们对于构建一致的网站非常有用.


Jas*_*kan 9

我个人更喜欢在ViewModel中放置页面所需的所有信息,因为这是ViewModel的目的 - 为View提供所有数据.所以我UserViewModel将包含属性Managers,Categories并且AllUsers控制器将在将ViewModel传递给视图之前填充这些集合.

这基本上就是你所做的 - 它只是从等式中删除了额外的ViewModel.

我还看到其他程序员使用ViewData将下拉列表发送到视图,但我不喜欢因为ViewData不是强类型,而ViewModel是.