2009-07-23 5 views
3

는의가이 같은 종류의 보이는 모델을 가정 해 봅시다 :MVC UpdateModel 이름이 일치하지 않는 경우

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

비주얼 스튜디오 당신이 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를 사용하는 것입니다.하지만 잘못된 느낌입니다.

답변

6

나는 당신에게 사용자 정의 모델 바인더 제안

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

흥미로운 접근 방법. 사용자 정의 모델 바인더에 익숙하지 않아 컨트롤러에서 이것을 어떻게 호출합니까? 그리고 "normal"속성을 위해 별도의 것을 추가해야합니까 (예를 들어 이름 하나와 같은) 또는 기본 바인더가이를 처리합니까? 감사. – swilliams

+0

내 원래 게시물에서 직접 지루할 수있는 MyDate뿐만 아니라 모든 속성을 수동으로 처리해야한다는 것을 의미하는 IModelBinder를 직접 구현할 것을 제안했습니다. MyClassBinder가 "Name"과 같은 표준 속성이 기본값으로 처리된다는 것을 의미하는 DefaultModelBinder에서 파생되도록 내 게시물을 수정했습니다. –

+0

컨트롤러에서 호출 할 필요가 없습니다. Application_Start에 바인더를 등록하기 만하면 컨트롤러가 기본 모델 바인더와 같이 작동하기 전에 프레임 워크에서 호출하게됩니다. –

4

이 문제를 처리하는 간단한 방법은 ValueProvider에서 값을 수동으로 가져 와서 이러한 속성을 제외하는 White List로 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); 

물론 유효성 검사/오류 처리를 수동으로 추가해야합니다. 이것은 당신의 컨트롤러 액션을 단순화

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

:

+0

을 그 작동 할 것이다. ValueProvider []. AttemptedValue를 사용해야하지만, RawValue는 문자열 배열을 반환합니다 :). – swilliams

+0

이것을 업데이트했습니다. – tvanfosson

관련 문제