在wwwroot之外提供静态文件,但在目录不存在时处理PhysicalFileProvider

Jef*_*eff 5 c# asp.net-core-mvc

我正在尝试从外部提供文件,wwwroot但也处理目录可能尚不存在的设置情况.例如,如果我构建了一个依赖于此目录的站点,但是用户没有按照安装说明进行操作并首先创建该目录.

为了争论,我们假装我想要一个简单的网站,其中有一个页面可以读取该目录的内容并显示一些文件.此页面还可能允许您从/Documents子目录下载文件.示例目录将是C:\Example\Documents.

由于这是一个aspnet核心mvc项目,我将UseStaticFiles()在Startup.cs中使用Configure方法

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory) {
    if (env.IsDevelopment()) {
        app.UseDeveloperExceptionPage();
        app.UseBrowserLink();
    } else {
        app.UseExceptionHandler("/Home/Error");
    }

    app.UseStaticFiles();

    // If C:/Example/Documents does not exist, an exception is thrown
    // ArgumentException: The directory name C:\Example\Documents\ is invalid
    // What is worse, the users is not directed to /Home/Error due to the application failing to properly start.
    app.UseStaticFiles(new StaticFileOptions() {
        FileProvider = new PhysicalFileProvider("C:/Example/Documents"),
        RequestPath = new PathString("/Documents"),
    });

    app.UseMvc(routes => {
        routes.MapRoute(
            name: "default",
            template: "{controller=Home}/{action=Index}/{id?}");
    });
}
Run Code Online (Sandbox Code Playgroud)

现在我有两个问题.在app.UseExceptionHandler("/Home/Error");似乎没有了一个异常的方法抛出生效的.如果所使用的路径PhysicalFileProvider不存在,则抛出内部服务器错误500,然后显示该页面,并且应用程序无法启动消息.但是,如果我处于开发人员模式,我确实看到了包含实际问题的开发人员异常页面.我真的只想制作一个友好的错误页面来处理这种情况.

问题的另一部分是当用户通过创建目录和添加内容来解决问题时会发生什么.一旦创建,他们就会刷新页面.解决方法是强制关闭应用程序并重新启动它.理想情况下,我希望它能够自行恢复.我需要在Controller中执行UseStaticHandle部分吗?你能做到吗?尝试在我的控制器中对IApplicationBuilder使用依赖注入时,我的尝试失败了,但我也没想到它会起作用.

老实说,我不确定处理这个问题的最佳方法是什么.理想情况是允许应用程序正常启动,这可以通过Directory.Exists()检查来完成PhysicalFileProvider,然后将用户转发到错误页面,但用户仍然需要在修复问题时重新启动应用程序.

Aed*_*seh 5

PhysicalFileProvider 抛出的异常:

System.ArgumentException: The directory name D:\Daten7\ is invalid.
Parameter name: path
   at System.IO.FileSystemWatcher..ctor(String path, String filter)
   at System.IO.FileSystemWatcher..ctor(String path)
   at Microsoft.Extensions.FileProviders.PhysicalFileProvider.CreateFileWatcher(String root)
   at Microsoft.Extensions.FileProviders.PhysicalFileProvider..ctor(String root)
   at WebApplication1.Startup.Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
Run Code Online (Sandbox Code Playgroud)

在 Startup.cs 中,将 PhysicalFileProvider 替换为 PhysicalFileProvider2。请在下面找到PhysicalFileProvider2 的源代码。

PhysicalFileProvider2 详细说明

ASP.Net 核心的类 PhysicalFileProvider坚持作为构造函数参数给出的目录在启动时已经存在,如果不存在则拒绝正常启动

我编写了可以使用的类 PhysicalFileProvider2。即使目录不存在,它也可以被实例化。但是在第一次调用其任何方法时,如果目录不存在,则会创建该目录。现在启动正常工作,用户可以将文件添加到目录,然后正确地提供服务。

public class PhysicalFileProvider2 : IFileProvider
{
    private string root;
    private PhysicalFileProvider physicalFileProvider;

    public PhysicalFileProvider2(string root)
    {
        this.root = root;
    }

    private PhysicalFileProvider GetPhysicalFileProvider()
    {
        if (!File.Exists(root))
        {
            Directory.CreateDirectory(root);
        }
        if (physicalFileProvider == null)
        {
            physicalFileProvider = new PhysicalFileProvider(root);
        }
        return physicalFileProvider;
    }

    public IDirectoryContents GetDirectoryContents(string subpath)
    {
        return GetPhysicalFileProvider().GetDirectoryContents(subpath);
    }

    public IFileInfo GetFileInfo(string subpath)
    {
        return GetPhysicalFileProvider().GetFileInfo(subpath);
    }

    public IChangeToken Watch(string filter)
    {
        return GetPhysicalFileProvider().Watch(filter);
    }
}
Run Code Online (Sandbox Code Playgroud)