Rico Suter's blog.
 


This article shows how to implement a post-processor for an ASP.NET MVC application, which transforms the output of an controller action before it is transmitted to the client. The obvious way to do this is by implementing a custom action filter. First, we implement the base filter class:

public abstract class OutputProcessorActionFilterAttribute : ActionFilterAttribute
{
    protected abstract string Process(string data);

    public override void OnResultExecuted(ResultExecutedContext filterContext)
    {
        var response = filterContext.HttpContext.Response;
        response.Filter = new OutputProcessorStream(response.Filter, Process);
    }
}

As you can see in the OnResultExecuted method, the response’s current Filter property is wrapped by a new stream implementation. Using this interceptor approach, it is possible to apply multiple action filters to an action method. The actual post-processing of the HTML output is done in the stream implementation OutputProcessorStream. This stream class gathers all outputs from the wrapped stream, transforms the output and writes the converted HTML data to the client:

internal class OutputProcessorStream : Stream
{
    private readonly StringBuilder _data = new StringBuilder();

    private readonly Stream _stream;
    private readonly Func<string, string> _processor;

    public OutputProcessorStream(Stream stream, Func<string, string> processor)
    {
        _stream = stream;
        _processor = processor;
    }

    public override void Write(byte[] buffer, int offset, int count)
    {
        _data.Append(Encoding.UTF8.GetString(buffer, offset, count));
    }

    public override void Close()
    {
        var output = _outputEncoding.GetBytes(_processor(_data.ToString()));
        _stream.Write(output, 0, output.Length);
        _stream.Flush();
        _data.Clear();
    }

    ...
}

Using the implemented base class, you can implement your specific post-processing action filter. The following class takes the output of an action result and converts all characters to upper case:

public class ToUpperFilterAttribute : OutputProcessorActionFilterAttribute
{
    protected override string Process(string data)
    {
        return data.ToUpper();
    }
}

Now, the implemented filter can be applied to your action method:

[ToUpperFilter]
public ActionResult Index()
{
    return View();
}

The source code of the final OutputProcessorActionFilterAttribute class can be found in the MyToolkit library. A sample ASP.NET MVC project can be found on GitHub.



Discussion