【问题标题】:Convert custom action filter for Web API use?转换自定义操作过滤器以供 Web API 使用?
【发布时间】:2012-06-12 02:08:40
【问题描述】:

我发现了一个非常好的操作过滤器,它将逗号分隔的参数转换为泛型类型列表:http://stevescodingblog.co.uk/fun-with-action-filters/

我想使用它,但它不适用于 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;
    }
}

【问题讨论】:

    标签: c# asp.net-mvc c#-4.0 asp.net-web-api action-filter


    【解决方案1】:

    ActionFilterAttribute 使用什么命名空间?对于 Web API,您需要使用 System.Web.Http.Filters 命名空间,而不是 System.Web.Mvc

    编辑

    这是一个粗略的转换,没有经过全面测试。

    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;
            }
        }
    }
    

    示例请求

    http://localhost:52595/api/csv?data=this,is,a,test,joe
    

    【讨论】:

    • 我希望就这么简单。我刚试过,但它不会编译。它无法识别 filterContext.ActionParameters、filterContext.RequestContext 和 filterContext.RouteData。
    • System.Web.HttpFilters --> System.Web.Http.Filters
    • 有什么方法可以在过滤器中获取变量值,它在get方法或web api项目中web api控制器的任何方法中定义
    【解决方案2】:

    这是另一种方式:

    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;
        }
    }
    

    并在 ApiController ActionMethod 中列出您的参数:

    [ModelBinder(typeof(ConvertCommaDelimitedList<decimal>))] List<decimal> StudentIds = null)
    

    StudentIds 是查询字符串参数 (&amp;StudentIds=1,2,4)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-05-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多