I have a scenario where I'd like to change the behavior of the DefaultModelBinder in how it binds to a List of enums.
I have an enum...
public enum MyEnum { FirstVal, SecondVal, ThirdVal }
and a class for a model...
public class MyModel
{
public List<MyEnum> MyEnums { get; set; }
}
and the POST body is...
MyEnums=&MyEnums=ThirdVal
Currently, after model binding, the MyEnums property will contain...
[0] = FirstVal
[1] = ThirdVal
Is there was a way to tell the model binder to ignore the empty value in the posted data so that MyEnums property could look like the following?
[0] = ThirdVal
You could write a custom model binder for MyModel:
public class MyModelModelBinder : DefaultModelBinder
{
protected override void SetProperty(
ControllerContext controllerContext,
ModelBindingContext bindingContext,
PropertyDescriptor propertyDescriptor,
object value)
{
if (value is ICollection<MyEnum>)
{
var myEnums = controllerContext.HttpContext.Request[propertyDescriptor.Name];
if (!string.IsNullOrEmpty(myEnums))
{
var tokens = myEnums.Split(new [] { ',' }, StringSplitOptions.RemoveEmptyEntries);
value = tokens.Select(x => (MyEnum)Enum.Parse(typeof(MyEnum), x)).ToList();
}
}
base.SetProperty(controllerContext, bindingContext, propertyDescriptor, value);
}
}
which is registered in Application_Start
:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
ModelBinders.Binders.Add(typeof(MyModel), new MyModelModelBinder());
}
UPDATE:
As requested in the comments section here's how to make the previous binder more generic:
protected override void SetProperty(
ControllerContext controllerContext,
ModelBindingContext bindingContext,
PropertyDescriptor propertyDescriptor,
object value)
{
var collection = value as IList;
if (collection != null && collection.GetType().IsGenericType)
{
var genericArgument = collection
.GetType()
.GetGenericArguments()
.Where(t => t.IsEnum)
.FirstOrDefault();
if (genericArgument != null)
{
collection.Clear();
var enumValues = controllerContext.HttpContext
.Request[propertyDescriptor.Name];
var tokens = enumValues.Split(
new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
foreach (var token in tokens)
{
collection.Add(Enum.Parse(genericArgument, token));
}
}
}
base.SetProperty(controllerContext, bindingContext, propertyDescriptor, value);
}
精彩评论