在MVC/ASP.NET MVC中正确使用Model vs Controller

Jam*_*ack 28 model-view-controller asp.net-mvc

我有一个Service类,其方法名为GetProducts().这封装了业务逻辑并调用存储库以获取产品列表.

我的MVC视图想要将该产品列表显示为MVC SelectList.这个逻辑的正确位置在哪里.我似乎有3个选择:

  1. 模型

    Model应该公开一个名为的属性ProductSelectList.当View调用此属性的getter时,Model应该Service.GetProducts()在传递之前调用并将结果转换为SelectList.

    合理的论点:Model应该调用业务逻辑和存储库.视图应仅提供预定数据.除了将上下文数据传递给模型外,不应涉及Controller.

  2. 视图

    视图应包含Service.GetProducts()直接调用的代码,并将结果转换为内联的SelectList.

    合理的参数:View应直接调用此数据,因为它专门用于View.没有必要涉及模型或控制器,因为我们无论如何都在调用抽象的服务方法,所以其他任何东西都会增加额外的开销.

  3. 调节器

    Controller应该调用Service.GetProducts(),将结果转换为SelectList并将其传递给Model,该Model应该包含一个简单的ProductSelectList属性.View将访问此属性以进行渲染.

    合理的参数:Controller知道要向Service方法提供哪些参数,因此它应该进行调用.模型应该是一个简单的数据占位符,由Controller填充.View的工作是简单地从Model中呈现数据.

我有一种感觉,正确的答案是模型,但其他两个做出了一些合理的观点.也许我已经拥有了一个与模型分开的服务类,这使得水域变得混乱了?

有人愿意分享他们的意见吗?这只是品味问题吗?

Ama*_*ere 15

我个人订阅了Number 3的逻辑,允许控制器填充模型(或者有时区分View模型).

  • 我的观点愚蠢,只显示数据.
  • 我让我的View Models存储View所需的信息,偶尔暴露出"get only"属性,将其他属性格式化为更好的格式.如果我的模型需要访问我的服务,那么我觉得我做错了什么.
  • 控制器安排并收集所有信息(但没有实际工作,留给服务.

在您的示例中,我的控制器操作类似于:

public ActionResult Index()
{
    IndexViewModel viewModel = new IndexViewModel();
    viewModel.ProductSelectList = new SelectList(Service.GetProducts(), "Value", "Name");
    return View(viewModel);
}
Run Code Online (Sandbox Code Playgroud)

和我的视图模型类似:

public class IndexViewModel()
{
   public SelectList ProductSelectList { get; set; }
   public int ProductID { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

视图的适当部分看起来像:

@Html.DropDownListFor(x => x.ProductID, Model.ProductSelectList);
Run Code Online (Sandbox Code Playgroud)

这样我就满足于我知道在哪里可以看到任何问题,而且一切都有一个非常具体的地方.

然而,没有正确的方法,因为这些事情似乎总是如此.Stephen Walther有一篇关于MVC技巧的精彩博客系列.在一篇文章中,他讨论了View模型的重点,虽然不是他填充的SelectList,但SelectList仍然是数据,与他的产品列表非常相似.


Tod*_*ith 7

在经典的MVC架构中,您的模型不应该只是视图数据的容器,因此它通常被称为ViewModel.ViewModel与您的服务层管理的实体模型不同.

然后,您的控制器负责从服务层返回的实体模型中填充ViewModel.

由于方便,一些开发人员将直接在他们的ViewModel中使用他们的服务层实体,但长期可能会导致头痛.解决这个问题的一种方法是使用AutoMapper等工具自动化与ViewModel和实体模型之间的数据混洗.

这是控制器的外观.请注意,由于存在从实体模型到View模型的映射,因此SSN等数据不会显示在视图中.

public class Customer : IEntity
{
  public string CustomerID { get; set; }
  public string SSN { get; set; }
  public string FirstName { get; set; }
  public string LastName { get; set; }    
  public Address Address { get; set; }
}

public class CustomerEditViewModel
{
  public string FirstName { get; set; }
  public string LastName { get; set; }
  public string Address1 { get; set; }
  public string Address2 { get; set; }
  public string Country { get; set; }
  public string City { get; set; }
  public string State { get; set; }
  public string Zip { get; set; }
  public string PhoneNumber { get; set; }
}

public class CustomerController
{
  [AcceptVerbs (HttpVerbs.Get)]
  public ActionResult Edit ()
  {
    Customer customer = _customerService.GetCustomer (User.Identity.Name);

    var model = new CustomerEditViewModel ()
    {
      FirstName = customer.FirstName,
      LastName = customer.LastName,
      Address1 = customer.Address.Address1,
      Address2 = customer.Address.Address2,
      Country = customer.Address.Country,
      City = customer.Address.City,
      State = customer.Address.State,
      Zip = customer.Address.Zip,
      PhoneNumber = customer.Address.PhoneNumber,
    };

    return View (model);
  }
}
Run Code Online (Sandbox Code Playgroud)


ajk*_*ajk 7

你是对的,有很多方法可以解决这个问题,甚至在考虑MVP,MVVM等变体之前.既然你特别询问ASP.Net MVC,我会推迟到微软:

MVC模型包含视图或控制器中未包含的所有应用程序逻辑.该模型应包含所有应用程序业务逻辑,验证逻辑和数据库访问逻辑.例如,如果您使用Microsoft Entity Framework访问数据库,那么您将在Models文件夹中创建Entity Framework类(.edmx文件).

视图应仅包含与生成用户界面相关的逻辑.控制器应该只包含返回正确视图或将用户重定向到另一个操作所需的最小逻辑(流控制).其他所有内容都应包含在模型中.

一般来说,你应该争取胖模型和瘦控制器.您的控制器方法应该只包含几行代码.如果控制器动作太胖,那么您应该考虑将逻辑移出到Models文件夹中的新类.

资源

我会说你的电话属于模特.