ASP.NET MVC Razor:コントローラーアクション内でRazorパーシャルビューのHTMLをレンダリングする方法


97

ASP.NETビューエンジンで特定の部分ビューのHTMLを生成する方法は既知です。

ただし、この機能がかみそり部分ビューで使用されている場合、例外は部分ビューが「UserControl」から派生しないことを示しているため、機能しません。

かみそり部分ビューをサポートするようにレンダリングを修正するにはどうすればよいですか?

この部分的なビューから電子メールを生成するため、これが必要です...

更新:

失敗するコード(@mcl):

public string RenderPartialToString(string controlName, object viewData)
    {
        ViewPage viewPage = new ViewPage() { ViewContext = new ViewContext() };
        viewPage.Url = this.GetUrlHelper();

        string fullControlName = "~/Views/Email/" + controlName + ".ascx";

        viewPage.ViewData = new ViewDataDictionary(viewData);
        viewPage.Controls.Add(viewPage.LoadControl(fullControlName));

        StringBuilder sb = new StringBuilder();
        using (StringWriter sw = new StringWriter(sb))
        {
            using (HtmlTextWriter tw = new HtmlTextWriter(sw))
            {
                viewPage.RenderControl(tw);
            }
        }
        return sb.ToString();
    }

1
これまでに持っていて例外を生成するコードを見せていただけますか?
mlibby 2010

回答:


154
@Html.Partial("nameOfPartial", Model)

更新

protected string RenderPartialViewToString(string viewName, object model)
{
    if (string.IsNullOrEmpty(viewName))
        viewName = ControllerContext.RouteData.GetRequiredString("action");

    ViewData.Model = model;

    using (StringWriter sw = new StringWriter()) {
        ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(ControllerContext, viewName);
        ViewContext viewContext = new ViewContext(ControllerContext, viewResult.View, ViewData, TempData, sw);
        viewResult.View.Render(viewContext, sw);

        return sw.GetStringBuilder().ToString();
    }
}

はい、これはビュー内に部分的なビューをレンダリングする方法です。しかし、それをコントローラーアクション内にレンダリングする方法は?
Peter Stegnar

これですばらしいです。RazonおよびASP表記で動作します。
Peter Stegnar

2
1つのサブ質問:別のコントローラースコープにあるビューを現在のビューにレンダリングする方法は?"EmailController"スコープ(メールビューフォルダー)にあるとしましょうか。
Peter Stegnar、2010

1
これは素晴らしい解決策でした。私はメールで正確なニーズがあり、これを使用することにしました。
uadrive 2011年

2
@AmeyKhadatkar:いいえ。jqueryはクライアント側であり、ビューはブラウザに送信される前にサーバー側で生成されます。
jgauffin

8

十分な回答はすでに与えられていますが、MVCコントローラークラスで利用できるヘルパーメソッドなしで使用できる、より冗長でないソリューションを提案したいと思います。「RazorEngine」と呼ばれるサードパーティのライブラリを使用すると、.NetファイルIOを使用してかみそりファイルの内容を取得し、呼び出すことができます

string html = Razor.Parse(razorViewContentString, modelObject);

こちらからサードパーティのライブラリを入手してください


5

ここRenderView Controller extensionからも使用できますソース

次のように使用します。

public ActionResult Do() {
var html = this.RenderView("index", theModel);
...
}

それがために働くかみそりウェブフォーム viewengines


リンクを確認した。@ChurkNorrisはASP.net MVC Awesomeの作者で、バージョン2.0(現在最新リリースは2012年3月12日)の商用製品です。バージョン1.9(2011年6月9日最新リリース)はまだオープンソースですが、おそらくこれ以上開発されません。1.9のフォークはありますか?
Joel Purra

@Omu:RenderViewは無効です。msdn.microsoft.com/en-us/library/…を
roland

@Rolandこれは、カスタムコントローラの拡張機能である
OMU

1

誰かが別のコントローラーのためにそれを行う方法を疑問に思っているのを見ました。

私の場合、すべてのメールテンプレートをViews / Emailフォルダーに入れましたが、ビューを関連付けたコントローラーに渡すようにこれを変更できます。

public static string RenderViewToString(Controller controller, string viewName, object model)
    {
        var oldController = controller.RouteData.Values["controller"].ToString();

        if (controller.GetType() != typeof(EmailController))
            controller.RouteData.Values["controller"] = "Email";

        var oldModel = controller.ViewData.Model;
        controller.ViewData.Model = model;
        try
        {
            using (var sw = new StringWriter())
            {
                var viewResult = ViewEngines.Engines.FindView(controller.ControllerContext, viewName,
                                                                           null);

                var viewContext = new ViewContext(controller.ControllerContext, viewResult.View, controller.ViewData, controller.TempData, sw);
                viewResult.View.Render(viewContext, sw);

                //Cleanup
                controller.ViewData.Model = oldModel;
                controller.RouteData.Values["controller"] = oldController;

                return sw.GetStringBuilder().ToString();
            }
        }
        catch (Exception ex)
        {
            Elmah.ErrorSignal.FromCurrentContext().Raise(ex);

            throw ex;
        }
    }

基本的にこれが行うことは、AccountControllerなどのコントローラーを取得して、それがEmailControllerであると考えるように変更して、コードがViews/Emailフォルダー内を検索するようにすることです。FindViewメソッドはパラメーターとしてまっすぐなパスをとらないため、これを行う必要があります。ControllerContext

文字列のレンダリングが完了すると、AccountControllerがResponseオブジェクトで使用される初期状態に戻ります。


1

素晴らしいコード; 少しのヒント:ビューモデルだけでなく、さらに多くのデータをバイパスする必要がある場合

 if (model is ViewDataDictionary)
 {
     controller.ViewData = model as ViewDataDictionary;
 } else {
     controller.ViewData.Model = model;
 }

2
回答が完了していません
poohdedoo 2013年

0

HtmlHelper拡張機能として@jgauffin回答を借用します。

public static class HtmlHelperExtensions
{
    public static MvcHtmlString RenderPartialViewToString(
        this HtmlHelper html, 
        ControllerContext controllerContext, 
        ViewDataDictionary viewData,
        TempDataDictionary tempData,
        string viewName, 
        object model)
    {
        viewData.Model = model;
        string result = String.Empty;

        using (StringWriter sw = new StringWriter())
        {
            ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(controllerContext, viewName);
            ViewContext viewContext = new ViewContext(controllerContext, viewResult.View, viewData, tempData, sw);
            viewResult.View.Render(viewContext, sw);

            result = sw.GetStringBuilder().ToString();
        }

        return MvcHtmlString.Create(result);
    }
}

かみそりビューでの使用:

Html.RenderPartialViewToString(ViewContext, ViewData, TempData, "Search", Model)

1
@ Html.Partial(string partialViewName、object model、ViewDataDictionary viewData)を使用することの違いを説明できますか?HtmlHelperが必要なため、どのようなメリットがありますか?
bkqc
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.