2009-07-23 78 views
3

假設你有一個模型,它看起來有點像這樣:MVC的UpdateModel時,名稱不匹配

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韓元」 t工作,因爲MyDate-Month沒有定義。有沒有辦法將自定義聯編程序添加到項目中來處理這種情況,或者如果HTML輸入的命名方式不同(出於任何原因)?

我發現的一種解決方法是在提交之前使用JavaScript向表單中注入隱藏輸入,將字段連接並命名正確,但感覺不對。

回答

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

當然,您還需要手動添加驗證/錯誤處理。

+0

那會工作。雖然我需要使用ValueProvider []。AttemptedValue,RawValue返回一個字符串數組:)。 – swilliams 2009-07-23 18:57:20

+0

我已經更新了這個。 – tvanfosson 2009-07-23 19:36:30