Обработка параметра печати json в приложении ASP.NET Core API

Этот вопрос почти дословно спрашивается на этот вопрос stackoverflow

Но я хотел бы сделать это в ASP.NET Core Api. Я планирую реализовать его как заголовок, а не в строке запроса. Я изо всех сил пытаюсь изменить Json SerializerSettings, который был установлен в методе ConfigureServices.

services.AddMvc(config =>
        {
            config.Filters.Add(new WebApiRequireHttps());                
        })
            .AddJsonOptions(options =>
            {
                options.SerializerSettings.Formatting = Formatting.Indented;
            });

Я пытаюсь изменить настройки сериализатора, чтобы использовать Formatting.None, когда я установил заголовок, например X-MyApi-Pretty: false.

Я пытаюсь создать свой собственный ActionFIlterAttribute, как в вышеупомянутом вопросе. Microsoft.AspNetCore.Mvc.Filters использует ActionExecutedContext, который, похоже, не имеет очевидного эквивалента ActionContext.RequestContext.Configuration.Formatters.JsonFormatter.

Есть ли аналог или я просто ошибаюсь? Мой google-fu действительно подводит меня в этом, и я чувствую, что упускаю что-то действительно очевидное.


person Corey    schedule 12.05.2017    source источник


Ответы (1)


Если вы хотите, чтобы он был глобальным, вы можете зарегистрировать собственный модуль форматирования вывода. Вот рабочий пример, который я сделал. Вы можете свободно использовать.

Он работает, читая заголовок с именем «jsonformat» для именованной настройки сериализатора json, например, с именем «pretty». Если заголовок отсутствует или заголовок недействителен, он возвращается к настройкам сериализатора json по умолчанию. Это может быть более чистым подходом, если вы хотите, чтобы он был доступен глобально — фильтры действий не требуются.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.Extensions.Primitives;
using Newtonsoft.Json;

...

public class NamedFormatJsonOutputFormatter : JsonOutputFormatter
{
    private readonly IDictionary<string, JsonSerializerSettings> _customJsonSettings;
    private readonly IDictionary<string, JsonSerializer> _customSerializers;
    public NamedFormatJsonOutputFormatter(JsonSerializerSettings defaultSerializerSettings, IDictionary<string, JsonSerializerSettings> customJsonSettings, ArrayPool<char> charPool) : base (defaultSerializerSettings, charPool)
    {
        _customJsonSettings = customJsonSettings;
        _customSerializers = new Dictionary<string, JsonSerializer>();
    }
    protected virtual JsonSerializer CreateCustomJsonSerializer(string serializerName)
    {
        JsonSerializer outputSerializer;
        var exists = _customSerializers.TryGetValue(serializerName, out outputSerializer);
        if (!exists)
        {
            var settings = _customJsonSettings[serializerName];
            outputSerializer = JsonSerializer.Create(settings);
            _customSerializers[serializerName] = outputSerializer;
        }
        return _customSerializers[serializerName];
    }
    public void WriteObjectWithNamedSerializer(TextWriter writer, string serializerName, object value)
    {
        if (writer == null)
        {
            throw new ArgumentNullException(nameof(writer));
        }

        using (var jsonWriter = CreateJsonWriter(writer))
        {
            var jsonSerializer = CreateCustomJsonSerializer(serializerName);
            jsonSerializer.Serialize(jsonWriter, value);
        }
    }
    public override async Task WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
    {
        var jsonSerializerNameHeader = context.HttpContext.Request.Headers.FirstOrDefault(h => h.Key == "jsonformat" && h.Value.Intersect(_customJsonSettings.Keys).Any());
        if (jsonSerializerNameHeader.Equals(default(KeyValuePair<string, StringValues>)))
        {
            await base.WriteResponseBodyAsync(context, selectedEncoding);
            return;
        }
        var jsonFormatName = jsonSerializerNameHeader.Value.FirstOrDefault();

        var response = context.HttpContext.Response;
        using (var writer = context.WriterFactory(response.Body, selectedEncoding))
        {
            WriteObjectWithNamedSerializer(writer, jsonFormatName, context.Object);
            await writer.FlushAsync();
        }
    }
}

Затем зарегистрируйте его в своих службах.AddMvc

using System.Buffers;
using Microsoft.AspNetCore.Mvc.Formatters;

...

services.AddMvc(options =>
{
    options.OutputFormatters.RemoveType<JsonOutputFormatter>();
    options.OutputFormatters.Add(new NamedFormatJsonOutputFormatter(new JsonSerializerSettings(),

        new Dictionary<string, JsonSerializerSettings>()
        {
            {
                "pretty", new JsonSerializerSettings()
                {
                    Formatting = Formatting.Indented
                }
            }
        }, ArrayPool<char>.Shared));
});
person kg743    schedule 12.05.2017
comment
Спасибо, это именно то, что я искал. - person Corey; 15.05.2017