【问题标题】:IRazorViewEngine.FindView with GetView can't find view带有 GetView 的 IrazorViewEngine.FindView 找不到视图
【发布时间】:2020-07-14 17:04:29
【问题描述】:

在我的 asp.net 核心项目中,我尝试使用此方法查找 Razor 视图:

private IView FindView(ActionContext actionContext, string viewName)
{
    var getViewResult = _viewEngine.GetView(executingFilePath: null, viewPath: viewName, isMainPage: true);
    if (getViewResult.Success)
    {
        return getViewResult.View;
    }

    var findViewResult = _viewEngine.FindView(actionContext, viewName, isMainPage: true);
    if (findViewResult.Success)
    {
        return findViewResult.View;
    }

    var searchedLocations = getViewResult.SearchedLocations.Concat(findViewResult.SearchedLocations);
    var errorMessage = string.Join(
        Environment.NewLine,
        new[] { $"Unable to find view '{viewName}'. The following locations were searched:" }.Concat(searchedLocations));

    throw new InvalidOperationException(errorMessage);
}

在哪里

viewName = "Views/Email/ResetPassword.cshtml"

_viewEngineIRazorViewEngine,但没有找到。

我的项目结构:

IView.FindView 方法是从业务中调用的。

我还有另一个项目,它具有项目结构并使用相同的方法来检索视图,更重要的是,它找到了这个视图,但它使用 netcoreapp2.2,而我当前的项目使用 netcoreapp3.1(Microsoft. AspNetCore.Mvc.Razor 版本相同 - 2.2.0)。

为什么这个方法在 .net core 3.1 上找不到视图?


更新

两个项目都会在构建时将此 Views 文件夹复制到 Api\bin\Debug\netcoreapp{version} 文件夹。

【问题讨论】:

  • 请创建一个minimal reproducible example。假设 _viewEngine 是 Razor 视图引擎,据我记得,在搜索视图时需要去掉文件扩展名(此处为 .cshtml)。所以我不相信这适用于另一个项目。
  • @CodeCaster 因为它被提到了here,所以没有必要关闭扩展。所以它起作用了。
  • @KainWhite 如果您在调用GetView 时设置isMainPage: false); 会发生什么?看起来在FindView 中您只需传递视图的名称而不需要目录信息,我想这种方法不需要扩展名。
  • @RyanWilson 仍然没有找到它。 .FindView() 相同
  • @KainWhite 您是否尝试查找任何其他视图以查看是否可以找到它们?如果您也找不到其他视图,我想您的代码有问题。

标签: asp.net-core asp.net-core-mvc razorengine


【解决方案1】:

虽然我在 Core 3.1 中从头开始构建东西,而不是从早期版本升级,但我遇到了同样的问题。我通过执行以下操作使事情正常进行:

我创建了IWebHostEnvironment 的实现(我调用了我的DummyWebHostEnvironment.cs)。除了一个接口的属性之外,我将所有属性都保留为默认实现;对于那个属性,我使用了包含视图的项目的名称。 (为简洁起见,我只是将其硬编码到下面的示例中;显然有更巧妙的方法来获取它。)

 public class DummyWebHostEnvironment : IWebHostEnvironment
    {
        public IFileProvider WebRootFileProvider { get => throw new System.NotImplementedException(); set => throw new System.NotImplementedException(); }
        public string WebRootPath { get => throw new System.NotImplementedException(); set => throw new System.NotImplementedException(); }
        public string ApplicationName { get => "TheProjectContainingMyViews.RazorClassLibrary"; set => throw new System.NotImplementedException(); }
        public IFileProvider ContentRootFileProvider { get => throw new System.NotImplementedException(); set => throw new System.NotImplementedException(); }
        public string ContentRootPath { get => throw new System.NotImplementedException(); set => throw new System.NotImplementedException(); }
        public string EnvironmentName { get => throw new System.NotImplementedException(); set => throw new System.NotImplementedException(); }
}

注意:从上面的代码可以看出,包含视图的项目是一个 RazorClassLibrary。 (我使用 thisthis 作为让 RazorViewEngine 在控制台应用程序中工作的指南。)

我有上面的实现,我将它与其他一些好东西一起添加到我的服务集合中:

private static RazorViewToStringRenderer GetRenderer()
        {
            var services = new ServiceCollection();
            var applicationEnvironment = PlatformServices.Default.Application;
            services.AddSingleton(applicationEnvironment);

            var appDirectory = Directory.GetCurrentDirectory();
    
            var environment = new DummyWebHostEnvironment();
            services.AddSingleton<IWebHostEnvironment>(environment);

            services.AddSingleton<ObjectPoolProvider, DefaultObjectPoolProvider>();

            var diagnosticSource = new DiagnosticListener("Microsoft.AspNetCore");
            services.AddSingleton<DiagnosticSource>(diagnosticSource);
            services.AddSingleton<DiagnosticListener>(diagnosticSource);

            services.AddLogging();
            services.AddMvc();
            services.AddSingleton<RazorViewToStringRenderer>();
            var provider = services.BuildServiceProvider();
            return provider.GetRequiredService<RazorViewToStringRenderer>();
        }

注意:请参阅上面的第一个链接以获取RazorViewToStringRenderer 的代码。界面如下:

public interface IRazorViewToStringRenderer
    {
        Task<string> RenderViewToStringAsync<TModel>(string viewName, TModel model);
    }

然后,在Program.cs,我可以这样做:

static async Task Main(string[] args)
        {
            var dto = BuildDto();
            var renderer = GetRenderer();

            var renderedString = await renderer.RenderViewToStringAsync("Views/Path/To/Some.cshtml", dto);
// ...

        }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-08-23
    • 2017-02-24
    • 1970-01-01
    • 1970-01-01
    • 2013-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多