首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >将JSON post模型解压缩为操作参数

将JSON post模型解压缩为操作参数
EN

Stack Overflow用户
提问于 2021-03-03 13:21:49
回答 2查看 345关注 0票数 2

我的任务是将一个大型的框架ASP.NET MVC应用程序升级到.NET 5,大部分工作已经完成,但是我遇到了一个问题,就是来自使用.NET对象的前端的HTTP调用。

大多数这些POST调用都有这样一个JSON主体:

代码语言:javascript
复制
{
   "param1" : "hello",
   "param2" : "world",
   "param3" : 123
}

其相应的控制器操作如下所示:

代码语言:javascript
复制
public ActionResult SaveData(string param1, string param2, int param3)
{
    //Do save stuff
}

这在ASP.NET核心中是行不通的。参数保持为空。我找到了一个解决方案,就是将这些参数封装在一个模型对象中,并将其作为唯一具有FromBody属性的参数使用。然而,这个应用程序有数百个包含各种参数的操作,我真的不希望为所有这些都编写模型。

因此,我正在寻找一种方法,告诉ASP.NET将这些JSON对象的属性作为相应操作的参数。我搜索了一下,但找不到有用的东西。有没有办法做到这一点,还是我不得不为每一个动作写模型?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-03-03 19:32:40

您可以为此创建一个自定义ValueProvider

代码语言:javascript
复制
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

代码语言:javascript
复制
services
    .AddMvc(options =>
    {
        options.ValueProviderFactories.Add(new JsonValueProviderFactory());
        //...
    });

Notes

此实现只支持普通值而不支持复杂对象,并且需要进行一些测试。如果您将复杂对象绑定为操作参数,请执行而不是,忘记指定FromBody属性,这样就会发生默认的模型绑定,并且该值提供程序不会破坏任何内容。

票数 1
EN

Stack Overflow用户

发布于 2021-03-03 17:19:18

我的一位同事展示了他的Google-fu,最终找到了这个图书馆,这正是我所需要的。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66457955

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档