2

I want to use different JSON Output Formatters for different Routes or Controllers. The default and a custom json output formatter

Startup.cs

services.AddControllers(options =>
        {
            options.RespectBrowserAcceptHeader = true;
            options.OutputFormatters.Add(new CustomJsonMediaFormatter());                
        });

CustomJsonMediaFormatter

public class CustomJsonMediaFormatter : TextOutputFormatter
{        

    public JsonMediaFormatter()
    {            
        SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("application/vnd.XYZ+json"));
        SupportedEncodings.Add(Encoding.UTF8);
        SupportedEncodings.Add(Encoding.Unicode);
    }

    protected override bool CanWriteType(Type type)
    {
      return true;          
    }

    public override async Task WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
    {
        // my code

    }        

}

Controller A

[ApiController]
[Produces("application/vnd.XYZ+json")]
public class AController : BaseController
{
    
    [HttpGet]
    public async Task<IActionResult> Get()
    {
        // return an object
    }
}

Controller B

[ApiController]
[Produces("application/json")]
public class BController : BaseController
{
    
    [HttpGet]
    public async Task<IActionResult> Get()
    {
        // return an object
    }
}

When I fire a request to the A Cotroller with Postman it is not using my Custom Output Formatter. It is still using the default JSON Output Formatter.

It seems that it takes the first JSON Output Formatter in the list. I tried to clear the output formatter list and add my custom json formatter. Then it is always using the custom formatter.

What I want to do with the custom output formatter is: I want to remove some fields from objects that the user is not allowed to see, depending on configuration. But only for some API Controllers and not all.

2 Answers 2

1

If you look that their docs, you'll see they are inserting the customer formatter at the beginning of the list. https://learn.microsoft.com/en-us/aspnet/core/web-api/advanced/custom-formatters?view=aspnetcore-5.0#how-to-configure-mvc-to-use-a-custom-formatter

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers(options =>
    {
        options.InputFormatters.Insert(0, new VcardInputFormatter());
        options.OutputFormatters.Insert(0, new VcardOutputFormatter());
    });
}

This leads me to believe execution order of the formatters DOES matter, and is likely executing the default json one before ever checking your custom content accept type.

Try updating your DI to:

services.AddControllers(options =>
{
   options.RespectBrowserAcceptHeader = true;
   options.OutputFormatters.Insert(0, new CustomJsonMediaFormatter());                
});
Sign up to request clarification or add additional context in comments.

1 Comment

this leads to the result, that my custom json formatter is always used, also for Controller B
1

I got the solution. Override the function CanWriteResult. From the context we get the content type

public override bool CanWriteResult(OutputFormatterCanWriteContext context)
    {
        return context.ContentType == "application/vnd.XYZ+json";
    }

Together with @JohnD's answer regarding the order of the formatters, it is working perfectly!

services.AddControllers(options =>
{
   options.RespectBrowserAcceptHeader = true;
   options.OutputFormatters.Insert(0, new CustomJsonMediaFormatter());                
});

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.