I found a really nice action filter that converts a comma-separated parameter to a generic type list: http://stevescodingblog.co.uk/fun-with-action-filters/
I would like to use it but it will not work for an ApiController, it completely ignore it. Can someone help convert this for Web API use?
[AttributeUsage(AttributeTargets.Method)] public class SplitStringAttribute : ActionFilterAttribute { public string Parameter { get; set; } public string Delimiter { get; set; } public SplitStringAttribute() { Delimiter = ","; } public override void OnActionExecuting(ActionExecutingContext filterContext) { if (filterContext.ActionParameters.ContainsKey(this.Parameter)) { string value = null; var request = filterContext.RequestContext.HttpContext.Request; if (filterContext.RouteData.Values.ContainsKey(this.Parameter) && filterContext.RouteData.Values[this.Parameter] is string) { value = (string)filterContext.RouteData.Values[this.Parameter]; } else if (request[this.Parameter] is string) { value = request[this.Parameter] as string; } var listArgType = GetParameterEnumerableType(filterContext); if (listArgType != null && !string.IsNullOrWhiteSpace(value)) { string[] values = value.Split(Delimiter.ToCharArray(), StringSplitOptions.RemoveEmptyEntries); var listType = typeof(List<>).MakeGenericType(listArgType); dynamic list = Activator.CreateInstance(listType); foreach (var item in values) { try { dynamic convertedValue = TypeDescriptor.GetConverter(listArgType).ConvertFromInvariantString(item); list.Add(convertedValue); } catch (Exception ex) { throw new ApplicationException(string.Format("Could not convert split string value to '{0}'", listArgType.FullName), ex); } } filterContext.ActionParameters[this.Parameter] = list; } } base.OnActionExecuting(filterContext); } private Type GetParameterEnumerableType(ActionExecutingContext filterContext) { var param = filterContext.ActionParameters[this.Parameter]; var paramType = param.GetType(); var interfaceType = paramType.GetInterface(typeof(IEnumerable<>).FullName); Type listArgType = null; if (interfaceType != null) { var genericParams = interfaceType.GetGenericArguments(); if (genericParams.Length == 1) { listArgType = genericParams[0]; } } return listArgType; } }
What namespace are you using for ActionFilterAttribute
? For Web API you need to be using System.Web.Http.Filters
namespace and not System.Web.Mvc
.
EDIT
Here's a rough conversion, not fully tested.
SplitStringAttribute
using System; using System.Collections.Generic; using System.ComponentModel; using System.Net.Http; using System.Web.Http.Controllers; using System.Web.Http.Filters; namespace StackOverflowSplitStringAttribute.Infrastructure.Attributes { [AttributeUsage(AttributeTargets.Method)] public class SplitStringAttribute : ActionFilterAttribute { public string Parameter { get; set; } public string Delimiter { get; set; } public SplitStringAttribute() { Delimiter = ","; } public override void OnActionExecuting(HttpActionContext filterContext) { if (filterContext.ActionArguments.ContainsKey(Parameter)) { var qs = filterContext.Request.RequestUri.ParseQueryString(); if (qs.HasKeys()) { var value = qs[Parameter]; var listArgType = GetParameterEnumerableType(filterContext); if (listArgType != null && !string.IsNullOrWhiteSpace(value)) { string[] values = value.Split(Delimiter.ToCharArray(), StringSplitOptions.RemoveEmptyEntries); var listType = typeof(List<>).MakeGenericType(listArgType); dynamic list = Activator.CreateInstance(listType); foreach (var item in values) { try { dynamic convertedValue = TypeDescriptor.GetConverter(listArgType).ConvertFromInvariantString(item); list.Add(convertedValue); } catch (Exception ex) { throw new ApplicationException(string.Format("Could not convert split string value to '{0}'", listArgType.FullName), ex); } } filterContext.ActionArguments[Parameter] = list; } } } base.OnActionExecuting(filterContext); } private Type GetParameterEnumerableType(HttpActionContext filterContext) { var param = filterContext.ActionArguments[Parameter]; var paramType = param.GetType(); var interfaceType = paramType.GetInterface(typeof(IEnumerable<>).FullName); Type listArgType = null; if (interfaceType != null) { var genericParams = interfaceType.GetGenericArguments(); if (genericParams.Length == 1) { listArgType = genericParams[0]; } } return listArgType; } } }
CsvController
using System.Web.Http; using System.Collections.Generic; using StackOverflowSplitStringAttribute.Infrastructure.Attributes; namespace StackOverflowSplitStringAttribute.Controllers { public class CsvController : ApiController { // GET /api/values [SplitString(Parameter = "data")] public IEnumerable<string> Get(IEnumerable<string> data) { return data; } } }
Example request
http://localhost:52595/api/csv?data=this,is,a,test,joe
Here is another way:
public class ConvertCommaDelimitedList<T> : CollectionModelBinder<T> { public override bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext) { var _queryName = HttpUtility.ParseQueryString(actionContext.Request.RequestUri.Query)[bindingContext.ModelName]; List<string> _model = new List<string>(); if (!String.IsNullOrEmpty(_queryName)) _model = _queryName.Split(',').ToList(); var converter = TypeDescriptor.GetConverter(typeof(T)); if (converter != null) bindingContext.Model = _model.ConvertAll(m => (T)converter.ConvertFromString(m)); else bindingContext.Model = _model; return true; } }
And list your param in the ApiController ActionMethod:
[ModelBinder(typeof(ConvertCommaDelimitedList<decimal>))] List<decimal> StudentIds = null)
Where StudentIds
is the querystring param (&StudentIds=1,2,4
)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With