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.
This is a cleaner solution that others out there. Does anyone have an example if the Action also uses parameters?
ReplyDeleteYou can write:
ReplyDeleteView("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;
}
Well actually I can't .
DeleteVisual Studio says
Cannot apply indexing with [] to an expression of type 'System.Web.Mvc.ViewResult'
Oops
Deletethis is is how it works in MVC3.
public static ViewResult With(this ViewResult vr, string key, object value)
{
vr.ViewData[key] = value;
return vr;
}
Does someone know how to do handle this with the ViewBag instead of ViewData?
Hello
ReplyDeleteI 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?
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
ReplyDeleteThanks a lot, this helped!
ReplyDeleteIt almost works..
ReplyDeleteIf 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 ?
Email me a sample project and I will have a look. Hard to say anything without seeing it.
ReplyDeleteAfter very long looking at the code, I noticed that I typed "@Model". it should be "@model".
ReplyDeleteI didn't know model is case-sensitive.
Does this work with Razor?
ReplyDeleteCompiler 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.
Never mind. I found the problem. I miss the @model.
ReplyDeleteThis is great stuff! YMMD!
ReplyDeleteBut does anyone have an idea, how I can apply this to calling ActionMethods on another controller?