2013-01-14 3 views
4

복잡한 모델에 바인딩 할 때 모든 공용 속성이 처리되고 각각에 대해 일치 바인딩이 시도되었다고 생각했습니다.밑줄 문자열 모델 바인더

내가 모델

class Model { 
     public string Foo {get;set;} 
     public string FooBar {get;set;} 
} 

?foo=foo&foo_bar=foo_bar 

같은 쿼리 문자열을 잘

작품 사용자 정의 모델 바인더보다 더 좋은 방법이 있나요 있도록 변수 명명의 문제를 해결하기 위해 노력하고있어 ? 어쨌든 내 것은 효과가 없습니다. FooBar는 단순히 건너 뜁니다.

public class StringModelBinder : DefaultModelBinder 
    { 
     public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) 
     { 
      var model = base.BindModel(controllerContext, bindingContext); 

      if (model != null) 
       return model; 

      var modelName = Regex.Replace(bindingContext.ModelName, "([a-z])([A-Z])", "$1_$2").ToLowerInvariant(); 

      var value = bindingContext.ValueProvider.GetValue(modelName); 

      return value; 
     } 

    } 

내가 복잡한 모델에 바인딩 할 때, 모든 공용 속성을 처리하고 일치 각 시도 바인딩이 인상이었다

ModelBinders.Binders.Add(typeof(string), new StringModelBinder()); 

답변

15

에 등록.

아니요. 잘못된 인상입니다. 기본 모델 바인더는 요청에 해당 값이있는 특성 만 바인드하려고 시도합니다. 귀하의 경우 FooBar 속성에 해당 값이 없으므로 바인딩되지 않습니다.

public class Model 
{ 
    public string Foo { get; set; } 

    [ParameterName("foo_bar")] 
    public string FooBar { get; set; } 
} 

는 그래서이 구현하자 : 우리가 쓸 수있는 경우

사실은 좋은 것입니다. 당신은 속성이 인스턴스로 장식되어있는 경우이 사용자 정의 모델은 모델의 메타 데이터를 분석하고 볼 수 있듯이

public class CustomModelBinder : DefaultModelBinder 
{ 
    protected override void BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor) 
    { 
     var propertyBinderAttribute = propertyDescriptor 
      .Attributes 
      .OfType<PropertyBinderAttribute>() 
      .FirstOrDefault(); 

     if (propertyBinderAttribute != null) 
     { 
      var value = propertyBinderAttribute.BindModel(controllerContext, bindingContext); 
      propertyDescriptor.SetValue(bindingContext.Model, value); 
     } 
     else 
     { 
      base.BindProperty(controllerContext, bindingContext, propertyDescriptor); 
     } 
    } 
} 

:

[AttributeUsageAttribute(AttributeTargets.Property)] 
public abstract class PropertyBinderAttribute : Attribute, IModelBinder 
{ 
    public abstract object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext); 
} 

및 사용자 정의 모델 바인더 : 우리는 기본 속성을 작성하여 시작 PropertyBinderAttribute를 사용합니다.

우리는 다음 Application_Start 우리의 정의 하나의 기본 모델 바인더를 대체합니다 :

:

ModelBinders.Binders.DefaultBinder = new CustomModelBinder(); 

을하고 모든 것을 이제 남은 것은 우리가 우리의 모델 속성을 장식하는 데 사용되는 ParameterNameAttribute 바인더를 구현하는 것입니다

public class ParameterNameAttribute : PropertyBinderAttribute 
{ 
    private readonly string parameterName; 
    public ParameterNameAttribute(string parameterName) 
    { 
     this.parameterName = parameterName; 
    } 

    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) 
    { 
     var value = bindingContext.ValueProvider.GetValue(this.parameterName); 
     if (value != null) 
     { 
      return value.AttemptedValue; 
     } 
     return null; 
    } 
} 
+2

감사합니다 (다시) Darin! 그것은 아름답 지 않은 것이 아닙니다. – Martin

+3

+1 : 내가 자랄 때 나는 이것과 같은 답변을 게시하고 싶다! –

+0

언젠가 Darin이 저를 몇 년 동안 구했던 시간을 더할 것입니다! –