MS MVC: Blocks Refactored
In my last post I talked about adding blocks to ms mvc to capture output. Our solution used an ugly hack with reflection, type caching, and lwg. Thanks to Jeremy Skinner and Phil who both pointed out you can use a response output filter to do the same thing. So here is an update to our capturing class.
/// <summary>Renders the action and returns a string.</summary> /// <param name=”viewRenderer”>The delegate to render.</param> /// <returns>The rendered text.</returns> public string Capture(Action viewRenderer) { IHttpResponse resp = _httpContext.Response; Stream originalFilter = null; CapturingResponseFilter innerFilter; string capturedHtml = ““; if (viewRenderer != null) { try { resp.Flush(); originalFilter = resp.Filter; innerFilter = new CapturingResponseFilter(resp.Filter); resp.Filter = innerFilter; viewRenderer(); resp.Flush(); capturedHtml = innerFilter.GetContents(resp.ContentEncoding); } finally { if (originalFilter != null) { resp.Filter = originalFilter; } } } return capturedHtml; }
The only thing to remember is to flush current response before and after you capture the text. The CapturingResponseFilter just inherits from Stream and is using a MemoryStream internally. The call to GetContents just dumps the memory stream to a string using the current encoding of the response.
What do you think… much simpler
Thanks Jeremy and Phil.
No prob. Glad I could help. That’s pretty nifty.
>The only thing to remember is to flush current response before and after you capture the text.
Sounds like you could wrap this in a using block to avoid the explicit calling of resp.Flush.
@Joe
Not quite. We need to flush the IHttpResponse so any garbage in its buffers gets written out before we start capturing, and then a second time, so anything in the buffers during the capture is flushed out through our filter.
HttpResponse does not implement IDisposable and if it did the using case isn’t valid because we are not trying to dispose of the response, we just need to ensure we are capturing all the data without any previous data that could have been sitting in the buffer.
Do you have an implementation for CapturingResponseFilter that I can get the source for? I’d like to try out your implementation.
Thanks.
@Tim
It should be in MVC-Contrib code. Jeremy Skinner ported it some time back when we were working on the UI stuff.
http://mvccontrib.googlecode.com/svn/trunk/src/MVCContrib/UI/CapturingResponseFilter.cs