使用模型绑定器时在 ASP.NET MVC 中往返视图数据

Posted

技术标签:

【中文标题】使用模型绑定器时在 ASP.NET MVC 中往返视图数据【英文标题】:Round-tripping view data in ASP.NET MVC while using Model Binders 【发布时间】:2011-01-05 02:06:03 【问题描述】:

假设我有一个包含以下“业务对象”的表单:

public class MyObject

    public string Name  get; set; 
    public User OtherUser  get; set; 
    public DateTime CreateDate  get; set; 
    public DateTime? StartDate  get; set; 
    public DateTime? EndDate  get; set; 

当用户在任何字段中输入数据时,我需要往返输入他们输入的内容,以便他们更正任何粗手指等,而无需重新输入他们的响应。

因为我不能在 DateTime 字段中往返传递像“2011 年 2 月 31 日”这样的值,所以我最终使用了这样的 View Model 对象:

public class MyObjectViewModel

    public string Name  get; set; 
    public string OtherUserName  get; set; 
    public string CreateDate  get; set; 
    public string StartDate  get; set; 
    public string EndDate  get; set; 

好的,一切都很好,花花公子,当使用以下模式时,我可以让它呈现与裸业务对象和值往返完全相同的效果:

public ActionResult Create(FormCollection form)

    var model = new MyObjectViewModel();
    if (TryUpdateModel(model, form) && ModelState.IsValid)
    
         // ...
    

    return View(model);

我有以下问题:

    将数据从视图模型中取出并放入业务对象的最简洁方法是什么? (即上述方法的其余部分是什么?) 能否减少对象之间的字段名称重复,从而巩固我的更改? 在上面的例子中,字段OtherUserName是一个string,需要转换成一个User对象。这是谁的责任?控制器?视图模型?模型粘合剂?

【问题讨论】:

【参考方案1】:
    AutoMapper 你不需要。 映射器

例子:

[HttpPut]
public ActionResult Create(MyObjectViewModel viewModel)

    if (!ModelState.IsValid)
    
        // there are validation errors => redisplay the view
        return View(viewModel);
    
    var model = Mapper.Map<MyObjectViewModel, MyObject>(viewModel);
    _repository.DoSomethingWithTheModel(model);
    return RedirectToAction("Success")

【讨论】:

+100 用于 AutoMapper。为了加强#2,消除重复,imo,不应该是最强的动力。我似乎在某些点上发现了重复——ViewModels 作为应用层边界交叉点就是这样一个点——复杂性净降低了。也就是说,是的,有一些相互镜像的对象会增加复杂性。但这种复杂性相对较小。减少视图和域之间的耦合具有更大的效果,同样是 imo。 有趣... automapper 会更新现有对象的属性吗? @John,AutoMapper 自动映射具有相同名称的属性。如果有不同的名称/规则,您需要定义它们。 另外,#3 会是什么样子?我已经在使用自己的基于反射的机制进行映射,但我对工作的完成方式不满意。 @John,这取决于User 对象与string 的关系。【参考方案2】:

您的问题主要是由于允许视图模型包含无效数据引起的。在视图模型上使用与数据类相同的强类型,添加一点 javascript 验证,“Feb 31”将永远不会到达服务器。解析类型绝对是模型绑定器的责任——您不需要做任何事情,您的控制器操作只需传递一个强类型模型对象。不过,用户可能有点不同——主要区别可能是您的视图模型有一个名为用户名的字段,而数据模型需要一个用户对象,其中包含表单上没有的信息。您的控制器需要获取/创建适当的用户对象并将其添加到数据类中。

在解析模型后,您仍然会在服务器端进行一些验证,但这将是更多自定义内容,例如检查字段是否相互一致,而不是简单的字符串格式问题。

为了减少重复,我在另一个问题上发布了我的模型风格 - asp.mvc model design

【讨论】:

【参考方案3】:

1) 您可以强烈键入您的视图,以便视图通过控制器“MyObject”类型。 2)不知道我明白你在问什么 3) 为什么不将此字段设为包含链接 ID 的外键的 ID?

另外 - 没有理由不能将日期时间字段传递给视图并按原样返回。您不需要将其作为字符串传递并进行转换。

PS - 我建议查看本教程 - 应该为您澄清我的答案。

http://www.asp.net/mvc/videos/what-is-aspnet-mvc-80-minute-technical-video-for-developers-building-nerddinner

【讨论】:

1) 首先,我的观点是强类型的。此外,不,如果我这样做,数据不会往返,我无法以这种方式更新现有的数据库对象。 3) 你要我让用户输入数据库中对象的 ID 吗?我认为这不会顺利进行。 1) 那么最简洁的方法是告诉您的控制器期待“MyObject”类型而不是 FormCollection。如果您使用的是强类型视图,绑定就这么简单。 3) 不,我通常通过 JSON/AJAX 检索友好名称并将其绑定到下拉列表。然后用户可以选择它,但 ID 会传递给控制器​​(您需要一些 javascript 帮助来执行此操作 - 在视图中需要它来将所选 ID 绑定到隐藏的模型 ID 字段)。

以上是关于使用模型绑定器时在 ASP.NET MVC 中往返视图数据的主要内容,如果未能解决你的问题,请参考以下文章

asp.net core mvc 2中抽象类的模型绑定器

为啥 ASP.Net MVC 模型绑定器将空 JSON 数组绑定到 null?

ASP.NET 5 MVC 6 RC1 API 中的自定义模型绑定异常

将自定义模型绑定器应用于 asp.net 核心中的对象属性

自定义模型绑定器未针对 ASP.NET Core 2 中的单个属性触发

Asp.net Core 模型绑定器接受布尔类型的随机整数