RazorViewEngine.FindView 找不到预编译视图

RazorViewEngine.FindView can't find the precompiled view

App.WebApp.Views是我在一个解决方案中的项目,我把我的观点放在App.Views中并用RazorGenerator预编译。如果我使用 App.Web 就好了,

~/Views/Index.cshtml is virtual path of my view in App.View

它可以在 App.Web

中成功渲染此视图
public ActionResult Index() {
  return View("~/Views/Index.cshtml");
}

但是当我尝试 RenderViewToString 时,它 returns 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();
        }
    }
}

而这一切又如何,

FakeController.RenderViewToString("FakeName", "~/Views/Index.csthml", MessageModel);

This is discussed and probably solved in asp.net core,但我正在使用 asp.net mvc 5.

你能帮我弄清楚为什么它不起作用吗?

您正在尝试使用 Razor View Engine 获取预编译视图。这是个错误。 Razor 引擎根据 cshtml 文件生成视图。然而,在预编译视图的情况下,cshtml 文件已经被 RazorGenerator 编译为一组从 System.Web.Mvc.WebViewPage 派生的 classes。这些 classes 覆盖方法 Execute()(由 RazorGenerator 根据输入 cshtml 自动生成)将 html 写入输出 TextWriter。 不再需要原始视图文件 (cshtml),因此不会随应用程序一起部署。当您调用尝试定位 cshtml 并基于它构建视图的 Razor 时,它预计会 returns null view.

ASP.NET MVC 支持多个视图引擎(实现 System.Web.Mvc.IViewEngine 的 classes)。 RazorViewEngine 就是其中之一。 RazorGenerator.Mvc NuGet 包添加了自己的基于预编译视图工作的视图引擎 (PrecompiledMvcEngine)。已注册的视图引擎存储在 ViewEngines.Engines 集合中。当您安装 RazorGenerator.Mvc NuGet 包时,它会添加 RazorGeneratorMvcStart class 来注册 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();
    }
}

重要说明:您应该将 RazorGenerator.Mvc NuGet 包安装到您的视图项目 (App.Views) 中,而不是 Web 应用程序项目中,因为 PrecompiledMvcEngine 将当前程序集作为源对于预编译视图。还要确保 RazorGeneratorMvcStart 没有添加到 App.Web 项目中。当我添加对 RazorGenerator.Mvc.dll 程序集的引用时,它发生在我身上。

Sample Project on GitHub