NET MVC Razor: 如何在控制器操作中呈现 Razor 部分视图的 HTML

如何在 ASP.NET 视图引擎 已经知道了上生成给定部分视图的 HTML。

但是,如果这个功能是用于剃刀部分视图它不工作,作为例外说,部分视图不是来自“用户控制”。

如何修复渲染支持剃刀局部视图?

我需要这个,因为我生成电子邮件从这个部分视图..。

更新:

失败的代码(@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();
}
127895 次浏览
@Html.Partial("nameOfPartial", Model)

Update

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

You could also use the RenderView Controller extension from here (source)

and use it like this:

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

it works for razor and web-forms viewengines

I saw that someone was wondering how to do it for another controller.

In my case I had all of my email templates in the Views/Email folder, but you could modify this to pass in the controller in which you have views associated for.

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

Essentially what this does is take a controller, such as AccountController and modify it to think it's an EmailController so that the code will look in the Views/Email folder. It's necessary to do this because the FindView method doesn't take a straight up path as a parameter, it wants a ControllerContext.

Once done rendering the string, it returns the AccountController back to its initial state to be used by the Response object.

Although adequate answers have already been given, I'd like to propose a less verbose solution, that can be used without the helper methods available in an MVC controller class. Using a third party library called "RazorEngine" you can use .Net file IO to get the contents of the razor file and call

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

Get the third party library here.

great code; little hint: if you sometimes have to bypass more data and not only the viewmodel ..

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

Borrowing @jgauffin answer as an HtmlHelper extension:

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

Usage in a razor view:

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