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

时间:2017-06-13 16:20:32

标签: c# asp.net-core-mvc

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

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

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

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

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

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

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

1 个答案:

答案 0 :(得分:1)

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)
  

在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);
    }
}