当名称不匹配时MVC UpdateModel

swi*_*ams 3 asp.net-mvc updatemodel

假设您有一个看起来像这样的模型:

public class MyClass {
    public string Name { get; set; }
    public DateTime MyDate { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

Visual Studio为您提供的默认编辑模板是MyDate属性的纯文本框.这一切都很好,但是我们可以说你需要把它分成它的月/日/年组件,你的表单看起来像:

<label for="MyDate">Date:</label>
<%= Html.TextBox("MyDate-Month", Model.MyDate.Month) %>
<%= Html.TextBox("MyDate-Day", Model.MyDate.Day) %>
<%= Html.TextBox("MyDate-Year", Model.MyDate.Year) %>
Run Code Online (Sandbox Code Playgroud)

提交时,UpdateModel由于没有定义,调用将无效MyDate-Month.有没有办法在项目中添加自定义绑定器来处理这样的情况,或者HTML输入的名称是否不同(出于何种原因)?

我发现一个解决方法是使用JavaScript在提交之前将隐藏的输入注入到表单中,这些输入连接字段并且命名正确,但这感觉不对.

Dar*_*rov 6

我建议你定制模型粘合剂:

using System;
using System.Globalization;
using System.Web.Mvc;

public class MyClassBinder : DefaultModelBinder
{
    protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
    {
        var model = (MyClass)base.CreateModel(controllerContext, bindingContext, modelType);

        var day = bindingContext.ValueProvider["MyDate-Day"];
        var month = bindingContext.ValueProvider["MyDate-Month"];
        var year = bindingContext.ValueProvider["MyDate-Year"];

        var dateStr = string.Format("{0}/{1}/{2}", month.AttemptedValue, day.AttemptedValue, year.AttemptedValue);
        DateTime date;
        if (DateTime.TryParseExact(dateStr, "MM/dd/yyyy", null, DateTimeStyles.None, out date))
        {
            model.MyDate = date;
        }
        else
        {
            bindingContext.ModelState.AddModelError("MyDate", "MyDate has invalid format");
        }

        bindingContext.ModelState.SetModelValue("MyDate-Day", day);
        bindingContext.ModelState.SetModelValue("MyDate-Month", month);
        bindingContext.ModelState.SetModelValue("MyDate-Year", year);

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

这将您的控制器操作简化为:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult MyAction(MyClass myClass)
{
    if (!ModelState.IsValid)
    {
        return View(myClass);
    }
    // Do something with myClass
    return RedirectToAction("success");
}
Run Code Online (Sandbox Code Playgroud)

并在Global.asax中注册绑定器:

protected void Application_Start()
{
    RegisterRoutes(RouteTable.Routes);
    ModelBinders.Binders.Add(typeof(MyClass), new MyClassBinder());
}
Run Code Online (Sandbox Code Playgroud)