2009-08-15 12 views
4

儘管this answer from Feb(我認爲版本1.0之後)聲稱它是可能的,但我無法將視圖渲染爲字符串,然後重定向。我以爲我做錯了什麼,然後我讀了這個answer from Haack in July,聲稱這是不可能的。將視圖渲染爲MVC中的字符串,然後重定向 - 解決方法?

如果有人有它的工作,並可以幫助我得到它的工作,這是偉大的(我會張貼代碼,錯誤)。不過,我現在需要解決方法。有一些,但沒有理想。有沒有人解決這個問題,或者對我的想法有任何評論?

  1. 這是呈現電子郵件。儘管我可以確實在Web請求外發送電子郵件(將信息存儲在數據庫中並在稍後獲取),但有很多類型的電子郵件,我不想存儲模板數據(用戶對象,其他一些LINQ對象)在一個分貝,讓它得到渲染。我可以創建一個更簡單的,可序列化的POCO並將其保存在數據庫中,但爲什麼? ...我只想渲染文本!
  2. 我可以創建一個新的RedirectToAction對象來檢查頭是否已經發送(不知道如何做到這一點 - 嘗試/ catch?),如果是這樣,用meta重定向構建一個簡單的頁面,一個JavaScript重定向,還有一個「點擊這裏」鏈接。
  3. 在我的控制器中,我可以記得我是否已經提交了一封電子郵件,如果是,則通過顯示一個視圖手動執行#2。
  4. 我可以在任何潛在的電子郵件呈現之前手動發送重定向標頭。然後,我只是調用result.end而不是使用MVC基礎結構重定向。這看起來最簡單,但真的很混亂。
  5. 還有什麼?

編輯:我試過丹的代碼(非常相似,從一月/二月,我已經嘗試過的代碼),我仍然得到同樣的錯誤。我能看到的唯一實質性區別是他的示例在使用局部視圖時使用視圖。我會稍後嘗試使用視圖進行測試。

下面是我得到了什麼:

控制器

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's code 
     } 
    } 

錯誤

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

謝謝, 詹姆斯

+0

您是否曾經爲此找到過解決方法? – Kirschstein 2009-11-25 11:57:58

回答

0
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; 
    } 
    } 
} 

在訂單/ Email.aspx視圖,請確保您指一切從ViewData的,而不是模型。你可以這樣做:

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

丹 - 感謝您的嘗試,但是我收到了您在Jan發佈的代碼後得到的「無法重定向錯誤」。我在我的問題中貼上了一切。我究竟做錯了什麼?謝謝。 – 2009-08-16 10:15:23

0

已更新。

現在我明白,你要使用的視圖引擎生成HTML實際的電子郵件,我提出以下建議:

程序代碼來渲染動作控制器中的文本: http://mikehadlow.blogspot.com/2008/06/mvc-framework-capturing-output-of-view_05.html

對您的代碼進行少量編輯:

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

你如何建議我實現我在示例中試圖做的事情?即,我想使用模板引擎來創建電子郵件,而不是將它們和一堆HTML連接在一起。 – 2011-01-08 02:52:40

+0

謝謝......當我在一兩個月內回到該項目時,我會看看這個。 – 2011-01-24 01:57:24

相關問題