c# - por - ¿Convertir el filtro de acción personalizado para el uso de la API web?
web api ejemplo (2)
Encontré un filtro de acción realmente bueno que convierte un parámetro separado por comas en una lista de tipos genéricos: http://stevescodingblog.co.uk/fun-with-action-filters/
Me gustaría usarlo pero no funcionará para un ApiController, lo ignorará por completo. ¿Alguien puede ayudar a convertir esto para el uso de la API web?
[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;
}
}
Aquí hay otra manera:
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;
}
}
Y enumera tu parametro en el ApiController ActionMethod:
[ModelBinder(typeof(ConvertCommaDelimitedList<decimal>))] List<decimal> StudentIds = null)
Donde StudentIds
es el StudentIds
( &StudentIds=1,2,4
)
¿Qué espacio de nombres está utilizando para ActionFilterAttribute
? Para la API web, debe utilizar el espacio de nombres System.Web.Http.Filters
y no System.Web.Mvc
.
EDITAR
Aquí hay una conversión aproximada, no completamente probada.
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 SplitStringAttribute.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 SplitStringAttribute.Infrastructure.Attributes;
namespace SplitStringAttribute.Controllers
{
public class CsvController : ApiController
{
// GET /api/values
[SplitString(Parameter = "data")]
public IEnumerable<string> Get(IEnumerable<string> data)
{
return data;
}
}
}
Solicitud de ejemplo
http://localhost:52595/api/csv?data=this,is,a,test,joe