Asp.Net Virtual directory in core

Time:2020-9-3

Write it at the front

Deploy now Asp.Net Core applications are no longer limited to windows IIS. They are deployed by docker container and various reverse agents. There are also a small number of IIS deployment, IIS deployment is really fast and simple, graphical operation of three, five division two can publish a system. in the past Asp.Net When MVC projects are deployed, IIS is often used as a function——Virtual directory

The virtual directory can be directly located to other non project paths, and the path can be used as a part of the website to save the uploaded files to other drive letters or indirectly use static files other than the project. stay Asp.Net In MVC, accessing files from virtual paths is also very simple, such asServer.MapPath(“~/Upload/liohuang.jpg”); 

But in the Asp.Net Different from the core, it is abstracted into a “file system”, that isFileProvider。 Fileprovider is a general term for all types and corresponding objects that implement ifileprovider interface. In the. Net core file system [2]: what is a fileprovider? 》The article has been dialyzed, it is not wordy here.

The content of this article is as follows: Asp.Net How to use “virtual directory” gracefully in core application.

Practical operation

First, create a new. Net core webapi empty project and deploy it on disk D. virtual directory assumes that the physical path is in disk F. create three test directories respectivelyF:/test1 、 F:/test2AndF:/test3The corresponding files are stored in the directory1/2/3.jpgAndmybook.txt 。

Read virtual directory file

InStartup.ConfigureServicesInjectionIFileProvider :

services.AddSingleton(new PhysicalFileProvider("F:\\test1"));

Create a new controller, readmybook.txtContent in:

[ApiController]
    [Route("[controller]/[action]")]
    public class LioHuangController : ControllerBase
    {
        [HttpGet]
        public object GetFiles([FromServices]IFileProvider fileProvider)
        {
            var file = fileProvider.GetFileInfo("mybook.txt");
            if (file.Exists)
            {
                return ReadTxtContent(file.PhysicalPath);
            }
            return 0;
        }

        /// 
        ///Read text (original address: https://www.cnblogs.com/EminemJK/p/13362368.html )
        /// 
        private string ReadTxtContent(string Path)
        {
            if (!System.IO.File.Exists(Path))
            {
                return "Not found!";
            }
            using (StreamReader sr = new StreamReader(Path, Encoding.UTF8))
            {
                StringBuilder sb = new StringBuilder();
                string content;
                while ((content = sr.ReadLine()) != null)
                {
                    sb.Append(content);
                }
                return sb.ToString();
            }
        }
    }

After the interface reads the file, it returns the following contents:

 IFileProviderThe interface uses directory to organize files and use them uniformlyIFileInfoInterfacePhysicalPathRepresents the physical path of the file.

    public interface IFileInfo
    {
        bool Exists { get; }
        bool IsDirectory { get; }
        DateTimeOffset LastModified { get; }
        string Name { get; }
        string PhysicalPath { get; }
        Stream CreateReadStream();
    }

How to deal with multiple virtual directories? Simple, multiple injectionIFileProviderThat’s it,

services.AddSingleton(new PhysicalFileProvider("F:\\test1"));
   services.AddSingleton(new PhysicalFileProvider("F:\\test2"));
   services.AddSingleton(new PhysicalFileProvider("F:\\test3"));

The code is modified as follows:

public object GetFiles([FromServices] IEnumerable fileProviders)

 IEnumerable fileProvidersThe interface array will have three, corresponding to different directories in the order of injection. Of course, injectionIFileProviderWe can encapsulate one layer. Let’s talk about it later.

In addition, some said it was directReadTxtContent(“F:\test1\mybook.txt”);Doesn’t it smell good? Fragrance, Asp.Net Core has more access than Asp.Net Before MVC, the old version of the project was much higher. It was true that files outside the project could be read directly, but it was not suitable for direct access. Unless you only use it in one place, you can read it directly. However, static file access can’t be accessed. It’s just background reading. So it is used in a unified wayIFileProviderThe maintainability of the code is much higher.

Static file access

InStartup.ConfigureSet the static file directory

      app.UseStaticFiles(new StaticFileOptions()
            {
                FileProvider = new PhysicalFileProvider("F:\\test1"),
                RequestPath = "/test"
            });;
      app.UseStaticFiles(new StaticFileOptions()
            {
                FileProvider = new PhysicalFileProvider("F:\\test2"),
                RequestPath = "/test"
            });
      app.UseStaticFiles(new StaticFileOptions()
            {
                FileProvider = new PhysicalFileProvider("F:\\test3"),
                RequestPath = "/test"
            });

 FileProviderAs mentioned above, set the root directory of the physical pathRequestPathIs the prefix of the access path and must be a slant bar“/”At the beginning, the access address prefix is:https://localhost:5001/test/ 。 Once set up, you can access the path outside the project.

For example, when IIS is deployed, the virtual directory settings in IIS can be ignored directly, and the “virtual directory” effect can be achieved completely through the configuration injected.

Simplify configuration

In order to facilitate direct use in real projects, it should be set to configurable:

Inappsettings.jsonSetting in:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*",

  "VirtualPath": [
    {
      "Realpath": "F: \ \ test1", // real path
      "RequestPath": "/test",
      "Alias": "first"
    },
    {
      "Realpath": "F: \ \ test2", // real path
      "RequestPath": "/test",
      "Alias": "second"
    },
    {
      "Realpath": "F: \ \ test3", // real path
      "RequestPath": "/test",
      "Alias": "third"
    }
  ]
}

Create the corresponding entity mapping:

public class VirtualPathConfig
    {
        public List VirtualPath { get; set; }
    }

    public class PathContent
    {
        public string RealPath { get; set; }

        public string RequestPath { get; set; }

        public string Alias { get; set; }
    }

InPhysicalFileProviderIt is easy to obtain by adding an alias

public class MyFileProvider : PhysicalFileProvider
    {
        public MyFileProvider(string root, string alias) : base(root)
        {
            this.Alias = alias;
        }

        public MyFileProvider(string root, Microsoft.Extensions.FileProviders.Physical.ExclusionFilters filters, string alias) : base(root, filters)
        {
            this.Alias = alias;
        }

        /// 
        ///Alias
        /// 
        public string Alias { get; set; }
    }

AdjustmentStartup.ConfigureServicesAndStartup.Configure :

public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();
            services.Configure(Configuration);

            var config = Configuration.Get().VirtualPath;
            config.ForEach(f => 
            {
                services.AddSingleton(new MyFileProvider(f.RealPath,f.Alias));
            });
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            var config = Configuration.Get().VirtualPath;
            config.ForEach(f =>
            {
                app.UseStaticFiles(new StaticFileOptions()
                {
                    FileProvider = new PhysicalFileProvider(f.RealPath),
                    RequestPath =f.RequestPath
                });
            });
             
            app.UseRouting();
            app.UseAuthorization();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }

Finally, adjust the call mode.

[HttpGet]
        public object GetFiles([FromServices] IEnumerable fileProviders)
        {
            var file = fileProviders.FirstOrDefault(x=>x.Alias=="first").GetFileInfo("mybook.txt");
            if (file.Exists)
            {
                return ReadTxtContent(file.PhysicalPath);
            }
            return 0;
        }

last

Abstract pass through of physical file systemPhysicalFileProviderThis oneFileProviderWith the help ofIFileProviderIn fact, it can be extended to realize the function of lightweight “cloud disk”, not just the function of IIS virtual directory. It’s done. No overtime tonight!


 This article is synchronized with the publication of DotNetGeek (ID:dotNetGeek) official account.