Art Of Programming

musings by Dmytrii Nagirniak

Render Any ASP.NET MVC ActionResult to a String

I often see questions on the net about how to render a view to a string so it can be used somewhere.

My approach allows doing it without thinking about all the boilerplate code. Additionally not only the ViewResult can be rendered into a string but just about any type of the result. Here is example on how to return a JSON including the result of the view as additional information:

 

// Controller Action:
public JsonResult DoSomething() {
    var viewString = View("TheViewToRender").Capture(ControllerContext);
    return new JsonResult {
        JsonRequestBehavior = JsonRequestBehavior.AllowGet,
        Data = new {
            time = DateTime.Now,
            html = viewString
        }
    };
}

 

This can be done with 2 simple utility classes below. Just include them somewhere into your project.

 

    public class ResponseCapture : IDisposable {
        private readonly HttpResponseBase response;
        private readonly TextWriter originalWriter;
        private StringWriter localWriter;
        public ResponseCapture(HttpResponseBase response) {
            this.response = response;
            originalWriter = response.Output;
            localWriter = new StringWriter();
            response.Output = localWriter;
        }
        public override string ToString() {
            localWriter.Flush();
            return localWriter.ToString();
        }
        public void Dispose() {
            if (localWriter != null) {
                localWriter.Dispose();
                localWriter = null;
                response.Output = originalWriter;
            }
        }
    }
    public static class ActionResultExtensions {
        public static string Capture(this ActionResult result, ControllerContext controllerContext) {
            using (var it = new ResponseCapture(controllerContext.RequestContext.HttpContext.Response)) {
                result.ExecuteResult(controllerContext);
                return it.ToString();
            }
        }
    }

Enjoy and let me know if it works for you.

Comments

The Dode
Never mind. I found the problem. I miss the @model.
The Dode
Does this work with Razor?

Compiler Error Message: CS1973: 'System.Web.Mvc.HtmlHelper' has no applicable method named 'TextBox' but appears to have an extension method by that name. Extension methods cannot be dynamically dispatched. Consider casting the dynamic arguments or calling the extension method without the extension method syntax.
Anonymous
After very long looking at the code, I noticed that I typed "@Model". it should be "@model".
I didn't know model is case-sensitive.
Dmytrii Nagirniak
Email me a sample project and I will have a look. Hard to say anything without seeing it.
Anonymous
It almost works..
If my view contains "@Model" on the first line. This line will be also in the output.

"@Model x.y" will be in the string as "x.y x.y"

any ideas ?
Anonymous
Thanks a lot, this helped!
Dmytrii Nagirniak
For the .NET 3.5 it will be needed to substitute the HttpContext on the controller and involves a bit more code, but still is possible. Have a look for an example
tecnocrata
Hello
I have a question. How can I do it in .NET Framework 3.5? in thi, Output property doesn't have a setter method.
Could you help me please?
Dmytrii Nagirniak
You can write:

View("ViewName").With("name", "Dima").With("likes", "Ruby").Capture(ControllerContext)


with this simple extension method:

public static ViewResult With(this ViewResult vr, string key, object value) {
vr[key] = value;
return vr;
}
Gabriel
This is a cleaner solution that others out there. Does anyone have an example if the Action also uses parameters?

Comments