Manipulate response in web api in .net Core MVC Pipeline - Solution 3
Create Action Filters for the two endpoints also created two output formatters
Welcome to part 3 of the series, you can read the previous parts here 1 & 2.
If you have already read the previous part and know the problem we are trying to solve, please skip the next two paragraphs.
A quick recap of the problem of what I'm trying to solve here, I have a web api that has two different endpoints that needs to serve the same data but with minor difference. Here I would be discussing about my second approach to solve this.
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 schema is same, but the namespaces are different.
Create ActionFilter
and Outputformatters
for the endpoints
This approach is a mix of solution 1 and Solution 2.
Create Action Filters for the two endpoints, also created two output formatters like in solution 1 for both the endpoints. In the action filter, get the result object and add the output formatters to the formatters of the result.
Details
Start by creating two Action Filters one for the Washington weather station endpoint and Quebec endpoint.
The snippet of the new Action Filter
public class QubecCanadaOuputFilterAttribute : ActionFilterAttribute
{
public override async void OnResultExecuting(ResultExecutingContext context)
{
var response = context.HttpContext.Response;
if (response.StatusCode != 200)
{
base.OnResultExecuting(context);
}
var result = context.Result as ObjectResult;
result.Formatters.Add(new QuebecCanadaOutputFormatter());
base.OnResultExecuting(context);
}
}
Next we create two output formatters for the endpoints, one for Washington and other for Quebec Canada endpoint
public class QuebecCanadaOutputFormatter : XmlSerializerOutputFormatter
{
public QuebecCanadaOutputFormatter()
{
}
public QuebecCanadaOutputFormatter(XmlWriterSettings xmlWriterSettings) :
base(xmlWriterSettings)
{
}
protected override void Serialize(
XmlSerializer xmlSerializer,
XmlWriter xmlWriter,
object value
)
{
var namespaces = new XmlSerializerNamespaces();
namespaces.Add("WS", "http://www.qubeccanadaweatherstation.com/xml/namespaces/type");
namespaces.Add("Metric", "http://www.qubeccanadaweatherstation.com/xml/namespaces/siunit/temperature");
xmlSerializer.Serialize (xmlWriter, value, namespaces);
}
}
Output
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>
Endpoint 2: Quebec Canada
<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>
Pros and Cons of this approach
Pros
- The MVC pipeline remains unaltered, unlike Solution 1.
- Because there is a separate action filter, there is a clear separation of concerns. Code is well separated, i.e business logic is taken care of by the API, and formatting the output is achieved by the formatters.
- We are not writing into the response body here like solution 2, so the middleware in the pipeline will not be affected in case any middleware alters the response.
Cons
I haven't found any yet.
Code
The sample code for solution 3 is here
Solution : OutputFormatters_in_result.sln