Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert custom action filter for Web API use?

Tags:

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;     } } 
like image 518
TruMan1 Avatar asked Jun 08 '12 00:06

TruMan1


2 Answers

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 
like image 162
Jonathan Avatar answered Dec 20 '22 16:12

Jonathan


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)

like image 20
TimDog Avatar answered Dec 20 '22 15:12

TimDog