WebApi Owin OAuth(三)WebApi入参的常规习惯问题

众所周知WebApi的入参形式是很让人烦心的事情,[FromBody]、[FromUri]、参数实体封装(泛滥成灾),这些入参方式就是在墙奸程序员,至于框架的这种设计初衷无法去揣测,还好有伟大的程序员,无意中查到国外一大牛对此做了改造,表示感谢!

SimplePostVariableParameterBinding.cs

using log4net;
using Newtonsoft.Json;
using SSXLX.Api.Common;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Globalization;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using System.Web.Http.Controllers;
using System.Web.Http.Metadata;

namespace SSXLX.WebApi
{
    public class SimplePostVariableParameterBinding : HttpParameterBinding
    {
        private const string MultipleBodyParameters = "MultipleBodyParameters";
        protected static ILog logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);

        public SimplePostVariableParameterBinding(HttpParameterDescriptor descriptor) : base(descriptor) { }

        /// <summary>
        /// Check for simple binding parameters in POST data. Bind POST
        /// data as well as query string data
        /// </summary>
        /// <param name="metadataProvider"></param>
        /// <param name="actionContext"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public override Task ExecuteBindingAsync(ModelMetadataProvider metadataProvider, HttpActionContext actionContext, CancellationToken cancellationToken)
        {
            string stringValue = null;
            TaskCompletionSource<AsyncVoid> tcs = new TaskCompletionSource<AsyncVoid>();
            try
            {
                NameValueCollection col = TryReadBody(actionContext.Request);
                if (col != null)
                    stringValue = col[Descriptor.ParameterName];
                // try reading query string if we have no POST/PUT match
                if (stringValue == null)
                {
                    var query = actionContext.Request.GetQueryNameValuePairs();
                    if (query != null)
                    {
                        var matches = query.Where(kv => kv.Key.ToLower() == Descriptor.ParameterName.ToLower());
                        if (matches.Count() > 0)
                            stringValue = matches.First().Value;
                    }
                }
                object value = StringToType(stringValue);

                // Set the binding result here 给字段挨个赋值
                SetValue(actionContext, value);

                // now, we can return a completed task with no result

                tcs.SetResult(default(AsyncVoid));

            }
            catch (Exception ex)
            {
                logger.LogException("ExecuteBindingAsync", ex);
                //throw ex;
            }
            return tcs.Task;
        }


        /// <summary>
        /// Method that implements parameter binding hookup to the global configuration object's
        /// ParameterBindingRules collection delegate.
        /// 
        /// This routine filters based on POST/PUT method status and simple parameter
        /// types.
        /// </summary>
        /// <example>
        /// GlobalConfiguration.Configuration.
        ///       .ParameterBindingRules
        ///       .Insert(0,SimplePostVariableParameterBinding.HookupParameterBinding);
        /// </example>    
        /// <param name="descriptor"></param>
        /// <returns></returns>
        public static HttpParameterBinding HookupParameterBinding(HttpParameterDescriptor descriptor)
        {
            try
            {
                var supportedMethods = descriptor.ActionDescriptor.SupportedHttpMethods;
                // Only apply this binder on POST operations
                if (supportedMethods.Contains(HttpMethod.Post))
                {
                    var supportedTypes = new Type[] { typeof(string),
                                                typeof(int),
                                                typeof(long),
                                                typeof(long?),
                                                typeof(decimal),
                                                typeof(double),
                                                typeof(bool),
                                                typeof(DateTime),
                                                typeof(byte[])
                                            };
                    if (supportedTypes.Count(typ => typ == descriptor.ParameterType) > 0)
                        return new SimplePostVariableParameterBinding(descriptor);
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return null;
        }


        private object StringToType(string stringValue)
        {
            object value = null;
            try
            {
                if (stringValue == null)
                    value = null;
                else if (Descriptor.ParameterType == typeof(string))
                    value = stringValue;
                else if (Descriptor.ParameterType == typeof(int))
                    value = int.Parse(stringValue, CultureInfo.CurrentCulture);
                else if (Descriptor.ParameterType == typeof(Int32))
                    value = Int32.Parse(stringValue, CultureInfo.CurrentCulture);
                else if (Descriptor.ParameterType == typeof(Int64))
                    value = Int64.Parse(stringValue, CultureInfo.CurrentCulture);
                else if (Descriptor.ParameterType == typeof(decimal))
                    value = decimal.Parse(stringValue, CultureInfo.CurrentCulture);
                else if (Descriptor.ParameterType == typeof(double))
                    value = double.Parse(stringValue, CultureInfo.CurrentCulture);
                else if (Descriptor.ParameterType == typeof(DateTime))
                    value = DateTime.Parse(stringValue, CultureInfo.CurrentCulture);
                else if (Descriptor.ParameterType == typeof(bool))
                {
                    value = false;
                    if (stringValue == "true" || stringValue == "on" || stringValue == "1")
                        value = true;
                }
                else
                    value = stringValue;
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return value;
        }

        /// <summary>
        /// Read and cache the request body
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        private NameValueCollection TryReadBody(HttpRequestMessage request)
        {
            object result = null;
            try
            {
                if (!request.Properties.TryGetValue(MultipleBodyParameters, out result))
                {
                    var contentType = request.Content.Headers.ContentType.MediaType.ToLower();
                    if (contentType == null)
                    {
                        result = null;
                    }
                    else if (contentType.Contains("application/x-www-form-urlencoded"))
                    {
                        result = request.Content.ReadAsFormDataAsync().Result;
                    }
                    else if (contentType.Contains("application/json"))//解决json问题
                    {
                        var jsonStr = request.Content.ReadAsStringAsync().Result;//{"Name":"tongl","Age":22}
                        var json = JsonConvert.DeserializeObject<IDictionary<string, string>>(jsonStr);
                        if (json != null || json.Count > 0)
                        {
                            var nvc = new NameValueCollection();
                            foreach (var item in json)
                            {
                                nvc.Add(item.Key, item.Value);
                            }
                            result = nvc;
                        }
                    }
                    else
                    {
                        result = null;
                    }
                    request.Properties.Add(MultipleBodyParameters, result);
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return result as NameValueCollection;
        }

        private struct AsyncVoid
        {
        }
    }
}

通过NameValueCollection获取参数集合,给每个字段参数赋值,重新绑定

在WebApiConfig.cs的Register中添加参数规则过滤

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Web.Http;
using Microsoft.Owin.Security.OAuth;
using Newtonsoft.Json.Serialization;
using System.Net.Http.Formatting;

namespace SSXLX.WebApi
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Web API 配置和服务
            // 将 Web API 配置为仅使用不记名令牌身份验证。
            config.SuppressDefaultHostAuthentication();
            config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));

            // Web API 路由
            config.MapHttpAttributeRoutes();

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{action}/{id}",
                defaults: new { id = RouteParameter.Optional, action = RouteParameter.Optional }
            );

            <strong>config.ParameterBindingRules.Add(SimplePostVariableParameterBinding.HookupParameterBinding);</strong>
        }
    }
}

如此接口的参数定义则可以定义为我们常规的习惯

public async Task<IHttpActionResult> Regist(string loginName, string password, string idCard, string validCode)

也满足接口强类型语言的初衷,避免了大量的参数实体的封装造成参数实体泛滥成灾。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值