2011-09-29 5 views
7

단일 개체에 모델 바인더를 호출 할 수있는 방법이 있습니까?MVC가 단일 개체에서 직접 모델 바인더를 호출합니다.

내가 원하지 않는/사용자 정의 모델 바인더가 필요합니다 - 난 그냥 이렇게 뭔가하고 싶은 :

MyViewModel1 vModel1 = new MyViewModel1(); 
InvokeModelBinder(vModel1); 

MyViewModel2 vModel2= new MyViewModel2(); 
InvokeModelBinder(vModel2); 

그리고이 완료있을 때, vModel1 및 vModel2 모두의 특성이 결합 된을 들어오는 요청에 무엇이 있는지. 컨트롤러/액션이 작성되는 방식 때문에 vModel1 및 vModel2를 액션 메소드의 입력 목록에 반드시 나열하고 싶지는 않습니다 (선택적으로 바인드 할 수있는 잠재적으로 긴 뷰 모델 목록이 될 수 있기 때문에).

답변

2

이 많은 수준 이럴에 잘못 :

  1. 이 ASP.NET MVC가 작동하도록 설계 방법이 아니다.
  2. 귀하의 행동은 그들이 기대하는 데이터에 대한 분명한 계약을 정의하지 않습니다.
  3. 무엇에서 벗어나나요? 나쁜 디자인 같은 냄새.

모델 바인딩은 리플렉션에 의해 결정됩니다. 액션이 호출되기 전에 메서드 매개 변수 목록이 반영되고 각 객체와 속성에 대해 모델 바인더를 호출하여 다양한 값 공급자 (양식 POST 값 공급자, URL 매개 변수 등)의 각 속성 값을 찾습니다. 모델 바인딩 중에 ModelState 유효성 검사도 수행됩니다.

그래서 기본 ASP.NET MVC를 사용하지 않으면이 모든 것을 잃게됩니다.

IModelBinder modelBinder = ModelBinders.Binders.GetBinder(typeof(MyObject)); 
MyObject myObject = (MyObject) modelBinder.BindModel(this.ControllerContext, ** ModelBindingContext HERE**); 

당신은 당신이 ModelBindingContext을 initalize 할 필요가 있음을 알 수 뭔가 ASP.NET MVC는 내부적으로 현재를 기반으로 할 것입니다 : 당신이 수동으로 같은 모델 바인더를 잡아하더라도

그것을 반영하는 속성.

protected virtual object GetParameterValue(ControllerContext controllerContext, ParameterDescriptor parameterDescriptor) { 
// collect all of the necessary binding properties 
Type parameterType = parameterDescriptor.ParameterType; 
IModelBinder binder = GetModelBinder(parameterDescriptor); 
IDictionary<string, ValueProviderResult> valueProvider = controllerContext.Controller.ValueProvider; 
string parameterName = parameterDescriptor.BindingInfo.Prefix ?? parameterDescriptor.ParameterName; 
Predicate<string> propertyFilter = GetPropertyFilter(parameterDescriptor); 

// finally, call into the binder 
ModelBindingContext bindingContext = new ModelBindingContext() { 
    FallbackToEmptyPrefix = (parameterDescriptor.BindingInfo.Prefix == null), // only fall back if prefix not specified 
    ModelName = parameterName, 
    ModelState = controllerContext.Controller.ViewData.ModelState, 
    ModelType = parameterType, 
    PropertyFilter = propertyFilter, 
    ValueProvider = valueProvider 
}; 
object result = binder.BindModel(controllerContext, bindingContext); 
return result; 

}

+0

'무엇부터 빠져 나갑니? 나쁜 디자인 같은 냄새가 풍긴다. "여러 모델 유형에 바인딩하기에는 좋지 않은 디자인 같지만 성능이 좋다. 초기화 된 모든 객체를 주입 할 수 있습니다. 그런 다음 설정 한 주입 객체를 사용하지 않고 가드 절을 사용하여 일찍 반환 할 수 있습니다. 또는, 가드 절 이후에 객체를 사용하기를 원한다면,'UpdateModel'이 의존성을 해결하게하십시오. 지저분하지만, 성능을 위해 디자인 거래를해야한다면 가능성이 있습니다. – StuperUser

8

사용 Controller.UpdateModel :

MyViewModel1 vModel1 = new MyViewModel1(); 
UpdateModel(vModel1); 

업데이트 컨트롤러의 ModelState는 유효성 검사 오류가있는 경우

참고 여기에서 ASP.NET MVC 소스 코드에서 냈다됩니다 (액션 모델 전달과 관련 있음), UpdateModel (모든 모델 포함)은 Upd에도 불구하고 excetion을 발생시킵니다. ateModel 성공 및 vModel1이 업데이트되었습니다. 따라서 ModelState의 오류를 제거하거나 UpdateModel을 try/catch에 넣고 excotion을 무시하십시오.

+1

FWIW, 왜이 마법을 발견하게되어 기쁩니다. '마법사'프레임 워크 (예 : 하나의 긴 양식을 '다음 페이지'및 '이전 페이지'버튼이있는 여러 개의 작은 양식으로 나누는 방법)을 구현하고 있습니다.각 개별 페이지를 POST에 대한 일반적인 컨트롤러 동작으로 되돌리려면 각 페이지에는 유효성 검사 특성이있는 강력한 형식화 된 뷰 모델이 있습니다. 하나의 공통 컨트롤러 동작이 있기 때문에 어떤 페이지가 나에게 다시 게시되는지 확인할 때까지 어떤 뷰 모델을 바인드할지 모릅니다. –