在将 razor 视图呈现为字符串时修改控制器上下文



将视图呈现为字符串已经被问了很多次,但我的问题有所不同。

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

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

我无法确切地弄清楚 Render 方法使用什么属性来确定要查看哪些视图文件夹。从本质上讲,我希望弄清楚这一点,以便我可以告诉它查看电子邮件视图文件夹。

这是我的代码供参考:

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在订单视图文件夹中查找我的视图,我需要告诉它在电子邮件视图文件夹中查找。

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

所有这些参数都来自路由数据(除非通过 View("viewname") 等参数明确覆盖。它们特别actioncontrollerarea。通过修改这些值,可以更改 MVC 的多种工作方式。包括在选择控制器之前确定要使用的控制器。操作和区域相同。

希望这有帮助。

最新更新