每个请求的ASP.NET Core API JSON serializersettings

时间:2017-06-29 14:42:49

标签: c# serialization asp.net-core json.net asp.net-core-webapi

根据请求中的某些值(标题或在url中),我想更改DTO对象的序列化。 为什么?我已将[JsonProperty("A")]应用于我的DTO,但根据客户端(网站或移动应用),它是否要使用该属性。 我从

开始
services
.AddMvc()
.AddJsonOptions(opt =>
{
#if DEBUG
    opt.SerializerSettings.ContractResolver = new NoJsonPropertyNameContractResolver();
#endif
}

因此,在调试时,我获得了具有完整属性名称的JSON。我使用JsonProperty属性来缩短响应JSON,它适用于移动应用程序(Xamarin),后者反序列化回相同的DTO。 但现在我有一个网站使用相同的API通过jQuery获取数据,但在那里我想处理DTO的完整属性名称,而不是JsonProperty属性中给出的名称。 网站和WebApi位于同一台服务器上,因此如果响应稍微大一点就没问题。

我从中间件类开始对客户标头值做出反应,这有效,但现在我不知道如何进入JSON SerializerSettings。搜索网络但找不到它。

在搜索时,我已经阅读了有关InputFormatters和OutputFormatters以及内容协商的内容,但我不知道必须走向哪个方向。

我不想使用不同的设置两次部署相同的API 如果有帮助的话,我能够更改routesconfig之类的内容。

更新
不仅JSON响应必须以两种不同的方式序列化,而且反序列化必须以两种不同的方式完成。

2 个答案:

答案 0 :(得分:13)

以下是两个选项:

1。手动格式化

您在services.AddMvc().AddJsonOptions()设置的选项已在DI中注册,您可以将其注入您的控制器和服务中:

public HomeController(IOptions<MvcJsonOptions> optionsAccessor)
{
    JsonSerializerSettings jsonSettings = optionsAccessor.Value.SerializerSettings;
}

要按请求覆盖这些序列化设置,您可以使用Json方法或创建JsonResult实例:

public IActionResult Get()
{
    return Json(data, new JsonSerializerSettings());

    return new JsonResult(data, new JsonSerializerSettings());
}

2。结果筛选器替换JSON输出

public class ModifyResultFilter : IAsyncResultFilter
{
    public ModifyResultFilter(IOptions<MvcJsonOptions> optionsAccessor)
    {
        _globalSettings = optionsAccessor.Value.SerializerSettings;
    }

    public async Task OnResultExecutionAsync(
        ResultExecutingContext context,
        ResultExecutionDelegate next)
    {
        var originResult = context.Result as JsonResult;

        context.Result = new JsonResult(originResult.Value, customSettings);

        await next();
    }
}

在动作/控制器上使用它:

[ServiceFilter(typeof(ModifyResultFilter ))]
public IActionResult Index() {}

或创建自定义属性,如documentation

中所述
[ModifyResultAttribute]
public IActionResult Index() {}

不要忘记在DI中注册过滤器。

答案 1 :(得分:3)

感谢您的评论和答案。我找到了一个带输入和输出格式的解决方案。感谢http://rovani.net/Explicit-Model-Constructor/指出我正确的方向。

我已经创建了自己的输入和输出格式,它继承自JsonInputFormatter以保持相同的功能。
在构造函数中,我设置了支持的mediatype(使用了一些类似于JSON的现有类型) 还必须覆盖CreateJsonSerializer以将ContractResolver设置为所需的(可以实现单例) 必须这样做,因为更改构造函数中的serializerSettings会更改所有输入/输出格式的serializersettings,这意味着默认的JSON格式化程序也将使用新的合同解析器。
同样这样做意味着您可以通过AddMvc().AddJsonOption()

设置一些默认的JSON选项

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

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:

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

然后注册它的扩展方法:

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 App可以访问webapi并通过JsonProperty属性设置(短)属性名称来接收JSON。
在网站中,我们可以通过添加Accept(获取调用)和ContentType(post / put调用)标头来获取完整的JSON属性名称。我们通过jQuery&#39; s $.ajaxSetup(做了一次。

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