如何使用.NET 6.0中的最小API配置Newtonsoftjson

发布于 2025-02-13 19:55:19 字数 1254 浏览 4 评论 0 原文

我有 net6.0 带有最小API的项目,我想使用 netwtonsoftjson 而不是内置 system.text.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));
});

配置行为。相反,它看起来使用默认 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?

I have net6.0 project with minimal api and I would like to use NetwtonsoftJson instead of built in System.Text.Json library for serialization and deserialization.

At the moment I have this configurations for JsonOptions and that works as expected

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));
});

If I try to change to something equivalent that uses Newtonsoft.Json.JsonSerializerSettings like below I am not getting same behavior. Instead it looks like it uses default System.Text.Json configuration.

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

In net5.0 I know I could use this

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

However, if I use it like above in my net6.0 project then I am not using anymore MinimalApi ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

从来不烧饼 2025-02-20 19:55:20

docs

身体绑定源使用system.text.json进行绝对化。它是不是可以更改此默认的

,因此我建议仅使用 system.text.json 。但是,如果真的需要 - 您可以尝试一些解决方法。

根据我的理解,最小的API依赖于有关类型结合的一些惯例。从我可以看到他们搜索下一个签名的方法 - valuetask&lt; tmodel?&gt; bindasync(httpcontext上下文,参数参数) href =“ https://github.com/dotnet/aspnetcore/blob/a450cb69b5e4549f5551515cdb05771f568771f56cefd7/src/src/http/http/httppp.extp.extensionsionsion noreferrer“> httpcontext.request.request.readfromjsonasync 内部使用 system.text.json ,并且无法更改,因此 services.add。 。

要使用 newtonsoft.json 您可以尝试下一个(除了通过 app.mappost直接处理请求(“/pst”,(httpcontext c)=&gt; c.request ...)< /code>):

如果您对所有需要使用它的类进行控制

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模型粘合剂 - David Fowler。尽管我无法使其适用于 services.addcontrollers()
  • 。 href =“ https://github.com/davidfowl/minimalapiplayground/blob/main/main/src/minimalapiplayground/properties/properties/parameterbinders.cs” rel =“ nofollow norefloll noreferrer”>

As mentioned in the docs:

The body binding source uses System.Text.Json for deserialization. It is not possible to change this default

So I would recommend to just use System.Text.Json. But if really needed - there are workarounds you can try.

From my understanding Minimal APIs rely on some conventions regarding type binding. From what I can see they search for method with next signature - ValueTask<TModel?> BindAsync(HttpContext context, ParameterInfo parameter) on the type otherwise will try to use httpContext.Request.ReadFromJsonAsync which internally uses System.Text.Json and that can't be changed, so services.Add...().AddNewtonsoftJson((options) => //options); approach will not work.

To use Newtonsoft.Json you can try next (other than directly handling request via app.MapPost("/pst", (HttpContext c) => c.Request...)):

If you have control over all your classes which needs to be deserialized using it you can inherit them all from some generic base class which will have the method with needed signature (also you can use interface with 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);
    }
}

And usage:

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

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

Note that BaseModel<TModel> implemenation in this example is quite naive and possibly can be improved (check out HttpRequestJsonExtensions.ReadFromJsonAsync at least).

If you don't have control over the models or don't want to inherit them from some base you can look into creating wrappers:

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));
    }
}

And usage changes to:

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

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

Some extra useful links:

  • MVC model binders - by David Fowler. Though I was not able to make it work for services.AddControllers().AddNewtonsoftJson((options) => //options);
  • ParameterBinder - similar approach by Damian Edwards
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文