假设您有一个看起来像这样的模型:
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在提交之前将隐藏的输入注入到表单中,这些输入连接字段并且命名正确,但这感觉不对。
答案 0 :(得分: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;
}
}
这将您的控制器操作简化为:
[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());
}
答案 1 :(得分:4)
处理此问题的一种简单方法是从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 );
当然,您还需要手动添加验证/错误处理。