在wwwroot外部提供静态文件,但在目录不存在时处理PhysicalFileProvider [英] Serve static files outside wwwroot, but handle PhysicalFileProvider when directory does not exist

查看:189
本文介绍了在wwwroot外部提供静态文件,但在目录不存在时处理PhysicalFileProvider的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试从wwwroot外部提供文件,但也处理目录可能还不存在的设置情况.例如,如果我建立了一个依赖于此目录的站点,但是用户没有遵循安装说明,而是先创建目录.

I am trying to serve files from outside wwwroot but also handle a setup situation where the directory may not exist yet. For example, if I built a site which relies on this directory, but a user did not follow install instructions and create the directory first.

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

For the sake of argument, let's pretend I want a simple website which has a page that will read the contents of that directory and display some files. This page might also allow you to download files from /Documents subdirectory. The example directory would be C:\Example\Documents.

因为这是一个aspnet核心mvc项目,所以我将在Startup.cs内的Configure方法中使用UseStaticFiles()

As this is an aspnet core mvc project, I would use UseStaticFiles() in the Configure method inside Startup.cs

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,然后显示该页面,并显示应用程序启动失败消息.但是,如果我处于开发人员模式,则确实会看到带有实际问题的开发人员例外页面.我真的只想制作一个友好的错误页面来处理这种情况.

Now I have a two part problem. The app.UseExceptionHandler("/Home/Error"); does not seem to take effect at all if an exception is thrown in this method. If the path used in PhysicalFileProvider does not exist, an internal server error 500 is thrown and the page is then displayed with an application failed to start message. If I am in developer mode, however, I do see the developer exception page with the actual problem. I really just want to make a friendly error page to handle this situation.

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

The other part of the problem is what happens when the users fix the issue by creating the directory and adding content. Once created, they would then refresh the page. The fix is to force close the application and restart it. Ideally, I would like it to recover on its own. Would I need to do the UseStaticHandle piece in the Controller? Can you even do that? My attempt failed when trying to use dependency injection on IApplicationBuilder in my controller, but I also did not expect it to work.

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

I am honestly unsure what the best way to handle this would be. The ideal situation is to allow the application to start properly, which could be accomplished with a Directory.Exists() check around the PhysicalFileProvider, and then forward the user to an error page, but the user would still need to restart the application when they fix the issue.

推荐答案

PhysicalFileProvider引发的异常:

Exception thrown by 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 的源代码.

In Startup.cs replace PhysicalFileProvider with PhysicalFileProvider2. Please find source code of PhysicalFileProvider2 below.

PhysicalFileProvider2的详细说明

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

Class PhysicalFileProvider of ASP.Net core insists that directory given as argument to constructor already exists on startup and if it not exists refuses to start up properly

我写了PhysicalFileProvider2类,可以代替使用它.即使目录不存在,也可以实例化它.但是,如果该目录尚不存在,则在首次调用其任何方法时都会创建该目录.现在启动可以正常工作,用户可以将文件添加到目录中,然后可以正确提供文件.

I wrote class PhysicalFileProvider2 which can be used instead. It can be instantiated even if the directory does not exist. But on first invocation of any of its method the directory is created if it not already exists. Now startup properly works and users can add files to directory, which then are properly served.

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

这篇关于在wwwroot外部提供静态文件,但在目录不存在时处理PhysicalFileProvider的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆