Displaying string representation in MVC and then redirecting - workarounds?

I cannot display the string representation and then redirect, despite this answer from Feb (after version 1.0, I think), which claims that this is possible. I thought I was doing something wrong, and then I read this answer from Haack in July , which claims this is not possible.

If someone works and can help me get him to work, that’s great (and I will send the code, errors). However, I am now in need of workarounds. There are few, but nothing perfect. Has anyone solved this or had any comments on my ideas?

  • This is for email rendering. Although I can send emails outside of the web request (store information in db and receive it later), there are many types of emails, and I do not want to store the template data (user object, several other LINQ objects) in db, so that I can receive it later visualization. I could create a simpler, serializable POCO and save it in db, but why? ... I just need visualized text!
  • I can create a new RedirectToAction object that checks if headers have been sent (I can’t figure out how to do it - try / catch?) And, if so, it creates a simple meta-redirected page, javascript redirect, as well as a click link here".
  • In my controller, I can remember if I sent an email, and if so, manually do # 2, showing the view.
  • I can manually send redirect headers before any potential email rendering. Then, instead of using the MVC framework to redirect the redirect, I just call result.end. It seems simple but really dirty.
  • Anything else?

EDIT : I tried the Dan code (very similar to the code from January / February that I already tried), and I still get the same error. The only significant difference that I see is that his example uses a view while I use a partial view. I will try to check this later with a view.

Here is what I have:

controller

public ActionResult Certifications(string email_intro) { //a lot of stuff ViewData["users"] = users; if (isPost()) { //create the viewmodel var view_model = new ViewModels.Emails.Certifications.Open(userContext) { emailIntro = email_intro }; //i've tried stopping this after just one iteration, in case the problem is due to calling it multiple times foreach (var user in users) { if (user.Email_Address.IsValidEmailAddress()) { //add more stuff to the view model specific to this user view_model.user = user; view_model.certification302Summary.subProcessesOwner = new SubProcess_Certifications(RecordUpdating.Role.Owner, null, null, user.User_ID, repository); //more here.... //if i comment out the next line, everything works ok SendEmail(view_model, this.ControllerContext); } } return RedirectToAction("Certifications"); } return View(); } 

SendEmail ()

  public static void SendEmail(ViewModels.Emails.Certifications.Open model, ControllerContext context) { var vd = context.Controller.ViewData; vd["model"] = model; var renderer = new CustomRenderers(); //i fixed an error in your code here var text = renderer.RenderViewToString3(context, "~/Views/Emails/Certifications/Open.ascx", "", vd, null); var a = text; } 

Customrenderers

 public class CustomRenderers { public virtual string RenderViewToString3(ControllerContext controllerContext, string viewPath, string masterPath, ViewDataDictionary viewData, TempDataDictionary tempData) { //copy/paste of dan code } } 

Error

 [HttpException (0x80004005): Cannot redirect after HTTP headers have been sent.] System.Web.HttpResponse.Redirect(String url, Boolean endResponse) +8707691 

Thanks James

+4
source share
3 answers
 public Action SendEmail(int id) { //Let say that id is the db id of an order that a customer has just placed. //Go get that model from the db. MyModel model = new Model(id); //Now send that email. Don't forget the model and controller context. SendEmail(model, this.ControllerContext); //Render (or redirect!) return RedirectToAction("Wherever"); } private static void SendEmail(MyModel model, ControllerContext controllerContext) { //Recreate the viewdata ViewDataDictionary viewData = controllerContext.Controller.ViewData; viewData["Order"] = model; string renderedView = ""; CustomRenderers customRenderers = new CustomRenderers(); //Now render the view to string //ControllerContext, ViewPath, MasterPath, ViewDataDictionary, TempDataDictionary //As you can see, we're not passing a master page, and the tempdata is in this instance. renderedView = RenderViewToString(controllerContext, "~/Views/Orders/Email.aspx", "", viewData, null); //Now send your email with the string as the body. //Not writing that, as the purpose is just to show the rendering. :) } //Elsewhere... public class CustomRenderers { public virtual string RenderViewToString(ControllerContext controllerContext, string viewPath, string masterPath, ViewDataDictionary viewData, TempDataDictionary tempData) { if (tempData == null) { tempData = new TempDataDictionary(); } 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; } } } 

In your Orders / Email .aspx view, make sure you link to everything starting with ViewData, not the model. You can do it:

 <% MyModel model = (MyModel)ViewData["Order"] %> 
0
source

Here is an alternative method for rendering a string representation that never results in data being returned (so it should avoid your problem): http://craftycodeblog.com/2010/05/15/asp-net-mvc-render-partial- view-to-string /

To make a normal view instead of a partial view, you need to change "ViewEngines.Engines.FindPartialView" to "ViewEngines.Engines.FindView".

0
source

Updated.

Now that I understand that you want to use the submission engine to generate the actual email in html, I suggest the following:

Code for displaying actions in the text inside the controller: http://mikehadlow.blogspot.com/2008/06/mvc-framework-capturing-output-of-view_05.html

Minor changes to your code:

 public ActionResult Certifications(string email_intro) { //a lot of stuff ViewData["users"] = users; if (isPost()) { //create the viewmodel var view_model = new ViewModels.Emails.Certifications.Open(userContext) { emailIntro = email_intro }; foreach (var user in users) { if (user.Email_Address.IsValidEmailAddress()) { view_model.user = user; view_model.certification302Summary.subProcessesOwner = new SubProcess_Certifications(RecordUpdating.Role.Owner, null, null, user.User_ID, repository); SendEmail(view_model); } } return RedirectToAction("Certifications"); } return View(); } public void SendEmail(ViewModels.Emails.Certifications.Open model) { var vd = context.Controller.ViewData; vd["model"] = model; var renderer = new CustomRenderers(); // Implement the actual email rendering as a regular action method on this controller var text = this.CaptureActionHtml(c => (ViewResult)c.RenderEmail(model)); var a = text; } 
0
source

All Articles