Manipulate response in web api in .net Core MVC Pipeline - Solution 1
Using Action Filter to clear the output formatter

Search for a command to run...
Using Action Filter to clear the output formatter

No comments yet. Be the first to comment.
A 3 part series to talk about my experiment with trying to intercept and manipulate the response in .net core.
Using Action Filters for the endpoints and manually serializing the output
Create Action Filters for the two endpoints also created two output formatters

Using Action Filters for the endpoints and manually serializing the output

I ran into a problem where I had a web api and the endpoints had to serve data in XML format for two different vendors. The result of both the endpoints is the same object and data but with some minor differences like namespaces. I didn't want to go with the obvious solution of serializing the object with the different namespaces and returning them from the endpoint. I wanted to explore other ways to tackle this problem
This blog post is in 3 parts because I found three different ways to Intercept and manipulate the response, each with its pros and cons, which I will be discussing too.
To demonstrate the solution I'm using a weather station api as my example, the api has two endpoints one returns the weather data for Quebec, Canada and other reports the weather data of Washington, U.S. Both the endpoint returns the data in xml format the data set schema is same, but the namespaces are different.
Using Action Filter to clear the output formatter of the MVC pipeline and adding the vendor-specific formatter
I created two output formatters inheriting from XmlSerializerOutputFormatter.
I serialize the object to the correct format using the vendor-specific XML namespaces.

namespace OutputFormatter.API
{
public class WashingtonOutputFormatter : XmlSerializerOutputFormatter
{
public WashingtonOutputFormatter() { }
public WashingtonOutputFormatter(XmlWriterSettings xmlWriterSettings) : base(xmlWriterSettings) { }
protected override void Serialize(XmlSerializer xmlSerializer, XmlWriter xmlWriter, object value)
{
var namespaces = new XmlSerializerNamespaces();
namespaces.Add("WS", "http://www.wausweatherStation.com/xml/namespaces/type");
namespaces.Add("Metric", "http://www.wausweatherstation.com/xml/namespaces/siunit/temperature");
xmlSerializer.Serialize(xmlWriter, value, namespaces);
}
}
}
Create two ActionFilterAttribute, in this case for Quebec Canada, and another for Washington. These two action filters will clear the existing output filters in the MVC pipeline and add the corresponding output filter. Quebec Canada Action filter will add the Quebec Canada output formatter to the pipeline and the Washington Action filter will add only the Washington output formatter.

public class WashingtonOutputFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
var washingtonOutputFormat = new WashingtonOutputFormatter(new XmlWriterSettings() {OmitXmlDeclaration = true});
var outputFormattersToRemove = new List<IOutputFormatter>()
{
new XmlSerializerOutputFormatter(),
new SystemTextJsonOutputFormatter(new System.Text.Json.JsonSerializerOptions()),
new QuebecCanadaOutputFormatter()
};
var commonFormatter = new FilterActionCommon();
commonFormatter.ClearOutputFormatters(context, outputFormattersToRemove);
commonFormatter.AddOutputFormatter(context, washingtonOutputFormat);
base.OnActionExecuting(context);
}
}
Following is the output I would receive,
from endpoint 1: Washington Weather Station
<WeatherForecast xmlns:WS="http://www.wausweatherStation.com/xml/namespaces/type" xmlns:Metric="http://www.wausweatherstation.com/xml/namespaces/siunit/temperature">
<Date>2020-06-02T13:50:52.5094204-04:00</Date>
<Temperature>
<Celsius>8</Celsius>
<Farenheit>46</Farenheit>
</Temperature>
<Summary>Mild</Summary>
</WeatherForecast>
from endpoint 2: Quebec Canada Weather Station
<WeatherForecast xmlns:WS="http://www.qubeccanadaweatherstation.com/xml/namespaces/type" xmlns:Metric="http://www.qubeccanadaweatherstation.com/xml/namespaces/siunit/temperature">
<Date>2020-06-02T13:56:09.5506734-04:00</Date>
<Temperature>
<Celsius>34</Celsius>
<Farenheit>93</Farenheit>
</Temperature>
<Summary>Cool</Summary>
</WeatherForecast>
if you look closely the only difference between these two responses are the namespaces
Pros
Cons
The sample code is here Solution file OutputFormatters-Pipeline.sln