4

ビューを文字列にレンダリングしてからリダイレクトすることはできません. 2月(バージョン1.0以降だと思います)からのこの回答は可能であると主張しています。私は何か間違ったことをしていると思っていましたが、7月にHaackからのこの回答を読んで、それは不可能だと主張しました.

誰かがそれを機能させ、私がそれを機能させるのを手伝ってくれるなら、それは素晴らしいことです (そして、コードやエラーを投稿します)。しかし、私は今、回避策が必要なところにいます。いくつかありますが、理想的なものはありません。誰かがこれを解決しましたか、それとも私の考えにコメントがありますか?

  1. これは、電子メールをレンダリングすることです。私は確かにWebリクエストの外で電子メールを送信できますが(データベースに情報を保存して後で取得します)、電子メールには多くの種類があり、テンプレートデータ(ユーザーオブジェクト、他のいくつかのLINQオブジェクト)を保存したくありません) db で後でレンダリングできるようにします。もっとシンプルでシリアル化可能な POCO を作成してデータベースに保存することもできますが、なぜでしょうか? ... レンダリングされたテキストが欲しい!
  2. ヘッダーが送信されたかどうかを確認する新しい RedirectToAction オブジェクトを作成し (これを行う方法がわかりません -- try/catch?)、送信された場合は、メタ リダイレクト、JavaScript リダイレクトを使用して単純なページを構築します。 、および「ここをクリック」リンクもあります。
  3. コントローラー内で、メールをレンダリングしたかどうかを記憶できます。レンダリングした場合は、ビューを表示して手動で #2 を実行します。
  4. 電子メールがレンダリングされる可能性がある前に、リダイレクト ヘッダーを手動で送信できます。次に、MVC インフラストラクチャを使用してアクションにリダイレクトするのではなく、単に result.end を呼び出します。これは最も簡単に思えますが、非常に面倒です。
  5. 他に何か?

編集:ダンのコードを試しました(すでに試した1月/2月のコードと非常に似ています)が、まだ同じエラーが発生しています。私が見ることができる唯一の実質的な違いは、私が部分ビューを使用しているのに対し、彼の例ではビューを使用していることです。後でこれをビューでテストしてみます。

これが私が持っているものです:

コントローラ

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();
        }

メールを送る()

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

カスタムレンダラー

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

ありがとう、ジェームズ

4

3 に答える 3

0

ビューを文字列にレンダリングし、データが応答に出力されることのない代替方法を次に示します (したがって、問題を回避する必要があります): http://craftycodeblog.com/2010/05/15/asp-net-mvc -render-partial-view-to-string/

部分ビューではなく通常のビューをレンダリングするには、「ViewEngines.Engines.FindPartialView」を「ViewEngines.Engines.FindView」に変更する必要があります。

于 2010-05-15T17:38:32.090 に答える
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;         
} 
于 2010-12-30T05:26:23.987 に答える
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;
    }
  }
}

Orders/Email.aspx ビューで、モデルではなく ViewData からすべてを参照していることを確認してください。あなたはこれを行うことができます:

<% MyModel model = (MyModel)ViewData["Order"] %>
于 2009-08-15T19:10:32.630 に答える