gpt4 book ai didi

c# - 如何配置两个JSON序列化器并根据路由选择正确的一个

转载 作者:行者123 更新时间:2023-12-03 22:00:34 24 4
gpt4 key购买 nike

我有一个使用 .Net Framework 4.7 的 ASP.NET Core Web API 项目,我正在升级到 .Net Core 3.1。我升级的原因之一是使用新的 System.Text.Json 序列化程序。

目前,我有一些基于路由的 API 版本,例如:

/api/v1/controller
/api/v2/controller

我将创建一个新的 (v3) 来使用新的序列化程序。但问题是:我想在旧路由上继续使用 JSON.Net,以避免集成客户端出现任何可能的格式问题。

有没有一种简单的方法来配置 Asp.Net Core 以根据路由自动选择正确的 JSON 序列化程序?

最佳答案

您可以创建自己的 super InputFormatter/OutputFormatter以便它在运行时检查条件,然后决定使用 System.Text.Json或使用 Newtonsoft.Json动态。

例如,我们可以检查当前的操作方法(或 Controller 类):

  • 如果它有 [UseSystemTextJsonAttribute] 的自定义属性,然后使用 System.Text.Json
  • 如果它有 [UseNewtonsoftJsonAttribute] 的自定义属性,然后使用 Newtonsoft.Json .

  • 我创建了一个自定义 InputFormatter 供您引用:

    // the custom attribute
    internal abstract class UseJsonAttribute : Attribute, IAsyncActionFilter
    {
    public Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) => next();
    }
    internal class UseSystemTextJsonAttribute : UseJsonAttribute { }
    internal class UseNewtonsoftJsonAttribute : UseJsonAttribute { }

    // Our Super Input Formatter
    internal class MySuperJsonInputFormatter : TextInputFormatter
    {
    public MySuperJsonInputFormatter()
    {
    SupportedEncodings.Add(UTF8EncodingWithoutBOM);
    SupportedEncodings.Add(UTF16EncodingLittleEndian);
    SupportedMediaTypes.Add("application/json");
    }

    public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding)
    {
    var mvcOpt= context.HttpContext.RequestServices.GetRequiredService<IOptions<MvcOptions>>().Value;
    var formatters = mvcOpt.InputFormatters;
    TextInputFormatter formatter =null; // the real formatter : SystemTextJsonInput or Newtonsoft

    Endpoint endpoint = context.HttpContext.GetEndpoint();
    if(endpoint.Metadata.GetMetadata<UseSystemTextJsonAttribute>()!= null)
    {
    formatter= formatters.OfType<SystemTextJsonInputFormatter>().FirstOrDefault();
    //formatter = formatter ?? SystemTextJsonInputFormatter
    }
    else if( endpoint.Metadata.GetMetadata<UseNewtonsoftJsonAttribute>() != null){
    // don't use `Of<NewtonsoftJsonInputFormatter>` here because there's a NewtonsoftJsonPatchInputFormatter
    formatter= (NewtonsoftJsonInputFormatter)(formatters
    .Where(f =>typeof(NewtonsoftJsonInputFormatter) == f.GetType())
    .FirstOrDefault());
    }
    else{
    throw new Exception("This formatter is only used for System.Text.Json InputFormatter or NewtonsoftJson InputFormatter");
    }
    var result = await formatter.ReadRequestBodyAsync(context,encoding);
    return result;
    }
    }

    internal class MySuperJsonOutputFormatter : TextOutputFormatter
    {
    ... // similar to MySuperJsonInputFormatter, omitted for brevity
    }

    然后在启动中配置Json设置/选项:

    services.AddControllers(opts =>{ })
    .AddNewtonsoftJson(opts =>{ /**/ })
    .AddJsonOptions(opts =>{ /**/ });

    备注 AddNewtonsoftJson()将删除内置 SystemTextJsonInputFormatters .所以我们需要配置 MvcOptions手动:

    services.AddOptions<MvcOptions>()
    .PostConfigure<IOptions<JsonOptions>, IOptions<MvcNewtonsoftJsonOptions>,ArrayPool<char>, ObjectPoolProvider,ILoggerFactory>((opts, jsonOpts, newtonJsonOpts, charPool, objectPoolProvider, loggerFactory )=>{
    // configure System.Text.Json formatters
    if(opts.InputFormatters.OfType<SystemTextJsonInputFormatter>().Count() ==0){
    var systemInputlogger = loggerFactory.CreateLogger<SystemTextJsonInputFormatter>();
    opts.InputFormatters.Add(new SystemTextJsonInputFormatter(jsonOpts.Value, systemInputlogger));
    }
    if(opts.OutputFormatters.OfType<SystemTextJsonOutputFormatter>().Count() ==0){
    opts.OutputFormatters.Add(new SystemTextJsonOutputFormatter(jsonOpts.Value.JsonSerializerOptions));
    }
    // configure Newtonjson formatters
    if(opts.InputFormatters.OfType<NewtonsoftJsonInputFormatter>().Count() ==0){
    var inputLogger= loggerFactory.CreateLogger<NewtonsoftJsonInputFormatter>();
    opts.InputFormatters.Add(new NewtonsoftJsonInputFormatter(
    inputLogger, newtonJsonOpts.Value.SerializerSettings, charPool, objectPoolProvider, opts, newtonJsonOpts.Value
    ));
    }
    if(opts.OutputFormatters.OfType<NewtonsoftJsonOutputFormatter>().Count()==0){
    opts.OutputFormatters.Add(new NewtonsoftJsonOutputFormatter(newtonJsonOpts.Value.SerializerSettings, charPool, opts));
    }
    opts.InputFormatters.Insert(0, new MySuperJsonInputFormatter());
    opts.OutputFormatters.Insert(0, new MySuperJsonOutputFormatter());
    });

    现在它应该可以正常工作。

    关于c# - 如何配置两个JSON序列化器并根据路由选择正确的一个,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59650907/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com