C# 为 Web API 使用转换自定义操作过滤器?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10941669/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Convert custom action filter for Web API use?
提问by TruMan1
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/
我发现了一个非常好的动作过滤器,它将逗号分隔的参数转换为通用类型列表: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?
我想使用它,但它不适用于 ApiController,它完全忽略它。有人可以帮助将其转换为 Web API 使用吗?
[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;
}
}
采纳答案by Jonathan
What namespace are you using for ActionFilterAttribute? For Web API you need to be using System.Web.Http.Filtersnamespace and not System.Web.Mvc.
你用什么命名空间ActionFilterAttribute?对于 Web API,您需要使用System.Web.Http.Filters命名空间而不是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
CSV控制器
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
回答by TimDog
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:
并在 ApiController ActionMethod 中列出您的参数:
[ModelBinder(typeof(ConvertCommaDelimitedList<decimal>))] List<decimal> StudentIds = null)
Where StudentIdsis the querystring param (&StudentIds=1,2,4)
StudentIds查询字符串参数在哪里( &StudentIds=1,2,4)

