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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 15:51:54  来源:igfitidea点击:

Convert custom action filter for Web API use?

c#asp.net-mvcc#-4.0asp.net-web-apiaction-filter

提问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)