如何在 .NET 6.0 中使用 MinimalApi 配置 NewtonsoftJson

Posted

技术标签:

【中文标题】如何在 .NET 6.0 中使用 MinimalApi 配置 NewtonsoftJson【英文标题】:How to configure NewtonsoftJson with MinimalApi in .NET 6.0 【发布时间】:2021-11-05 09:17:02 【问题描述】:

我的 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()
        );
);

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

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

但是,如果我在 net6.0 项目中像上面那样使用它,那么我不再使用 MinimalApi 了吗?

【问题讨论】:

【参考方案1】:

据我了解,Minimal API 依赖于一些关于类型绑定的约定。据我所知,他们在类型上搜索具有下一个签名的方法 - ValueTask&lt;TModel?&gt; BindAsync(HttpContext context, ParameterInfo parameter) 否则将尝试使用内部使用 System.Text.JsonhttpContext.Request.ReadFromJsonAsync 并且无法更改,因此 services.Add...().AddNewtonsoftJson((options) =&gt; //options); 方法将不起作用。

要使用Newtonsoft.Json,你可以尝试下一个(除了直接通过app.MapPost("/pst", (HttpContext c) =&gt; c.Request...)处理请求):

如果您可以控制所有需要使用它进行反序列化的类,则可以从某个通用基类中继承它们,该基类将具有所需签名的方法(您也可以使用带有implemented static method 的接口):

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&lt;TModel&gt; 实现非常幼稚,可能还可以改进(至少请查看HttpRequestJsonExtensions.ReadFromJsonAsync)。

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

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 model binders - 大卫·福勒。虽然我无法使它适用于services.AddControllers().AddNewtonsoftJson((options) =&gt; //options); ParameterBinder - Damian Edwards 的类似方法

【讨论】:

嘿@Guru Stron 感谢您提供详细的解释和非常有用的链接,以便更好地了解事情的运作方式。与 MVC 相比,最小 api 的方法似乎是解决方法,而不是按照设计。我会接受它作为答案,因为我检查了相同的链接,实际上我没有看到其他方法。

以上是关于如何在 .NET 6.0 中使用 MinimalApi 配置 NewtonsoftJson的主要内容,如果未能解决你的问题,请参考以下文章

.NET 6.0中使用Identity框架实现JWT身份认证与授权

.NET 6.0中使用Identity框架实现JWT身份认证与授权

.NET 6.0中使用Identity框架实现JWT身份认证与授权

.NET 6.0中使用Identity框架实现JWT身份认证与授权

在.NET 6.0中使用不同的托管模型

在.NET 6.0中使用不同的托管模型