我实际上很喜欢你的第三种解决方案,我将它作为所有ModelBinder的通用解决方案,方法是将它放在一个定制绑定器中,该绑定器从DefaultModelBinder
继承,并被配置为您的MVC应用程序的默认模型绑定器。
然后,使用参数中提供的类型,您可以使此新的DefaultModelBinder
自动绑定任何使用PropertyBinder
属性修饰的属性。
我从这篇优秀的文章中得到了这个想法:http://aboutcode.net/2011/03/12/mvc-property-binder.html。
我也会告诉你我采取的解决方案:
我DefaultModelBinder
:
namespace MyApp.Web.Mvc
{
public class DefaultModelBinder : System.Web.Mvc.DefaultModelBinder
{
protected override void BindProperty(
ControllerContext controllerContext,
ModelBindingContext bindingContext,
PropertyDescriptor propertyDescriptor)
{
var propertyBinderAttribute = TryFindPropertyBinderAttribute(propertyDescriptor);
if (propertyBinderAttribute != null)
{
var binder = CreateBinder(propertyBinderAttribute);
var value = binder.BindModel(controllerContext, bindingContext, propertyDescriptor);
propertyDescriptor.SetValue(bindingContext.Model, value);
}
else // revert to the default behavior.
{
base.BindProperty(controllerContext, bindingContext, propertyDescriptor);
}
}
IPropertyBinder CreateBinder(PropertyBinderAttribute propertyBinderAttribute)
{
return (IPropertyBinder)DependencyResolver.Current.GetService(propertyBinderAttribute.BinderType);
}
PropertyBinderAttribute TryFindPropertyBinderAttribute(PropertyDescriptor propertyDescriptor)
{
return propertyDescriptor.Attributes
.OfType<PropertyBinderAttribute>()
.FirstOrDefault();
}
}
}
我IPropertyBinder
接口:
namespace MyApp.Web.Mvc
{
interface IPropertyBinder
{
object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext, MemberDescriptor memberDescriptor);
}
}
我PropertyBinderAttribute
:
namespace MyApp.Web.Mvc
{
public class PropertyBinderAttribute : Attribute
{
public PropertyBinderAttribute(Type binderType)
{
BinderType = binderType;
}
public Type BinderType { get; private set; }
}
}
属性粘合剂的一个实例:
namespace MyApp.Web.Mvc.PropertyBinders
{
public class TimeSpanBinder : IPropertyBinder
{
readonly HttpContextBase _httpContext;
public TimeSpanBinder(HttpContextBase httpContext)
{
_httpContext = httpContext;
}
public object BindModel(
ControllerContext controllerContext,
ModelBindingContext bindingContext,
MemberDescriptor memberDescriptor)
{
var timeString = _httpContext.Request.Form[memberDescriptor.Name].ToLower();
var timeParts = timeString.Replace("am", "").Replace("pm", "").Trim().Split(':');
return
new TimeSpan(
int.Parse(timeParts[0]) + (timeString.Contains("pm") ? 12 : 0),
int.Parse(timeParts[1]),
0);
}
}
}
上述性质的粘合剂的实施例中使用:
namespace MyApp.Web.Models
{
public class MyModel
{
[PropertyBinder(typeof(TimeSpanBinder))]
public TimeSpan InspectionDate { get; set; }
}
}
我想这种方法可以通过重写'GetPropertyValue'来改进。有关详细信息,请参阅[我的回答](http://stackoverflow.com/a/19727630/129073)。 – Gebb 2013-11-01 13:26:18
是否可以为Web API提供类似的PropertyBinder实现? – mehul9595 2014-05-23 06:53:47
'CreateBinder'不适用于我这个构造函数,所以我放弃了'HttpContext'并使用了'var value = bindingContext.ValueProvider.GetValue(memberDescriptor.Name);'来获取属性值。 – Brad 2016-11-29 20:47:01