在将剃刀视图渲染为字符串时修改控制器上下文

时间:2012-04-26 20:13:10

标签: c# razor

多次询问将视图呈现给字符串,但我的问题不同。

ViewEngineResult.View有一个名为Render(ViewContext, TextWriter)

的方法

如果我传入包含电子邮件视图的控制器,我的代码工作正常,但是如果操作方法来自另一个控制器,那么我需要能够修改ViewContext以查看EmailControllers视图。

我无法确切地知道Render方法用于确定要查看的视图文件夹的属性。基本上我想要弄明白这样我可以告诉它查看电子邮件views文件夹。

这是我的参考代码:

public static string RenderPartialViewToString(Controller controller, string viewName, object model)
    {
        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);

                controller.ViewData.Model = oldModel;
                return sw.GetStringBuilder().ToString();
            }
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }

所以回顾一下,如果我传递订单控制器,FindView在Orders视图文件夹中查找我的视图,我需要告诉它查看电子邮件视图文件夹。

1 个答案:

答案 0 :(得分:1)

ViewEngine查看RouteData以确定要加载的.cshtml文件。具体来说是controlleraction属性。你可以(并且可能推荐)传递你想要使用的控制器名称,但是你可以看到我现在已经在下面的代码中将它硬编码到Email

public static string RenderPartialViewToString(Controller controller, string viewName, object model)
{
    var oldModel = controller.ViewData.Model;
    controller.ViewData.Model = model;
    try
    {
        using (var sw = new StringWriter())
        {

            controller.RouteData.Values["controller"] = "Email";

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

            controller.ViewData.Model = oldModel;
            return sw.GetStringBuilder().ToString();
        }
    }
    catch (Exception ex)
    {
        throw ex;
    }
}

如果你真的想知道更多的东西

Razor在尝试确定要使用的视图时有几个位置。 {0}这里是操作(或以视图名称传递),{1}是控制器。

        ViewLocationFormats = new[] { 
            "~/Views/{1}/{0}.cshtml",
            "~/Views/{1}/{0}.vbhtml", 
            "~/Views/Shared/{0}.cshtml", 
            "~/Views/Shared/{0}.vbhtml"
        }; 

与此相同,除了我们还有{2}这个区域。

        AreaViewLocationFormats = new[] {
            "~/Areas/{2}/Views/{1}/{0}.cshtml", 
            "~/Areas/{2}/Views/{1}/{0}.vbhtml",
            "~/Areas/{2}/Views/Shared/{0}.cshtml", 
            "~/Areas/{2}/Views/Shared/{0}.vbhtml" 
        };

所有这些参数都来自RouteData(除非通过View("viewname")等参数专门覆盖。它们是专门的actioncontrollerarea。通过修改这些参数值可以改变MVC的几种工作方式。包括在选择一个控制器之前确定使用哪个控制器。与动作和区域相同。

希望这有帮助。