Serve static files outside wwwroot, but handle PhysicalFileProvider when the directory does not exist

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

For argument, let me pretend that I need a simple website that has a page that will read the contents of this directory and display some files. This page may also allow you to download files from the /Documents subdirectory. An example directory would be C:\Example\Documents .

Since this is an aspnet kernel 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?}"); }); } 

Now I have a problem with two parts. app.UseExceptionHandler("/Home/Error"); does not seem to take effect at all if an exception is thrown in this method. If the path used by PhysicalFileProvider does not exist, an internal server 500 error occurs and the page is displayed when the application does not start the message. However, if I am in developer mode, I see a developer exception page with a real problem. I just want to create a friendly error page to deal with this situation.

Another part of the problem is what happens when users fix the problem by creating a directory and adding content. Once created, they will refresh the page. The fix is ​​to force the application to close and restart it. Ideally, I would like him to recover on his own. Do I need to use the UseStaticHandle element in the controller? Can you do it? My attempt failed while trying to use dependency injection in IApplicationBuilder in my controller, but I also did not expect it to work.

I honestly don't know how best to handle this. The ideal situation is to allow the application to start correctly, which can be performed using Directory.Exists() checks around the PhysicalFileProvider , and then forward the user to the error page, but the user will still have to restart the application when they fix the problem.

+5
source share
1 answer

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) 

In Startup.cs, replace PhysicalFileProvider with PhysicalFileProvider2. Please find the source code for PhysicalFileProvider2 .

Detailed Description PhysicalFileProvider2

Class PhysicalFileProvider The ASP.Net core insists that the directory specified as the constructor argument already exists at startup, and if it does not exist, refuses to start correctly

I wrote a PhysicalFileProvider2 class that can be used instead. It can be created even if the directory does not exist. But the first time you call any of its methods, a directory is created if it does not already exist. It now starts correctly, and users can add files to the directory, which are then properly maintained.

 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); } } 
+1
source

Source: https://habr.com/ru/post/1268814/


All Articles