# Manipulate response in web api in .net Core MVC Pipeline - Solution 2

Welcome to the part 2 the [problem](https://blog.rbipin.com/manipulate-response-in-net-core-mvc-pipeline-part-13).

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.

## Using Action Filters and manually serializing the output
Create `Action Filters` for the endpoints and manually serialize the output in the `OnResultExecuting()` method and write the serialized output to the response body.

### Details
Create two action filters one for the Washington weather station endpoint and Quebec endpoint.

![Sol2-action-filters.jpeg](https://cdn.hashnode.com/res/hashnode/image/upload/v1653370297196/-HJKBeibs.jpeg align="center")

Created a custom XML serializer to serialize the object into XML.

![Sol2-xml-serializers.jpeg](https://cdn.hashnode.com/res/hashnode/image/upload/v1653370362763/ORZvhNgtI.jpeg align="center")

Use the XML serializers in the corresponding action filters and serialize the object, here is a snippet from Washington action filter

```c#
// Action Filter
        public class WashingtonOuputFilterAttribute : 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;
                var serializedResult = WashingtonOutputSerializer.Instance.Serialize(result.Value);
                var resultBytes = Encoding.UTF8.GetBytes(serializedResult);
                response.Headers.Add("Content-Type", "application/xml");
                await response.Body.WriteAsync(resultBytes, 0, resultBytes.Length);
                base.OnResultExecuting(context);
            }
        }
```
Here is the code of lazy-loaded singleton Washington XML Serializer

```c#
   //Washington XML Serializer
        public class WashingtonOutputSerializer
        {
            public static readonly Lazy<WashingtonOutputSerializer> lazyWashingtonSerializer =
                new Lazy<WashingtonOutputSerializer>(() => new WashingtonOutputSerializer());

            public static WashingtonOutputSerializer Instance
            {
                get { return lazyWashingtonSerializer.Value; }
            }

            private WashingtonOutputSerializer() { }

            public string Serialize(object outputObject)
            {
                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");
                return XMLSerializer.Instance.Serialize(outputObject, namespaces);
            }
        }
```
**Output**

Endpoint 1: Washington Weather Station

```xml
    <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 Weather Station

```xml
   <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](https://blog.rbipin.com/manipulate-response-in-net-core-mvc-pipeline-part-13).
- 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.
**Cons**
- Since we start writing/ manipulating the response body manually, further manipulation of response is not possible. This is demonstrated in the code using a middleware.

### Demonstration of the drawback of this solution
Start by creating a middleware called `SimpleMiddleware` in the solution to 
demonstrate one of the drawbacks of this solution. The middleware simply sets the response status to 200.

![Sol2-middleware.jpeg](https://cdn.hashnode.com/res/hashnode/image/upload/v1653372367123/fKykZI2c5.jpeg align="center")

_The middleware is commented in the Configure() method in the `Startup.cs` file._
```c#
//app.UseSimpleMiddleware();
```

![error_middleware-1.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1653372457411/Q-uQV40aA.png align="center")

### Code
The sample code is [here](https://github.com/rbipin/asp.net_response_manipulation)
Solution file: `Serialize_in_action_filter.sln`





