MVC的UpdateModel当名称不匹配(MVC UpdateModel when the nam

2019-07-30 16:56发布

比方说,你有一个模型,它看起来有点像这样:

public class MyClass {
    public string Name { get; set; }
    public DateTime MyDate { get; set; }
}

是的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) %>

当这个被提交,到电话UpdateModel将无法工作,因为没有一个清晰MyDate-Month 。 有没有一种方法来定制粘合剂添加到项目中来处理这种情况,或者如果HTML输入名称不同(无论何种原因)?

一个解决办法,我发现是使用JavaScript注入一个隐藏的输入成串接的领域,是正确命名之前提交的形式,但我感觉这是错误的。

Answer 1:

我建议你自定义的模型绑定:

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;
    }
}

这简化了您的控制器动作:

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

并注册在Global.asax中的粘结剂:

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


Answer 2:

一个简单的方法来处理,这将是从ValueProvider手动获取值和构造日期服务器端,使用的UpdateModel与排除这些属性的白名单。

  int month = int.Parse( this.ValueProvider["MyDate-Month"].AttemptedValue );
  int day = ...
  int year = ...

  var model = db.Models.Where( m = > m.ID == id );
  var whitelist = new string[] { "Name", "Company", ... };

  UpdateModel( model, whitelist );

  model.MyDate = new DateTime( year, month, day );

当然,你需要添加验证/错误处理以及手动。



文章来源: MVC UpdateModel when the names don't match up