zoukankan      html  css  js  c++  java
  • WebApi 中请求的 JSON 数据字段作为 POST 参数传入

      使用 POST 方式请求 JSON 数据到服务器 WebAPI 接口时需要将 JSON 格式封装成数据模型接收参数。即使参数较少,每个接口仍然需要单独创建模型接收。下面方法实现了将 JSON 参数中的字段作为接口参数接收。实现的并不完美,现在只支持 JSON 格式顶级结构字段作为参数使用,且未处理复杂格式参数。

      每个接收参数都会进行 JSON 反序列化操作,故参数多的情况下创建模型接收显然更节省资源。

      以下方法只进行过简单测试,如有问题,还请大佬们自行解决,解决后希望能在此留言与诸位网友分享。

    POST 提交的 JSON 数据演示:

    {'Code':10000,Msg:'中文测试'}

    WebApi 中获取方式:

            [HttpPost]
            public string Post([FromJson]int Code,[FromJson]string Msg)
            {
                return "OK";
            }

    FromJson 类:

        public class FromJsonAttribute : Attribute, IBindingSourceMetadata
        {
            public BindingSource BindingSource
            {
                get
                {
                    return BindingSource.Custom;
                }
            }
        }

    ModelBuilder 类:

        public class JsonParameterModelBinder : IModelBinder
        {
            private readonly BodyModelBinder bodyModelBinder;
    
            public JsonParameterModelBinder(IList<IInputFormatter> formatters, IHttpRequestStreamReaderFactory readerFactory)
            {
                bodyModelBinder = new BodyModelBinder(formatters, readerFactory);
            }
    
            public Task BindModelAsync(ModelBindingContext bindingContext)
            {
                if (bindingContext == null)
                    throw new ArgumentNullException(nameof(bindingContext));
    
                var postStr = string.Empty;
                using (StreamReader sr = new StreamReader(bindingContext.HttpContext.Request.Body))
                    postStr = sr.ReadToEndAsync().Result;
    
                var jobj = Newtonsoft.Json.JsonConvert.DeserializeObject<Newtonsoft.Json.Linq.JObject>(postStr);
                var val = jobj[bindingContext.FieldName]?.ToObject<object>();
    
                if (val != null)
                    bindingContext.Result = ModelBindingResult.Success(Convert.ChangeType(val, bindingContext.ModelType, null));
    
                //将流重新写回 Request.Body 不然第二个参数再操作时会报错
                bindingContext.HttpContext.Request.Body = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(postStr));
    
                return Task.CompletedTask;
            }
        }

    Provider 类:

        public class JsonParameterModelBinderProvider : IModelBinderProvider
        {
            private readonly IList<IInputFormatter> _formatters;
    
            public JsonParameterModelBinderProvider(IList<IInputFormatter> Formatters)
            {
                _formatters = Formatters;
            }
    
            public IModelBinder GetBinder(ModelBinderProviderContext context)
            {
                if (context == null)
                    throw new ArgumentNullException(nameof(context));
    
                if (context.BindingInfo.BindingSource != null && context.BindingInfo.BindingSource.CanAcceptDataFrom(BindingSource.Custom))
                    return new JsonParameterModelBinder(_formatters, context.Services.GetRequiredService<IHttpRequestStreamReaderFactory>());
    
                return null;
            }
        }

    修改 Startup.cs 的 void ConfigureServices(IServiceCollection services) 方法,增加:

                services.AddMvc(options =>
                {
                    options.ModelBinderProviders.Insert(0, new JsonParameterModelBinderProvider(options.InputFormatters));
                });

    插入到 0 位置,优先处理,尽量不要使用 Add 方法插入到末位,否则可能不会被处理。

    以上代码在 .Net 5 下测试通过。其他框架版本未测试。

  • 相关阅读:
    斯坦福大学Andrew Ng教授主讲的《机器学习》公开课观后感
    关于内推,你该知道的点点滴滴
    向大学说拜拜——大学 > 兴趣 + 时间 + 思考 + 实践
    源码浅析:InnoDB聚集索引如何定位到数据的物理位置,并从磁盘读取
    5.7.17版本mysqlbinlog实时拉取的二进制日志不完整的原因分析
    InnoDB的ibd数据文件为什么比data_length+index_length+data_free的总和还要大?
    gh-ost工具在线改表过程的详细解析
    MySQL5.7 使用utf8mb4字符集比latin1字符集性能低25%,你敢信?
    通过slow query log可以查出长时间未提交的事务吗?用实验+源码来揭晓答案
    源码浅析:MySQL一条insert操作,会写哪些文件?包括UNDO相关的文件吗?
  • 原文地址:https://www.cnblogs.com/oangs/p/14273813.html
Copyright © 2011-2022 走看看