ActionResult参数,没有默认构造函数



显然有很多方法可以做到这一点,但我认为我应该征求一些关于这些方法的优缺点的反馈。

首先,NerdDinner教程的编辑动作是在表单(比如表单A):

[HttpPost]
public ActionResult Edit(int id, FormCollection collection) {

在我看来,如果你塑造你的ViewModels很好地匹配你的视图,那方法形式B:

[HttpPost]
public ActionResult Edit(MyViewModel mvm) {

似乎是一种更好、更简洁的方法。然后,我只是将VM属性映射到模型属性并保存。但是,如果ViewModel中嵌入了通过构造函数初始化的其他实体(例如在nerddinner教程中),则如果没有默认构造函数,则此编辑操作将失败,您将不得不使用第一种方法。

那么,第一个问题是你是否同意通常形式B更好?有缺点吗?

其次,如果使用表单B,那么装饰器类型验证将需要在ViewModel中。在ViewModels中嵌入实体并仅在实体级别保持验证是否有优势?

这是一个相当普遍的SO问题。

第一个问题是你是否同意通常形式B更好?

我唯一不使用表单B的时候是在我上传文件的时候。否则,我认为任何人都不应该使用表单A。我认为人们使用Form A的原因是缺乏对ASP能力的理解。. Net版本的MVC。

其次,如果使用表单B,那么装饰器类型验证将需要在ViewModel中。

看情况而定。我给你举个例子:

public IValidateUserName
{
  [Required]
  string UserName { get; set; }
}
public UserModel
{
  string UserName { get; set; }
}
[MetadataType(typeof(IValidateUserName))]
public UserValiationModel : UserModel
{
}

验证装饰器位于接口中。我在派生类上使用元数据类型来验证派生类型。我个人喜欢这种做法,因为它允许可重用的验证,并且元数据类型/验证不是ASP的一部分。. NET核心功能,因此它可以在ASP. NET之外使用。. Net (MVC)应用程序

在ViewModels中嵌入实体有什么好处吗…

是的,我尽我最大的努力从不传递一个基本模型给视图。这是我不做的一个例子:

public class person { public Color FavoriteColor { get; set; } }
ActionResult Details()
{
  Person model = new Person();
  return this.View(model);
}

当你想传递更多的数据给你的视图(局部或布局数据)会发生什么?大多数情况下,这些信息与Person无关,因此将其添加到Person模型中没有意义。相反,我的模型通常看起来像:

public class DetailsPersonViewModel()
{
  public Person Person { get; set; }
}
public ActionResult Details()
{
  DetailsPersonViewModel model = new DetailsPersonViewModel();
  model.Person = new Person();
  return this.View(model);
}

现在我可以添加视图需要的超出Person所知道的DetailsPersonViewModel所需的数据。例如,假设这将显示一个For,其中包含所有颜色,供Person选择一个收藏夹。所有可能的颜色都不是person的一部分,也不应该是person Model的一部分,所以我会将它们添加到DetailPersonViewModel中。

public class DetailsPersonViewModel()
{
  public Person Person { get; set; }
  public IEnumerable<Color> Colors { get; set; }
}

. .并且只在实体级别保持验证?

System.ComponentModel.DataAnnotations不是用来验证属性的属性的,所以这样做:

public class DetailsPersonViewModel()
{
  [Required(property="FavoriteColor")]
  public Person Person { get; set; }
}

不存在也没有意义。为什么ViewModel不应该包含需要验证的实体的验证?

如果没有默认构造函数,则此编辑操作失败,您必须使用第一种方法。

正确,但为什么ViewModel或ViewModel中的实体没有无参数构造函数?听起来像是一个糟糕的设计,即使有这样的需求,也可以通过ModelBinding轻松解决。下面是一个例子:

// Lets say that this person class requires 
// a Guid for a constructor for some reason
public class Person
{
  public Person(Guid id){ }
  public FirstName { get; set; }
}
public class PersonEditViewModel
{
  public Person Person { get; set; }
}
public ActionResult Edit()
{
  PersonEditViewModel model = new PersonEditViewModel();
  model.Person = new Person(guidFromSomeWhere);
  return this.View(PersonEditViewModel);
}
//View 
@Html.EditFor(m => m.Person.FirstName)
//Generated Html
<input type="Text" name="Person.FirstName" />

现在我们有了一个表单,用户可以在其中输入新的名字。我们如何在这个构造函数中获取值?很简单,ModelBinder并不关心它绑定到哪个模型,它只是将HTTP值绑定到匹配的类属性。

[MetadataType(typeof(IPersonValidation))]
public class UpdatePerson
{
  public FirstName { get; set; }
}  
public class PersonUpdateViewModel
{
  public UpdatePerson Person { get; set; }
}
[HttpPost]
public ActionResult Edit(PersonUpdateViewModel model)
{
  // the model contains a .Person with a .FirstName of the input Text box
  // the ModelBinder is simply populating the parameter with the values
  // pass via Query, Forms, etc
  // Validate Model
  // AutoMap it or or whatever
  // return a view
}

我还没有看一下NerDinner项目,但是,我通常尽量避免在一个动作的POST中有一个ViewModel,而是只提交"表单"的元素。

例如,如果ViewModel有一个Dictionary用于某种类型的下拉菜单,那么整个下拉菜单将不会被提交,只会提交所选的值。

我的一般做法是:

[HttpGet]
public ActionResult Edit(int id) 
{
     var form = _service.GetForm(id);
     var pageViewModel = BuildViewModel(form);
     return View(pageViewModel);
}
[HttpPost]
public ActionResult Edit(int id, MyCustomForm form) 
{
     var isSuccess = _service.ProcessForm(id);    
      if(isSuccess){
         //redirect
      }
      //There was an error. Show the form again, but preserve the input values
      var pageViewModel = BuildViewModel(form);
      return View(pageViewModel);
}
private MyViewModel BuildViewModel(MyCustomForm form)
{
     var viewModel = new MyViewModel();
     viewModel.Form = form;
     viewModel.StateList = _service.GetStateList();
    return viewModel;
}

相关内容

最新更新