Model binding comma separated query string parameter

前端 未结 4 1762
逝去的感伤
逝去的感伤 2020-12-02 13:45

How can I bind query string parameter that is comma separated value

http://localhost/Action?ids=4783,5063,5305

to a controller action expec

4条回答
  •  情歌与酒
    2020-12-02 13:59

    Here's my improved version of Nathan Taylor’s solution used in archil's answer.

    1. Nathan’s binder could only bind sub-properties of complex models, while mine can also bind individual controller arguments.
    2. My binder also gives you correct handling of empty parameters, by returning an actual empty instance of your array or IEnumerable.

    To wire this up, you can either attach this to an individual Controller argument:

    [ModelBinder(typeof(CommaSeparatedModelBinder))]
    

    …or set it as the global default binder in Application_Start in global.asax.cs:

    ModelBinders.Binders.DefaultBinder = new CommaSeparatedModelBinder();
    

    In the second case it will try and handle all IEnumerables and fall back to ASP.NET MVC standard implementation for everything else.

    Behold:

    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;
        }
    }
    

提交回复
热议问题