【问题标题】:ASP.NET MVC Razor: How to render a Razor Partial View's HTML inside the controller actionASP.NET MVC Razor:如何在控制器操作中呈现 Razor 部分视图的 HTML
【发布时间】:2011-05-19 16:12:06
【问题描述】:

如何在 ASP.NET 视图引擎is known 上生成给定局部视图的 HTML。

但是,如果在 razor 局部视图上使用此功能,它就不起作用,因为异常表示局部视图不是从“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();
    }

【问题讨论】:

  • 你能展示你到目前为止产生异常的代码吗?

标签: c# asp.net-mvc razor


【解决方案1】:

您也可以使用来自hereRenderView Controller extension (source)

并像这样使用它:

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

它适用于 razorweb-forms 视图引擎

【讨论】:

【解决方案2】:

借用@jgauffin 答案作为 HtmlHelper 扩展:

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)

【讨论】:

  • 您能解释一下使用@Html.Partial(string partialViewName, object model, ViewDataDictionary viewData) 的区别吗?需要 HtmlHelper 有什么好处?
【解决方案3】:
@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();
    }
}

【讨论】:

  • 是的,这就是在视图中渲染局部视图的方式。但是如何在控制器动作中渲染它呢?
  • 太好了,现在就是这样!使用 Razon 和 ASP 表示法。
  • 一个子问题:如何渲染另一个控制器范围内的视图然后是当前的?假设它在“EmailController”范围内(电子邮件视图文件夹)?
  • 这是一个很好的解决方案。我对电子邮件有确切的需求并选择使用它。
  • @AmeyKhadatkar:没有。 jquery 是客户端,视图在发送到浏览器之前在服务器端生成。
【解决方案4】:

很棒的代码;小提示:如果你有时不得不绕过更多数据而不仅仅是视图模型..

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

【讨论】:

  • 你的答案还没有完成
【解决方案5】:

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

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

获取第三方库here

【讨论】:

    【解决方案6】:

    我看到有人想知道如何为另一个控制器做这件事。

    在我的情况下,我的所有电子邮件模板都在 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 对象使用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-05-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-03
      • 2011-08-09
      相关资源
      最近更新 更多