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 下测试通过。其他框架版本未测试。