The Problem

I have a web API with two endpoints, the endpoints serve mapped data in XML format for two different vendors. The result of both the endpoints is the same object but there are some differences like namespaces. The problem is how to return the same object with only namespaces serialized differently? I didn't want to go with the obvious solution of serializing the object with the different namespaces and returning them.

Solution 1 is here

Solution 2 is here

Solution 3

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.

Pros and Cons of the solution

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. Let me know in case any finds any.

Implementation

Step 1
I created two Action Filters one for the Washington weather station endpoint and Quebec endpoint.

Sol2-action-filters

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);
        }
    }

Step 2

Next created two output formatters for the endpoints, one for Washington and other for Quebec Canada endpoint

code_output_formatters

The snippet of one of the output formatters

 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);
        }
    }

I created a middleware called SimpleMiddleware in the solution. The middleware simply sets the response status to 200.

Sol2-middleware

Output
Endpoint 1: Washington Weather Staion

<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>

Code
The sample code for solution 3 is here
or https://github.com/BipinBlog/asp.net_response_manipulation
Solution : OutputFormatters_in_result.sln