Render a view as a string

Posted by Dan Atkinson on Stack Overflow See other posts from Stack Overflow or by Dan Atkinson
Published on 2009-01-27T11:43:56Z Indexed on 2010/05/15 17:34 UTC
Read the original article Hit count: 422

Filed under:
|

Hi all!

I'm wanting to output two different views (one as a string that will be sent as an email), and the other the page displayed to a user.

Is this possible in ASP.NET MVC beta?

I've tried multiple examples:

RenderPartial to String in ASP.NET MVC Beta
If I use this example, I receive the "Cannot redirect after HTTP headers have been sent.".

MVC Framework: Capturing the output of a view
If I use this, I seem to be unable to do a redirectToAction, as it tries to render a view that may not exist. If I do return the view, it is completely messed up and doesn't look right at all.

Does anyone have any ideas/solutions to these issues i have, or have any suggestions for better ones?

Many thanks!

Below is an example. What I'm trying to do is create the GetViewForEmail method:

public ActionResult OrderResult(string ref)
{
  //Get the order
  Order order = OrderService.GetOrder(ref);

  //The email helper would do the meat and veg by getting the view as a string
  //Pass the control name (OrderResultEmail) and the model (order)
  string emailView = GetViewForEmail("OrderResultEmail", order);

  //Email the order out
  EmailHelper(order, emailView);
  return View("OrderResult", order);
}

Accepted answer from Tim Scott (changed and formatted a little by me):

public virtual string RenderViewToString(
  ControllerContext controllerContext,
  string viewPath,
  string masterPath,
  ViewDataDictionary viewData,
  TempDataDictionary tempData)
{
  Stream filter = null;
  ViewPage viewPage = new ViewPage();

  //Right, create our view
  viewPage.ViewContext = new ViewContext(controllerContext, new WebFormView(viewPath, masterPath), viewData, tempData);

  //Get the response context, flush it and get the response filter.
  var response = viewPage.ViewContext.HttpContext.Response;
  response.Flush();
  var oldFilter = response.Filter;

  try
  {
      //Put a new filter into the response
      filter = new MemoryStream();
      response.Filter = filter;

      //Now render the view into the memorystream and flush the response
      viewPage.ViewContext.View.Render(viewPage.ViewContext, viewPage.ViewContext.HttpContext.Response.Output);
      response.Flush();

      //Now read the rendered view.
      filter.Position = 0;
      var reader = new StreamReader(filter, response.ContentEncoding);
      return reader.ReadToEnd();
  }
  finally
  {
      //Clean up.
      if (filter != null)
      {
        filter.Dispose();
      }

      //Now replace the response filter
      response.Filter = oldFilter;
  }
}

Example usage

Assuming a call from the controller to get the order confirmation email, passing the Site.Master location.

string myString = RenderViewToString(this.ControllerContext, "~/Views/Order/OrderResultEmail.aspx", "~/Views/Shared/Site.Master", this.ViewData, this.TempData);

© Stack Overflow or respective owner

Related posts about asp.net-mvc

Related posts about rendering