如何在 .NET 6.0 中使用最小 Api 配置 Newtonsoft Json

2024-05-03

I have net6.0具有最少 api 的项目,我想使用NetwtonsoftJson而不是内置的System.Text.Json用于序列化和反序列化的库。

目前我有这个配置JsonOptions并且按预期工作

builder.Services.Configure<JsonOptions>(options =>
{
    options.SerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
    options.SerializerOptions.WriteIndented = true;    
    options.SerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles;
    options.SerializerOptions.Converters.Add(new JsonStringEnumConverter(JsonNamingPolicy.CamelCase));
});

如果我尝试更改为使用的等效项Newtonsoft.Json.JsonSerializerSettings就像下面我没有得到相同的行为。相反,它看起来像使用默认值System.Text.Json配置。

builder.Services.Configure<JsonSerializerSettings>(options =>
{
    options.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
    options.Converters.Add(
        new StringEnumConverter
        {
            NamingStrategy = new Newtonsoft.Json.Serialization.CamelCaseNamingStrategy()
        });
});

In net5.0我知道我可以用这个

services.AddControllers().AddNewtonsoftJson((options) => //options); // OR
services.AddMvc().AddNewtonsoftJson((options) => //options);

但是,如果我像上面那样在我的net6.0项目然后我不再使用 MinimalApi ?


正如在docs https://learn.microsoft.com/en-us/aspnet/core/fundamentals/minimal-apis?view=aspnetcore-7.0#configure-json-deserialization-options-for-body-binding:

正文绑定源使用 System.Text.Json 进行反序列化。这是not可以更改此默认值

但也有解决方法。

根据我的理解,最小 API 依赖于一些有关类型绑定的约定。据我所知,他们搜索具有下一个签名的方法 -ValueTask<TModel?> BindAsync(HttpContext context, ParameterInfo parameter)在类型上,否则将尝试使用httpContext.Request.ReadFromJsonAsync https://github.com/dotnet/aspnetcore/blob/a450cb69b5e4549f5515cdb057a68771f56cefd7/src/Http/Http.Extensions/src/RequestDelegateFactory.cs#L588其内部使用System.Text.Json这无法改变,所以services.Add...().AddNewtonsoftJson((options) => //options);方法不会起作用。

To use Newtonsoft.Json您可以尝试下一步(除了通过直接处理请求app.MapPost("/pst", (HttpContext c) => c.Request...)):

如果您可以控制需要使用它反序列化的所有类,您可以从某个通用基类继承它们,该基类将具有具有所需签名的方法(您也可以使用接口实现静态方法 https://github.com/DamianEdwards/MinimalApiPlayground/blob/main/src/MinimalApiPlayground/Properties/IInterfaceBinder.cs):

public class BaseModel<TModel>
{
    public static async ValueTask<TModel?> BindAsync(HttpContext context, ParameterInfo parameter)
    {
        if (!context.Request.HasJsonContentType())
        {
            throw new BadHttpRequestException(
                "Request content type was not a recognized JSON content type.",
                StatusCodes.Status415UnsupportedMediaType);
        }

        using var sr = new StreamReader(context.Request.Body);
        var str = await sr.ReadToEndAsync();
        
        return JsonConvert.DeserializeObject<TModel>(str);
    }
}

及用法:

class PostParams : BaseModel<PostParams>
{
    [JsonProperty("prop")]
    public int MyProperty { get; set; }
}

// accepts json body {"prop": 2}
app.MapPost("/pst", (PostParams po) => po.MyProperty);

注意BaseModel<TModel>这个例子中的实现非常简单,可能可以改进(查看HttpRequestJsonExtensions.ReadFromJsonAsync https://github.com/dotnet/aspnetcore/blob/a450cb69b5e4549f5515cdb057a68771f56cefd7/src/Http/Http.Extensions/src/HttpRequestJsonExtensions.cs#L50至少)。

如果您无法控制模型或不想从某个基础继承它们,您可以考虑创建包装器:

public class Wrapper<TModel>
{
    public Wrapper(TModel? value)
    {
        Value = value;
    }

    public TModel? Value { get; }

    public static async ValueTask<Wrapper<TModel>?> BindAsync(HttpContext context, ParameterInfo parameter)
    {
        if (!context.Request.HasJsonContentType())
        {
            throw new BadHttpRequestException(
                "Request content type was not a recognized JSON content type.",
                StatusCodes.Status415UnsupportedMediaType);
        }

        using var sr = new StreamReader(context.Request.Body);
        var str = await sr.ReadToEndAsync();

        return new Wrapper<TModel>(JsonConvert.DeserializeObject<TModel>(str));
    }
}

用法更改为:

class PostParams
{
    [JsonProperty("prop")]
    public int MyProperty { get; set; }
}

// accepts json body {"prop": 2}
app.MapPost("/pst", (Wrapper<PostParams> po) => po.Value.MyProperty);

一些额外有用的链接:

  • MVC 模型绑定器 https://github.com/davidfowl/MinimalApiPlayground/blob/main/src/MinimalApiPlayground/Properties/ModelBinderOfT.cs——大卫·福勒着。虽然我没能让它发挥作用services.AddControllers().AddNewtonsoftJson((options) => //options);
  • 参数绑定器 https://github.com/davidfowl/MinimalApiPlayground/blob/main/src/MinimalApiPlayground/Properties/ParameterBinders.cs- 达米安·爱德华兹 (Damian Edwards) 的类似方法
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在 .NET 6.0 中使用最小 Api 配置 Newtonsoft Json 的相关文章

随机推荐

  • 在 Perl 中,如何从父进程向子进程发送消息(或信号),反之亦然?

    我正在编写一个管理多进程的程序 这就是我所做的 而且效果很好 但现在 我想将消息从子进程发送到父进程 反之亦然 从父进程到子进程 你知道最好的方法吗 你知道我所做的是否是我想要的正确方法 从子进程到父进程发送消息 信号或共享内存 反之亦然
  • 使用“nuxt build”时动态创建的类不可用 - tailwindcss nuxtjs

    我有一个 nuxtjs 项目 与 tailwindcss 一起使用 在该项目中 我动态生成负边距的类 如下所示 div class mins 1 div 整个项目在本地运行良好 但如果我运行nuxt build nuxt start 它的编
  • 有没有办法重新分区 Kafka 流中的输入主题?

    我有一个由 byte 键控的主题 我想对其进行重新分区并通过消息正文中字段中的另一个键处理该主题 我发现有KGroupedStream and groupby功能 但它需要一个聚合函数来转换为 KTable KStream 我不需要聚合 我
  • 即使我确实为变量设置了初始值,数据段也没有被初始化

    我已经编写了一个代码 该代码应该生成某种数字列表 但是即使我为它们分配了初始值 我的数据段变量也没有被初始化 This is how DS 0000 looks when I run it 这是我的代码 但数据段只保留垃圾值 MODEL s
  • 实体框架的状态模式

    我有一个模型Enquiry 它可以处于两种状态之一 还有更多状态 但出于此目的 我将仅比较两种状态 New and Closed 查询所处的状态取决于用户能够对查询执行什么操作 例如 无法删除已关闭的查询 而可以删除新的查询等等 基本示例
  • Windows Phone 8.1 应用程序多语言

    我正在使用 Visual Studio 2015 在 SilverLight 中创建 Windows Phone 应用程序 8 1 我正在用英语和阿拉伯语创建多语言应用程序 为此 我在项目中创建了 Strings 文件夹 其中包含 en U
  • 仅从 MySQL 中的日期时间 (YYYY-MM-DD HH:MM:SS) 中选择不同的日期

    执行此命令会带来以下结果 所有列中的所有日期 因此它本质上与 SELECT date 执行相同的操作 没有不同 SELECT DISTINCT date FROM daily ORDER BY date DESC 2013 02 12 16
  • 如何在 Android Studio 中为单独的模块生成签名的 APK?

    我的项目有 3 个模块 include app include videograbber include audiograbber 现在我想为Videograbber模块生成签名的APK 当我在 Android Studio 中使用 生成签
  • 自定义 UIAlertView?

    鉴于蓝色与我的 UI 界面不相配 我只是想知道是否有办法更改 uialertview 的颜色 或者使用图像代替 所有按钮 关闭 等仍然存在 Thanks CodeCropper 的优秀人员刚刚推出了一个开源控件 可让您创建自定义警报视图 这
  • Big O 用于有限、固定大小的可能值集

    这个问题 https stackoverflow com questions 12305028 java what is the best way to find first duplicate character in a string引
  • 在画布中的鼠标位置放大/缩小

    我正在尝试使用 p5 js 实现缩放功能 当前缩放级别以及 x 和 y 位置存储在controls view目的 默认位置或 0 0 位置位于左上角 问题是调整放大 缩小时的 x 和 y 位置值 以便无论视图的当前位置是什么 它都会停留在缩
  • 调试 python Web 服务

    我正在使用找到的说明here http www diveintopython net http web services user agent html 尝试检查发送到我的网络服务器的 HTTP 命令 但是 我没有看到按照教程中的建议在控制
  • cuda中有模板化的数学函数吗? [复制]

    这个问题在这里已经有答案了 我一直在寻找 cuda 中的模板化数学函数 但似乎找不到 在普通的 C 中 如果我调用std sqrt它是模板化的 并且将根据参数是浮点数还是双精度数执行不同的版本 我想要这样的 CUDA 设备代码 我的内核将真
  • registerForActivityResult TakePicture 未触发

    我尝试使用新的 registerForActivityResult 来拍照 我可以打开相机意图 但拍照后 未触发回调 并且我在 logcat 上看不到任何有关 Activity Result 或错误的信息 我也尝试了RequestPermi
  • 如何在android中格式化长整型以始终显示两位数

    我有一个倒计时器 显示从 60 到 0 的秒数 1 分钟倒计时器 当它达到 1 位数字 例如 9 8 7 时 它显示 9 而不是 09 我尝试使用String format B 02d B x 我将 x 从 long 转换为字符串 它不起作
  • 角度材质选择不会检测嵌套组件生成的选项的更改

    我正在尝试提取过滤和显示我的逻辑mat option是我的mat selects 到他们自己的组件中 然而 由于某种原因 会显示选项 但单击它们不会触发事件 我正在编写的网络应用程序有很多mat select每个都可能有很多mat opti
  • 实体框架..自引用表..获取深度=x的记录?

    我成功地在实体框架中使用自引用表 但我不知道如何获得所需深度的记录 这应该是什么逻辑 Model public class FamilyLabel public FamilyLabel this Children new Collectio
  • fread 的填充选项

    假设我有这个 txt 文件 AA 3 3 3 3 CC ad 2 2 2 2 2 ZZ 2 AA 3 3 3 3 CC ad 2 2 2 2 2 With read csv I can gt read csv linktofile txt
  • 验证仅适用于数组的第一项

    给定这个模型代码 Required Display Name Name public string Name get set 以下查看代码有效 Html LabelFor model gt model Name Html TextBoxFo
  • 如何在 .NET 6.0 中使用最小 Api 配置 Newtonsoft Json

    I have net6 0具有最少 api 的项目 我想使用NetwtonsoftJson而不是内置的System Text Json用于序列化和反序列化的库 目前我有这个配置JsonOptions并且按预期工作 builder Servi