如何绑定逗号分隔值的查询字符串参数
http://localhost/Action?ids=4783,5063,5305
到控制器动作期望列表?
public ActionResult Action(List<long> ids) { return View(); }
注意!控制器动作中的ids必须有一个列表(或者基于IEnumerable的东西),所以字符串ID不被接受为答案,因为这些参数被传递给许多动作,并且将字符串解析为数组会增加不必要的噪声。
解决方法
这是我的改进版本的Nathan Taylor在解决方案中使用的解决方案。
> Nathan的活页夹只能绑定复杂模型的子属性,
而我的也可以绑定单个控制器参数。
>我的活页夹还可以通过返回一个空格来正确处理空参数
您的数组或IEnumerable的实际空实例。
要连接这个,你可以将它附加到一个单独的Controller参数:
[ModelBinder(typeof(CommaSeparatedModelBinder))]
…或将其设置为global.asax.cs中Application_Start中的全局默认绑定:
ModelBinders.Binders.DefaultBinder = new CommaSeparatedModelBinder();
在第二种情况下,它将尝试处理所有的IEnumerable,并回到ASP.NET MVC标准实现的一切。
看吧:
public class CommaSeparatedModelBinder : DefaultModelBinder { private static readonly MethodInfo ToArrayMethod = typeof(Enumerable).GetMethod("ToArray"); public override object BindModel(ControllerContext controllerContext,ModelBindingContext bindingContext) { return BindCsv(bindingContext.ModelType,bindingContext.ModelName,bindingContext) ?? base.BindModel(controllerContext,bindingContext); } protected override object GetPropertyValue(ControllerContext controllerContext,ModelBindingContext bindingContext,System.ComponentModel.PropertyDescriptor propertyDescriptor,IModelBinder propertyBinder) { return BindCsv(propertyDescriptor.PropertyType,propertyDescriptor.Name,bindingContext) ?? base.GetPropertyValue(controllerContext,bindingContext,propertyDescriptor,propertyBinder); } private object BindCsv(Type type,string name,ModelBindingContext bindingContext) { if (type.GetInterface(typeof(IEnumerable).Name) != null) { var actualValue = bindingContext.ValueProvider.GetValue(name); if (actualValue != null) { var valueType = type.GetElementType() ?? type.GetGenericArguments().FirstOrDefault(); if (valueType != null && valueType.GetInterface(typeof(IConvertible).Name) != null) { var list = (IList)Activator.CreateInstance(typeof(List<>).MakeGenericType(valueType)); foreach (var splitValue in actualValue.AttemptedValue.Split(new[] { ',' })) { if(!String.IsNullOrWhiteSpace(splitValue)) list.Add(Convert.ChangeType(splitValue,valueType)); } if (type.IsArray) return ToArrayMethod.MakeGenericMethod(valueType).Invoke(this,new[] { list }); else return list; } } } return null; } }