如何配置两个JSON序列化器并根据路由选择正确的序列化器 [英] How to configure two JSON serializers and select the correct one based on the route

查看:57
本文介绍了如何配置两个JSON序列化器并根据路由选择正确的序列化器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have an ASP.NET Core Web API project using .Net Framework 4.7 and I'm upgrading to .Net Core 3.1. One of the reasons that I'm upgrading is to use the new System.Text.Json serializer.

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

Currently, I have some versions of the API based on the route, like:

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

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

And I will create a new one (v3) to use the new serializer. But here is the problem: I want to keep using JSON.Net on the older routes, to avoid any possible formating problem with the integrated clients.

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

Is there an easy way to configure Asp.Net Core to automatically select the correct JSON serializer based on the route?

推荐答案

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

You could create your own super InputFormatter/OutputFormatter so that it checks the condition at runtime and then make a decision to use System.Text.Json or use Newtonsoft.Json dynamically.

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

For example, we can check the current action method ( or controller class):

  • 如果其自定义属性为[UseSystemTextJsonAttribute],请使用System.Text.Json
  • 如果其自定义属性为[UseNewtonsoftJsonAttribute],请使用Newtonsoft.Json.
  • if it has a custom attribute of [UseSystemTextJsonAttribute], then use System.Text.Json
  • if it has a custom attribute of [UseNewtonsoftJsonAttribute], then use Newtonsoft.Json.

我创建了一个自定义InputFormatter供您参考:

I create a custom InputFormatter for your reference:

// 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设置/选项:

And then configure the Json settings/options in the startup:

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

注意AddNewtonsoftJson()将删除内置的SystemTextJsonInputFormatters.因此,我们需要手动配置MvcOptions:

Note AddNewtonsoftJson() will remove the builtin SystemTextJsonInputFormatters. So we need configure the MvcOptions manually :

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

现在应该可以正常工作了.

Now it should work fine.

这篇关于如何配置两个JSON序列化器并根据路由选择正确的序列化器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆