RazorViewEngine.FindView 无法找到预编译视图。

8

App.WebApp.Views都是我的项目,放在同一个解决方案中。我将视图放在了App.Views并使用RazorGenerator进行了预编译。如果我使用App.Web,它可以正常工作,如下:

~/Views/Index.cshtml 是我的视图在App.View中的虚拟路径。

它可以成功地渲染在App.Web中。

public ActionResult Index() {
  return View("~/Views/Index.cshtml");
}

但是当我尝试使用RenderViewToString时,它返回null

class FakeController : ControllerBase
{
    protected override void ExecuteCore() { }
    public static string RenderViewToString(string controllerName, string viewName, object viewData)
    {
        using (var writer = new StringWriter())
        {
            var routeData = new RouteData();
            routeData.Values.Add("controller", controllerName);
            var fakeControllerContext = new ControllerContext(new HttpContextWrapper(new HttpContext(new HttpRequest(null, "http://google.com", null), new HttpResponse(null))), routeData, new FakeController());
            var razorViewEngine = new RazorViewEngine();
            var razorViewResult = razorViewEngine.FindView(fakeControllerContext, viewName, "", false);
            var viewContext = new ViewContext(fakeControllerContext, razorViewResult.View, new ViewDataDictionary(viewData), new TempDataDictionary(), writer);
            razorViewResult.View.Render(viewContext, writer);
            return writer.ToString();
        }
    }
}

这是如何做到的,涉及IT技术。
FakeController.RenderViewToString("FakeName", "~/Views/Index.csthml", MessageModel);

在此输入图片描述

这个问题已经在asp.net core中被讨论并可能已经解决,但我正在使用asp.net mvc 5。

请问你能帮我找出为什么它不起作用吗?

1个回答

7
您正在尝试使用 Razor 视图引擎来获取预编译视图,这是一个错误。Razor 引擎基于 cshtml 文件生成视图。然而,在预编译视图的情况下,cshtml 文件已经由 RazorGenerator 编译成一组派生自 System.Web.Mvc.WebViewPage 的类。这些类重写了 Execute() 方法(根据输入的 cshtml 自动生成),将 HTML 写入到输出的 TextWriter 中。
原始视图文件(cshtml)不再需要,并且因此不部署在应用程序中。当您调用 Razor 并尝试定位 cshtml 并基于其构建视图时,它会返回 null 视图。
ASP.NET MVC 支持多个视图引擎(实现 System.Web.Mvc.IViewEngine 接口的类)。RazorViewEngine 是其中之一。RazorGenerator.Mvc NuGet 包添加了它自己的视图引擎(PrecompiledMvcEngine),该引擎基于预编译视图工作。注册的视图引擎存储在 ViewEngines.Engines 集合中。当您安装 RazorGenerator.Mvc NuGet 包时,它会添加 RazorGeneratorMvcStart 类来注册 PrecompiledMvcEngine 的实例。
[assembly: WebActivatorEx.PostApplicationStartMethod(typeof(App.Views.RazorGeneratorMvcStart), "Start")]

namespace App.Views {
    public static class RazorGeneratorMvcStart {
        public static void Start() {
            var engine = new PrecompiledMvcEngine(typeof(RazorGeneratorMvcStart).Assembly) {
                UsePhysicalViewsIfNewer = HttpContext.Current.Request.IsLocal
            };

            ViewEngines.Engines.Insert(0, engine);

            // StartPage lookups are done by WebPages. 
            VirtualPathFactoryManager.RegisterVirtualPathFactory(engine);
        }
    }
}

访问预编译视图时,您应该使用这个PrecompiledMvcEngine实例而不是RazorViewEngine。以下是经过调整的RenderViewToString方法的代码:

public static string RenderViewToString(string controllerName, string viewName, object viewData)
{
    using (var writer = new StringWriter())
    {
        var routeData = new RouteData();
        routeData.Values.Add("controller", controllerName);
        var fakeControllerContext = new ControllerContext(new HttpContextWrapper(new HttpContext(new HttpRequest(null, "http://google.com", null), new HttpResponse(null))), routeData, new FakeController());
        var viewEngine = ViewEngines.Engines.OfType<PrecompiledMvcEngine>().FirstOrDefault();
        if (viewEngine == null)
        {
            throw new InvalidOperationException("PrecompiledMvcEngine is not registered");
        }
        var viewResult = viewEngine.FindView(fakeControllerContext, viewName, "", false);
        var viewContext = new ViewContext(fakeControllerContext, viewResult.View, new ViewDataDictionary(viewData), new TempDataDictionary(), writer);
        viewResult.View.Render(viewContext, writer);
        return writer.ToString();
    }
}

重要提醒:您应该在视图项目(App.Views)中安装RazorGenerator.Mvc NuGet软件包,而不是在Web应用程序项目中安装,因为PrecompiledMvcEngine以当前程序集作为预编译视图的源。同时,请确保未将RazorGeneratorMvcStart添加到App.Web项目中。当我添加对RazorGenerator.Mvc.dll程序集的引用时,这种情况发生了。 Github上的示例项目

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接