ASP.NETビューエンジンで特定の部分ビューのHTMLを生成する方法 既知 。
ただし、この機能がカミソリのパーシャルビューで使用されている場合、パーシャルビューは「UserControl」から派生しないという例外があるため、動作しません。
かみそり部分ビューをサポートするためにレンダリングを修正する方法は?
この部分的なビューからメールを生成するため、これが必要です...
UPDATE:
失敗するコード(@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();
}
@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();
}
}
適切な答えは既に与えられていますが、MVCコントローラクラスで利用可能なヘルパーメソッドなしで使用できる、より冗長なソリューションを提案したいと思います。 「RazorEngine」というサードパーティライブラリを使用すると、.NetファイルIOを使用して、カミソリファイルの内容を取得し、呼び出すことができます
string html = Razor.Parse(razorViewContentString, modelObject);
サードパーティライブラリを取得します こちら 。
私は誰かが別のコントローラーのためにそれをする方法を疑問に思っているのを見ました。
私の場合、すべてのメールテンプレートは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オブジェクトで使用されます。
素晴らしいコード;小さなヒント:ビューモデルだけでなく、より多くのデータをバイパスする必要がある場合.
if (model is ViewDataDictionary)
{
controller.ViewData = model as ViewDataDictionary;
} else {
controller.ViewData.Model = model;
}
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)