写在前面

  现在部署asp.net core应用已经不再限制于windows的iis上,更多的是docker容器、各种反向代理来部署。也有少部分用iis部署的,iis部署确实是又快又简单,图形化操作三下五除二就可以发布好一个系统了。在过去asp.net mvc 项目部署的时候,还常常使用iis一个功能——虚拟目录。

虚拟目录可以直接定位到非项目的其他路径,将路径作为网站的一部分,可实现上传文件保存到其他盘符或间接的使用项目以外的静态文件。在asp.net mvc中从虚拟路径中存取文件也很简单,如server.mappath(“~/upload/liohuang.jpg”);

但在asp.net core上不同,它被抽象出一个“文件系统”,也就是fileprovider。fileprovider是对所有实现了ifileprovider接口的所有类型以及对应对象的统称,在artech蒋老师的《.net core的文件系统[2]:fileprovider是个什么东西?》文章中已经透析了,这里不在罗里吧嗦了。

这篇文章要解决的内容是:asp.net core应用中,如何优雅的使用“虚拟目录”。

实操

  首先,新建一个.net core webapi空项目部署在d盘,“虚拟目录”假设物理路径在f盘,分别创建三个测试目录:f:/test1、f:/test2和f:/test3,目录里分别存放对应的文件1/2/3.jpg和mybook.txt。

读取虚拟目录文件

  在startup.configureservices注入ifileprovider:

services.addsingleton<ifileprovider>(new physicalfileprovider("f:\\test1"));

新建一个控制器,读取mybook.txt中的内容:

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

  /// <summary>
  /// 读取文本 (原文地址:https://www.cnblogs.com/eminemjk/p/13362368.html)
  /// </summary>
  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();
   }
  }
 }

访问接口,接口读取文件之后,返回内容:

ifileprovider接口采用目录来组织文件,并统一使用ifileinfo接口来表示,physicalpath表示文件的物理路径。

public interface ifileinfo
 {
  bool exists { get; }
  bool isdirectory { get; }
  datetimeoffset lastmodified { get; }
  string name { get; }
  string physicalpath { get; }
  stream createreadstream();
 }

如多个虚拟目录,怎么处理?简单,注入多个ifileprovider即可,

 services.addsingleton<ifileprovider>(new physicalfileprovider("f:\\test1"));
   services.addsingleton<ifileprovider>(new physicalfileprovider("f:\\test2"));
   services.addsingleton<ifileprovider>(new physicalfileprovider("f:\\test3")); 

代码修改为:

  public object getfiles([fromservices] ienumerable<ifileprovider> fileproviders)

ienumerable<ifileprovider> fileproviders接口数组将会有三个,按注入的顺序对应不同的目录。当然,注入ifileprovider的时候,就可以封装一层了,下面再讲。

另外,有的说直接readtxtcontent(“f:\test1\mybook.txt”);不香吗?香,asp.net core的访问权限要比asp.net mvc之前老版本项目要高许多,确实是可以直接读取项目以外的文件,但是并不适合直接去访问,除非说你只有一个地方使用到,那么就可以直接读取,但静态的文件的访问,就访问不到了,仅仅是后台读取而已。所以统一使用ifileprovider来约束,代码的可维护性要高许多。

静态文件访问

  在startup.configure设置静态文件目录,即可:

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

fileprovider同上面所说的,设置好物理路径的根目录,requestpath则是访问路径的前缀,必须是斜杆“/”开头,访问地址前缀则为:https://localhost:5001/test/。设置好之后,就可以访问项目以外的路径了。

如在iis部署的时候 ,可以直接忽略iis中的虚拟目录设置,完完全全可以通过注入的配置来设置达到“虚拟目录”的效果。

简化配置

  为了方便达到真实项目中可以直接使用,那么就要设置为可配置的:

在appsettings.json中设置:

{
 "logging": {
 "loglevel": {
  "default": "information",
  "microsoft": "warning",
  "microsoft.hosting.lifetime": "information"
 }
 },
 "allowedhosts": "*",

 "virtualpath": [
 {
  "realpath": "f:\\test1", //真实路径
  "requestpath": "/test",
  "alias": "first"
 },
 {
  "realpath": "f:\\test2", //真实路径
  "requestpath": "/test",
  "alias": "second"
 },
 {
  "realpath": "f:\\test3", //真实路径
  "requestpath": "/test",
  "alias": "third"
 }
 ]
}

创建对应的实体映射:

public class virtualpathconfig
 {
  public list<pathcontent> virtualpath { get; set; }
 }

 public class pathcontent
 {
  public string realpath { get; set; }

  public string requestpath { get; set; }

  public string alias { get; set; }
 }

在physicalfileprovider上封装一层,加入别名便于获取:

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

    /// <summary>
    /// 别名
    /// </summary>
    public string alias { get; set; }
  }

调整startup.configureservices和startup.configure:

public void configureservices(iservicecollection services)
    {
      services.addcontrollers();
      services.configure<virtualpathconfig>(configuration);

      var config = configuration.get<virtualpathconfig>().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<virtualpathconfig>().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();
      });
    }

最后,调整调用方式,即可。

[httpget]
    public object getfiles([fromservices] ienumerable<myfileprovider> fileproviders)
    {
      var file = fileproviders.firstordefault(x=>x.alias=="first").getfileinfo("mybook.txt");
      if (file.exists)
      {
        return readtxtcontent(file.physicalpath);
      }
      return 0;
    }

最后

  物理文件系统的抽象通过physicalfileprovider这个fileprovider来实现,借助ifileprovider的特点,其实可以扩展实现轻量“云盘”的功能了,而不仅仅只是实现iis虚拟目录功能。搞定,今晚不加班!

到此这篇关于asp.net core 中的“虚拟目录”实现的文章就介绍到这了,更多相关asp.net core 虚拟目录内容请搜索www.887551.com以前的文章或继续浏览下面的相关文章希望大家以后多多支持www.887551.com!