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年

Answers:


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 2010年

太好了!使用Razon和ASP表示法。
Peter Stegnar 2010年

2
一个子问题:如何呈现位于当前当前另一个Controller范围内的视图?可以说它在“ EmailController”范围(电子邮件视图文件夹)中吗?
Peter Stegnar

1
这是一个很好的解决方案。我对电子邮件有确切的需求,因此选择使用它。
uadrive 2011年

2
@AmeyKhadatkar:不。jQuery是客户端,视图是在服务器端生成的,然后发送到浏览器。
jgauffin

8

尽管已经给出了足够的答案,但是我想提出一个不太冗长的解决方案,该解决方案可以在MVC控制器类中没有可用的辅助方法的情况下使用。使用名为“ RazorEngine”的第三方库,您可以使用.Net文件IO获取razor文件的内容并进行调用

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

此处获取第三方库。


5

您也可以使用RenderView Controller extensionfrom heresource

并像这样使用它:

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

它适用于剃须刀网络形式的视图引擎


检查链接。@ChurkNorris是ASP.net MVC Awesome的作者,该产品是2.0版(当前最新发布于2012年3月12日)的商业产品。1.9版(2011年6月9日最新发布)仍是开源的,但可能不会再开发了。有1.9的叉子吗?
乔尔·普拉

@Omu:RenderView是无效的。见msdn.microsoft.com/en-us/library/...
罗兰

@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

好的代码;小提示:如果您有时不得不绕过更多数据,而不仅仅是viewmodel ..

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

2
您尚未完成答案
poohdedoo

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(字符串partialViewName,对象模型,ViewDataDictionary viewData)的区别?由于需要HtmlHelper,有什么好处?
bkqc
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.