簡體   English   中英

每個請求的ASP.NET Core API JSON serializersettings

[英]ASP.NET Core API JSON serializersettings per request

根據請求中的某些值(標題或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響應必須以兩種不同的方式序列化,而且反序列化必須以兩種不同的方式完成。

這有兩個選擇:

1.手動格式化

您通過services.AddMvc().AddJsonOptions()設置的選項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() {}

或者按照文檔中的描述創建自定義屬性:

[ModifyResultAttribute]
public IActionResult Index() {}

不要忘記在DI中注冊過濾器。

感謝您的評論和解答。 我找到了一個帶輸入和輸出格式的解決方案。 感謝http://rovani.net/Explicit-Model-Constructor/指出我正確的方向。

我創建了自己的輸入和輸出格式,它繼承自JsonInputFormatter以保持相同的功能。
在構造函數中,我設置了支持的mediatype(使用了一些類似於JSON的現有類型)。
還必須覆蓋CreateJsonSerializer以將ContractResolver設置為所需的(可以實現單例)。
一定要做到這樣,因為改變serializerSettings在構造函數將改變所有輸入/ outputformatters的serializersettings,意味着默認的JSON格式化也將使用新的合同解析器。
這樣做也意味着你可以通過AddMvc().AddJsonOption()設置一些默認的JSON選項AddMvc().AddJsonOption()

示例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應用程序可以訪問webapi並通過JsonProperty屬性設置(短)屬性名稱來接收JSON。
在網站中,我們可以通過添加Accept(獲取調用)和ContentType(post / put調用)標頭來獲取完整的JSON屬性名稱。 我們通過jQuery的$.ajaxSetup(

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM