写在前面

现在部署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>/// 读取文本/// </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();});
}

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

最后

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

Asp.Net Core 中的“虚拟目录”相关推荐

  1. ASP.NET Core中使用GraphQL - 第七章 Mutation

    ASP.NET Core中使用GraphQL - 目录 ASP.NET Core中使用GraphQL - 第一章 Hello World ASP.NET Core中使用GraphQL - 第二章 中间 ...

  2. ASP.NET Core中使用GraphQL - 最终章 Data Loader

    ASP.NET Core中使用GraphQL - 目录 ASP.NET Core中使用GraphQL - 第一章 Hello World ASP.NET Core中使用GraphQL - 第二章 中间 ...

  3. ASP.NET Core 中的静态文件

    1.前言 当我们创建Core项目的时候,Web根目录下会有个wwwroot文件目录,wwwroot文件目录里面默认有HTML.CSS.IMG.JavaScript等文件,而这些文件都是Core提供给客 ...

  4. Asp.net Core中SignalR Core预览版的一些新特性前瞻,附源码(消息订阅与发送二进制数据)

    前言 一晃一个月又过去了,上个月有个比较大的项目要验收上线.所以忙的脚不沾地.现在终于可以忙里偷闲,写一篇关于SignalR Core的文章了. 先介绍一下SignalR吧,如下: ASP.NET S ...

  5. .ASP NET Core中缓存问题案例

    本篇博客中,我将描述一个关于会话状态(Session State)的问题, 这个问题我已经被询问了好几次了. 问题的场景 创建一个新的ASP.NET Core应用程序 一个用户在会话状态中设置了一个字 ...

  6. ASP.NET Core 中文文档 第三章 原理(13)管理应用程序状态

    原文:Managing Application State 作者:Steve Smith 翻译:姚阿勇(Dr.Yao) 校对:高嵩 在 ASP.NET Core 中,有多种途径可以对应用程序的状态进行 ...

  7. ASP.NET Core中的依赖注入(4): 构造函数的选择与服务生命周期管理

    ServiceProvider最终提供的服务实例都是根据对应的ServiceDescriptor创建的,对于一个具体的ServiceDescriptor对象来说,如果它的ImplementationI ...

  8. 在ASP.NET Core中创建自定义端点可视化图

    在上篇文章中,我为构建自定义端点可视化图奠定了基础,正如我在第一篇文章中展示的那样.该图显示了端点路由的不同部分:文字值,参数,动词约束和产生结果的端点: 在本文中,我将展示如何通过创建一个自定义的D ...

  9. 重学ASP.NET Core 中的标记帮助程序

    标记帮助程序是什么 标记帮助程序使服务器端代码可以在 Razor 文件中参与创建和呈现 HTML 元素. 例如,内置的 ImageTagHelper 可以将版本号追加到图片名称.  每当图片发生变化时 ...

最新文章

  1. 前缀函数及kmp算法
  2. 响应格式html,设置响应格式的HTML邮件
  3. Could not close the output stream for file hdfs://192.168.190.129:9000/BJ_4.c
  4. Java中的binarySearch方法
  5. 第五章 基元类型、引用类型、值类型 CLR学习第五课
  6. 论文浅尝 - ICML2020 | 对比图神经网络解释器
  7. 数学趣题——猴子吃桃问题
  8. MySQL显示连接的数据库名
  9. 【Tensorflow2】语义分割实战1---斑马线识别
  10. 【论文视频】对比学习论文综述【论文精读】
  11. nginx部署前端代码
  12. 卷积神经网络(CNN)实现手写体识别
  13. Windows重新分区,解决C盘无法扩展卷
  14. linux光盘游戏,Linux下五个好玩的即时战略游戏
  15. 使用跨端解决方案Rax编写鸿蒙应用
  16. 开机出现 A disk read error occurred Press 时怎么办
  17. 自己封装的Socket组件,实现服务端多进程共享Socket对象,协同处理客户端请求...
  18. Vue中的深坑——component和components
  19. 20221227英语学习
  20. 星际无限与约瑟企管战略合作 强势开启资本上市之路

热门文章

  1. 改变listview中item选中时文字的颜色
  2. 理解 Delphi 的类(七) - 认识类的多态
  3. google hdr+_更好的隐私权控制使Google+死了
  4. [AHOI2009]飞行棋 BZOJ1800
  5. python之新式类与经典类
  6. Maven发布工程到私服
  7. [ JS 进阶 ] Repaint 、Reflow 的基本认识和优化 (2)
  8. 配置Tomcat的日志系统
  9. 博客群发(2)--实现登陆
  10. 给定两个二叉树T和S,判断S是否为T的子树