ASP.NET MVC ビューを文字列としてレンダリングするにはどうすればいいですか? 質問する

ASP.NET MVC ビューを文字列としてレンダリングするにはどうすればいいですか? 質問する

2 つの異なるビュー (1 つは電子メールとして送信される文字列) と、もう 1 つはユーザーに表示されるページを出力したいと考えています。

これは ASP.NET MVC ベータ版で可能ですか?

複数の例を試しました:

1. ASP.NET MVC ベータ版で RenderPartial を文字列に変換する

この例を使用すると、「HTTP ヘッダーが送信された後にリダイレクトできません。」というメッセージが表示されます。

2. MVC フレームワーク: ビューの出力をキャプチャする

これを使用すると、存在しない可能性のあるビューをレンダリングしようとするため、redirectToAction を実行できないようです。ビューを返すと、完全にめちゃくちゃになり、まったく正しく見えません。

私が抱えているこれらの問題に対するアイデアや解決策、あるいはより良い解決策の提案をお持ちの方はいらっしゃいますか?

どうもありがとう!

以下は例です。私がやろうとしているのは、GetViewForEmail メソッドを作成することです。

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

Tim Scott からの承認された回答 (私が少し変更してフォーマットしました):

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

使用例

コントローラーから注文確認メールを取得するために呼び出しが行われ、Site.Master の場所が渡されるとします。

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

ベストアンサー1

これが私が思いついたもので、うまく機能しています。コントローラーの基本クラスに次のメソッドを追加しました。(コントローラーをパラメーターとして受け入れるこれらの静的メソッドを他の場所にいつでも作成できると思います)

MVC2 .ascx スタイル

protected string RenderViewToString<T>(string viewPath, T model) {
  ViewData.Model = model;
  using (var writer = new StringWriter()) {
    var view = new WebFormView(ControllerContext, viewPath);
    var vdd = new ViewDataDictionary<T>(model);
    var viewCxt = new ViewContext(ControllerContext, view, vdd,
                                new TempDataDictionary(), writer);
    viewCxt.View.Render(viewCxt, writer);
    return writer.ToString();
  }
}

Razor .cshtml スタイル

public string RenderRazorViewToString(string viewName, object model)
{
  ViewData.Model = model;
  using (var sw = new StringWriter())
  {
    var viewResult = ViewEngines.Engines.FindPartialView(ControllerContext,
                                                             viewName);
    var viewContext = new ViewContext(ControllerContext, viewResult.View,
                                 ViewData, TempData, sw);
    viewResult.View.Render(viewContext, sw);
    viewResult.ViewEngine.ReleaseView(ControllerContext, viewResult.View);
    return sw.GetStringBuilder().ToString();
  }
}

編集: Razor コードを追加しました。

おすすめ記事