Post-process the HTML output of an action in ASP.NET MVC

May 5, 2015, (updated on December 16, 2015), 3 comments, Software Development

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.

Tweet about this on TwitterShare on FacebookEmail this to someoneShare on TumblrShare on LinkedIn

Tags: , , , ,

3 responses to “Post-process the HTML output of an action in ASP.NET MVC”

  1. niko says:

    Your code has a problem for a little bit hardly scenario, as i.e. replace links…
    Using Encoding.UTF8.GetString with a parts of bytes (buffer) is dangerous. For example, a block of bytes may be interrupted in the middle of the html tag…
    My suggestion is to collect the list of byte arrays in the Write method, then in Close() combine their into a single whole and process it already…

  2. Very helpful, thanks for sharing!

  3. Tuan says:

    You saved my Week!
    Thanks a lot!

Leave a Reply

Your email address will not be published. Required fields are marked *

To create code blocks or other preformatted text, indent by four spaces:

    This will be displayed in a monospaced font. The first four 
    spaces will be stripped off, but all other whitespace
    will be preserved.
    
    Markdown is turned off in code blocks:
     [This is not a link](http://example.com)

To create not a block, but an inline code span, use backticks:

Here is some inline `code`.

For more help see http://daringfireball.net/projects/markdown/syntax