我的任务是将一个大型的框架ASP.NET MVC应用程序升级到.NET 5,大部分工作已经完成,但是我遇到了一个问题,就是来自使用.NET对象的前端的HTTP调用。
大多数这些POST调用都有这样一个JSON主体:
{
"param1" : "hello",
"param2" : "world",
"param3" : 123
}其相应的控制器操作如下所示:
public ActionResult SaveData(string param1, string param2, int param3)
{
//Do save stuff
}这在ASP.NET核心中是行不通的。参数保持为空。我找到了一个解决方案,就是将这些参数封装在一个模型对象中,并将其作为唯一具有FromBody属性的参数使用。然而,这个应用程序有数百个包含各种参数的操作,我真的不希望为所有这些都编写模型。
因此,我正在寻找一种方法,告诉ASP.NET将这些JSON对象的属性作为相应操作的参数。我搜索了一下,但找不到有用的东西。有没有办法做到这一点,还是我不得不为每一个动作写模型?
发布于 2021-03-03 19:32:40
您可以为此创建一个自定义ValueProvider。
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Mime;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.Net.Http.Headers;
using Newtonsoft.Json;
public class JsonValueProviderFactory : IValueProviderFactory
{
public async Task CreateValueProviderAsync(ValueProviderFactoryContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
string contentType = context.ActionContext.HttpContext.Request.Headers[HeaderNames.ContentType].FirstOrDefault();
bool isJson = contentType == null
? false
: contentType.StartsWith(MediaTypeNames.Application.Json, StringComparison.OrdinalIgnoreCase);
if (isJson)
{
context.ActionContext.HttpContext.Request.EnableBuffering();
using (var reader = new StreamReader(context.ActionContext.HttpContext.Request.Body, Encoding.UTF8, false, 1024, true))
{
string body = await reader.ReadToEndAsync();
var values = JsonConvert.DeserializeObject<Dictionary<string, object>>(body);
context.ActionContext.HttpContext.Request.Body.Seek(0, SeekOrigin.Begin); // rewind
var valueProvider = new JsonValueProvider(values);
context.ValueProviders.Add(valueProvider);
}
}
}
}
//todo: implement better logic for nested objects
public class JsonValueProvider : IValueProvider
{
private Dictionary<string, object> _values;
public JsonValueProvider(Dictionary<string, object> values)
{
_values = new Dictionary<string, object>(values, StringComparer.OrdinalIgnoreCase);
}
public bool ContainsPrefix(string prefix) => _values.ContainsKey(prefix);
public ValueProviderResult GetValue(string key)
{
return _values.TryGetValue(key, out object value)
? new ValueProviderResult(Convert.ToString(value))
: ValueProviderResult.None;
}
}在JsonValueProviderFactory中注册Startup.cs
services
.AddMvc(options =>
{
options.ValueProviderFactories.Add(new JsonValueProviderFactory());
//...
});Notes
此实现只支持普通值而不支持复杂对象,并且需要进行一些测试。如果您将复杂对象绑定为操作参数,请执行而不是,忘记指定FromBody属性,这样就会发生默认的模型绑定,并且该值提供程序不会破坏任何内容。
发布于 2021-03-03 17:19:18
我的一位同事展示了他的Google-fu,最终找到了这个图书馆,这正是我所需要的。
https://stackoverflow.com/questions/66457955
复制相似问题