Naprawdę lubię twoje trzecie rozwiązanie, tylko, zrobiłbym to ogólne rozwiązanie dla wszystkich modeli Binder, przez umieszczenie go w niestandardowym segregatorze, który dziedziczy po DefaultModelBinder
i jest skonfigurowany jako domyślny segregator dla twojej aplikacji MVC.
W takim przypadku nowy obiekt DefaultModelBinder
będzie automatycznie wiązał każdą właściwość ozdobioną atrybutem PropertyBinder
, używając typu podanego w parametrze.
Wpadłem na pomysł z tego wspaniałego artykułu: http://aboutcode.net/2011/03/12/mvc-property-binder.html.
będę również pokazać wam moje zdanie na rozwiązanie:
My 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();
}
}
}
Moja IPropertyBinder
interfejsu:
namespace MyApp.Web.Mvc
{
interface IPropertyBinder
{
object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext, MemberDescriptor memberDescriptor);
}
}
My PropertyBinderAttribute
:
namespace MyApp.Web.Mvc
{
public class PropertyBinderAttribute : Attribute
{
public PropertyBinderAttribute(Type binderType)
{
BinderType = binderType;
}
public Type BinderType { get; private set; }
}
}
Przykład spoiwa właściwość:
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);
}
}
}
przykładzie powyższego spoiwa własności używany:
namespace MyApp.Web.Models
{
public class MyModel
{
[PropertyBinder(typeof(TimeSpanBinder))]
public TimeSpan InspectionDate { get; set; }
}
}
Sądzę, że to podejście można poprawić, zastępując 'GetPropertyValue'. Zobacz [moja odpowiedź] (http://stackoverflow.com/a/19727630/129073), aby uzyskać szczegółowe informacje. – Gebb
Czy możliwe jest posiadanie podobnej implementacji PropertyBinder dla Web API? – mehul9595
'CreateBinder' nie działa dla mnie z tym konstruktorem, więc upuściłem' HttpContext' i użyłem 'var value = bindingContext.ValueProvider.GetValue (memberDescriptor.Name);', aby uzyskać wartość właściwości. – Brad