且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

每个请求的 ASP.NET Core API JSON 序列化程序设置

更新时间:2022-12-04 17:04:55

感谢您的意见和回答.我找到了输入和输出格式化程序的解决方案.感谢 http://rovani.net/Explicit-Model-Constructor/ 指出我在正确的方向.

Thanks for the comments and answers. I found a solution with Input and outputformatters. With thanks to http://rovani.net/Explicit-Model-Constructor/ to point me in the right direction.

我创建了自己的输入和输出格式化程序,它们继承自 JsonInputFormatter 以保持尽可能多的功能相同.
在构造函数中,我设置了支持的媒体类型(使用了一些看起来像现有 JSON 的媒体类型).
还必须重写 CreateJsonSerializer 以将 ContractResolver 设置为所需的(可以实现单例).
必须这样做,因为更改构造函数中的 serializerSettings 会更改所有输入/输出格式化程序的序列化程序设置,这意味着默认的 JSON 格式化程序也将使用新的合约解析器.
这样做也意味着您可以通过 AddMvc().AddJsonOption()

I've created my own input and outputformatters, which inherit from JsonInputFormatter to keep as much functionality the same.
In the constructor I set the supported mediatype (used some that looks like the existing one for JSON).
Also must override CreateJsonSerializer to set the ContractResolver to the desired one (could implement singleton).
Must do it this way, because changing the serializerSettings in the constructor would change the serializersettings for all input/outputformatters, meaning the default JSON formatters will also use the new contract resolver.
Also doing it this way means you can setup some default JSON options via AddMvc().AddJsonOption()

示例inputformatter,outputformatter使用相同的原理:

Example inputformatter, outputformatter uses the same principle:

static MediaTypeHeaderValue protoMediaType = MediaTypeHeaderValue.Parse("application/jsonfull");

public JsonFullInputFormatter(ILogger logger, JsonSerializerSettings serializerSettings, ArrayPool<char> charPool, ObjectPoolProvider objectPoolProvider) 
    : base(logger, serializerSettings, charPool, objectPoolProvider)
{
    this.SupportedMediaTypes.Clear();
    this.SupportedMediaTypes.Add(protoMediaType);
}

protected override JsonSerializer CreateJsonSerializer()
{
    var serializer = base.CreateJsonSerializer();            
    serializer.ContractResolver = new NoJsonPropertyNameContractResolver();

    return serializer;
}

根据上面提到的安装类 URL:

As per the mentioned URL above the setup class:

public class YourMvcOptionsSetup : IConfigureOptions<MvcOptions>
{
    private readonly ILoggerFactory _loggerFactory;
    private readonly JsonSerializerSettings _jsonSerializerSettings;
    private readonly ArrayPool<char> _charPool;
    private readonly ObjectPoolProvider _objectPoolProvider;

    public YourMvcOptionsSetup(ILoggerFactory loggerFactory, IOptions<MvcJsonOptions> jsonOptions, ArrayPool<char> charPool, ObjectPoolProvider objectPoolProvider)
    {
        //Validate parameters and set fields
    }

    public void Configure(MvcOptions options)
    {
        var jsonFullInputFormatter = new JsonFullInputFormatter(
            _loggerFactory.CreateLogger<JsonFullInputFormatter>(),
            _jsonSerializerSettings,
            _charPool,
            _objectPoolProvider
        );

        options.InputFormatters.Add(jsonFullInputFormatter);

        options.OutputFormatters.Add(new JsonFullOutputFormatter(
            _jsonSerializerSettings,
            _charPool
        ));
    }

然后是一个扩展方法来注册它:

And then an extension method to register it:

public static class MvcBuilderExtensions
{
    public static IMvcBuilder AddJsonFullFormatters(this IMvcBuilder builder)
    {
        if (builder == null)
        {
            throw new ArgumentNullException(nameof(builder));
        }
        ServiceDescriptor descriptor = ServiceDescriptor.Transient<IConfigureOptions<MvcOptions>, YourMvcOptionsSetup>();
        builder.Services.TryAddEnumerable(descriptor);
        return builder;
    }
}

ConfigureServices中调用它:

services.AddMvc(config =>
{
    config.RespectBrowserAcceptHeader = true; // To use the JsonFullFormatters if clients asks about it via Accept Header
})
.AddJsonFullFormatters() //Add our own JSON Formatters
.AddJsonOptions(opt =>
{
     //Set up some default options all JSON formatters must use (if any)
});

现在我们的 Xamarin 应用可以访问 webapi 并接收带有通过 JsonProperty 属性设置的(短)属性名称的 JSON.
在网站中,我们可以通过添加 Accept(get 调用)和 ContentType(post/put 调用)标头来获取完整的 JSON 属性名称.我们通过 jQuery 的 $.ajaxSetup(.

Now our Xamarin App can access the webapi and receive JSON with (short) property names set via JsonProperty attribute.
And in the website we can get the full JSON property names by adding an Accept (get calls) and ContentType (post/put calls) header. Which we do once via jQuery's $.ajaxSetup(.

$.ajaxSetup({
    contentType: "application/jsonfull; charset=utf-8",
    headers: { 'Accept': 'application/jsonfull' }
});