This question is almost verbatim what is being asked on this stackoverflow question
But I'd like to do it in a ASP.NET Core Api. I'm planning on implementing it as a a header instead of in the query string. I'm struggling with changing the Json SerializerSettings that has been set in the ConfigureServices method.
services.AddMvc(config =>
{
config.Filters.Add(new WebApiRequireHttps());
})
.AddJsonOptions(options =>
{
options.SerializerSettings.Formatting = Formatting.Indented;
});
What I'm trying to accomplish is change the Serializer's settings to use Formatting.None when I've set a header like X-MyApi-Pretty: false.
I'm trying to create my own ActionFIlterAttribute like in the aforementioned question. Microsoft.AspNetCore.Mvc.Filters uses ActionExecutedContext which doesn't seem to have an obvious equivalent to ActionContext.RequestContext.Configuration.Formatters.JsonFormatter.
Is there an equivalent or am I just going about this all wrong? My google-fu is really failing me on this and I feel like I'm missing something really obvious.
If you want it to be global, you can register a custom output formatter. Here's a working example I made. You're free to use.
It works by reading a header named "jsonformat" for a named json serializer setting, such as one named "pretty". If no header is present, or the header is invalid, it falls back to the default json serializer settings. This might be a cleaner approach if you want it available globally - no action filters required.
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();
}
}
}
Then register it in your services.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));
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With