Rendering a view to a string in MVC, then redirecting — workarounds?

后端 未结 3 1782
轻奢々
轻奢々 2021-01-14 03:14

I can\'t render a view to a string and then redirect, despite this answer from Feb (after version 1.0, I think) that claims it\'s possible. I thought I was doing something w

相关标签:
3条回答
  • 2021-01-14 03:49
    public Action SendEmail(int id)
    {
      //Let's 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 refer to everything from the ViewData, rather than the model. you can do this:

    <% MyModel model = (MyModel)ViewData["Order"] %>
    
    0 讨论(0)
  • 2021-01-14 03:52

    Updated.

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

    Code to render action to text within a controller: http://mikehadlow.blogspot.com/2008/06/mvc-framework-capturing-output-of-view_05.html

    Minor edits 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 讨论(0)
  • 2021-01-14 03:54

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

    To render a regular view instead of a partial view, you'll need to change "ViewEngines.Engines.FindPartialView" to "ViewEngines.Engines.FindView".

    0 讨论(0)
提交回复
热议问题