在MVC中,什么是ViewModel?

24 浏览
0 Comments

在MVC中,什么是ViewModel?

我是ASP.NET MVC的新手。我不太明白ViewModel的目的。

什么是ViewModel,为什么我们需要在ASP.NET MVC应用程序中使用ViewModel?

如果有一个很好的例子来说明它的工作和解释,那就更好了。

admin 更改状态以发布 2023年5月25日
0
0 Comments

视图模型是表示特定视图中使用的数据模型的类。我们可以将这个类作为登录页面的模型:

public class LoginPageVM
{
    [Required(ErrorMessage = "Are you really trying to login without entering username?")]
    [DisplayName("Username/e-mail")]
    public string UserName { get; set; }
    [Required(ErrorMessage = "Please enter password:)")]
    [DisplayName("Password")]
    public string Password { get; set; }
    [DisplayName("Stay logged in when browser is closed")]
    public bool RememberMe { get; set; }
}

使用这个视图模型,您可以定义视图(Razor视图引擎):

@model CamelTrap.Models.ViewModels.LoginPageVM
@using (Html.BeginForm()) {
    @Html.EditorFor(m => m);
    
}

还有一些操作:

[HttpGet]
public ActionResult LoginPage()
{
    return View();
}
[HttpPost]
public ActionResult LoginPage(LoginPageVM model)
{
    ...code to login user to application...
    return View(model);
}

这会产生这个结果(在提交表单后,屏幕上显示验证消息):

正如您所看到的,视图模型拥有许多作用:

  • 视图模型通过只包含在视图中显示的字段,来描述视图。
  • 视图模型可以使用数据注释或IDataErrorInfo中的特定验证规则。
  • 视图模型定义了视图的外观(对于LabelForEditorForDisplayFor助手)。
  • 视图模型可以结合来自不同数据库实体的值。
  • 您可以为视图模型指定易于显示的模板,并使用DisplayFor或EditorFor助手在许多地方重复使用它们。

另一个视图模型的示例及其检索:我们想要显示基本用户数据、他的特权和用户名。我们创建一个特殊的视图模型,它只包含所需的字段。我们从数据库中不同的实体中检索数据,但视图只知道视图模型类:

public class UserVM {
    public int ID { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public bool IsAdministrator { get; set; }
    public string MothersName { get; set; }
}

检索:

var user = db.userRepository.GetUser(id);
var model = new UserVM() {
   ID = user.ID,
   FirstName = user.FirstName,
   LastName = user.LastName,
   IsAdministrator = user.Proviledges.IsAdministrator,
   MothersName = user.Mother.FirstName + " " + user.Mother.LastName
} 

0
0 Comments

视图模型代表了您希望在视图/页面上显示的数据,无论是用于静态文本还是用于可以添加到数据库(或编辑)的输入值(如文本框和下拉列表)。它与您的领域模型不同,它是视图的模型。

假设您有一个员工类,表示您的员工领域模型,它包含以下属性(唯一标识符、名字、姓氏和创建日期):

public class Employee : IEntity
{
     public int Id { get; set; }
     public string FirstName { get; set; }
     public string LastName { get; set; }
     public DateTime DateCreated { get; set; }
}

视图模型与领域模型不同之处在于,视图模型仅包含您想要在视图上使用的数据(由属性表示)。例如,假设您想要添加一个新的员工记录,您的视图模型可能看起来像这样:

public class CreateEmployeeViewModel
{
     public string FirstName { get; set; }
     public string LastName { get; set; }
}

正如您所看到的,它仅包含两个属性。这两个属性也在员工领域模型中。为什么会这样呢?Id可能不是从视图设置的,它可能是由员工表自动生成的。DateCreated也可以在存储过程或应用程序的服务层中设置。因此,在视图模型中不需要IdDateCreated。在查看已捕获的员工的详细信息(静态文本)时,您可能希望显示这两个属性。

在加载视图/页面时,在员工控制器的创建操作方法中将创建此视图模型的实例,如果需要,则填充任何字段,然后将此视图模型传递给视图/页面:

public class EmployeeController : Controller
{
     private readonly IEmployeeService employeeService;
     public EmployeeController(IEmployeeService employeeService)
     {
          this.employeeService = employeeService;
     }
     public ActionResult Create()
     {
          CreateEmployeeViewModel model = new CreateEmployeeViewModel();
          return View(model);
     }
     public ActionResult Create(CreateEmployeeViewModel model)
     {
          // Do what ever needs to be done before adding the employee to the database
     }
}

你的视图/页面可能看起来像这样(假设你正在使用 ASP.NET MVCRazor 视图引擎):

@model MyProject.Web.ViewModels.CreateEmployeeViewModel
First Name: @Html.TextBoxFor(m => m.FirstName, new { maxlength = "50", size = "50" }) @Html.ValidationMessageFor(m => m.FirstName)
Last Name: @Html.TextBoxFor(m => m.LastName, new { maxlength = "50", size = "50" }) @Html.ValidationMessageFor(m => m.LastName)

验证只会在 FirstNameLastName 上执行。使用 FluentValidation,你可能会得到这样的验证:

public class CreateEmployeeViewModelValidator : AbstractValidator
{
     public CreateEmployeeViewModelValidator()
     {
          RuleFor(m => m.FirstName)
               .NotEmpty()
               .WithMessage("First name required")
               .Length(1, 50)
               .WithMessage("First name must not be greater than 50 characters");
          RuleFor(m => m.LastName)
               .NotEmpty()
               .WithMessage("Last name required")
               .Length(1, 50)
               .WithMessage("Last name must not be greater than 50 characters");
     }
}

而使用数据注解可能是这样的:

public class CreateEmployeeViewModel : ViewModelBase
{
    [Display(Name = "First Name")]
    [Required(ErrorMessage = "First name required")]
    public string FirstName { get; set; }
    [Display(Name = "Last Name")]
    [Required(ErrorMessage = "Last name required")]
    public string LastName { get; set; }
}

关键要记住的是,视图模型只代表你要使用的数据,其他的不用。如果你有一个拥有30个属性的领域模型,而你只想更新一个属性,你可以想象出所有不必要的代码和验证。在这种情况下,你只需要在视图模型中包含这一个值/属性,而不是领域对象中的全部属性。

视图模型可能不仅包含来自一个数据库表的数据,还可以从另一张表中组合数据。以我上面关于添加新员工记录的例子为例。除了只添加名字和姓氏外,你可能还想添加员工所属的部门。这些部门列表将来自你的 Departments 表。因此,现在你的视图模型中有来自 EmployeesDepartments 表的数据。你只需要添加以下两个属性到你的视图模型中,并填充数据即可:

public int DepartmentId { get; set; }
public IEnumerable Departments { get; set; }

当编辑已经添加到数据库中的员工数据时,它与我上面的例子并没有太大的区别。创建一个视图模型,比如叫做 EditEmployeeViewModel。只在这个视图模型中包含你想要编辑的数据,比如名字和姓氏。编辑数据并点击提交按钮。不用太担心 Id 字段,因为 Id 值可能已经在 URL 中了,例如:

http://www.yourwebsite.com/Employee/Edit/3

将这个Id与您的名字和姓氏值一起传递到您的存储库层。

删除记录时,我通常遵循与编辑视图模型相同的路径。我还将具有URL,例如:

http://www.yourwebsite.com/Employee/Delete/3

当视图第一次加载时,我将使用3的Id从数据库获取员工数据。然后,我会在我的视图/页面中只显示静态文本,以便用户可以看到正在删除哪个员工。当用户单击删除按钮时,我将只使用3的Id值并将其传递给我的存储库层。您只需要Id即可从表中删除记录。

另一个要点,您不需要为每个操作创建视图模型。如果它是简单的数据,则只使用EmployeeViewModel就可以了。如果它是复杂的视图/页面,并且它们彼此不同,则建议为每个使用单独的视图模型。

我希望这可以澄清您对视图模型和域模型的任何困惑。

0