Asp.Net Core 中的“虚拟目录”
写在前面
现在部署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空项目,这里物理路径在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 ;
} /// <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 ;
}
最后
物理文件系统的抽象通过 PhysicalFileProvider 这个 FileProvider 来实现,借助 IFileProvider 的特点,其实可以扩展实现轻量“云盘”的功能了,而不仅仅只是实现IIS虚拟目录功能。搞定,今晚不加班!
本文同步在DotNetGeek(ID:dotNetGeek)公众号发布
Asp.Net Core 中的“虚拟目录”的更多相关文章
- ASP.NET Core 中文文档目录
翻译计划 五月中旬 .NET Core RC2 如期发布,我们遂决定翻译 ASP.NET Core 文档.我们在 何镇汐先生. 悲梦先生. 张仁建先生和 雷欧纳德先生的群中发布了翻译计划招募信息,并召 ...
- ASP.NET Core中使用GraphQL - 最终章 Data Loader
ASP.NET Core中使用GraphQL - 目录 ASP.NET Core中使用GraphQL - 第一章 Hello World ASP.NET Core中使用GraphQL - 第二章 中间 ...
- ASP.NET Core中使用GraphQL - 第七章 Mutation
ASP.NET Core中使用GraphQL - 目录 ASP.NET Core中使用GraphQL - 第一章 Hello World ASP.NET Core中使用GraphQL - 第二章 中间 ...
- ASP.NET Core中使用GraphQL - 第八章 在GraphQL中处理一对多关系
ASP.NET Core中使用GraphQL - 目录 ASP.NET Core中使用GraphQL - 第一章 Hello World ASP.NET Core中使用GraphQL - 第二章 中间 ...
- Asp.Net Core 中获取应用程序物理路径(Getting the Web Root Path and the Content Root Path in ASP.NET Core)
如果要得到传统的ASP.Net应用程序中的相对路径或虚拟路径对应的服务器物理路径,只需要使用使用Server.MapPath()方法来取得Asp.Net根目录的物理路径,如下所示: // Classi ...
- ASP.NET Core 中的SEO优化(3):自定义路由匹配和生成
前言 前两篇文章主要总结了CMS系统两个技术点在ASP.NET Core中的应用: <ASP.NET Core 中的SEO优化(1):中间件实现服务端静态化缓存> <ASP.NET ...
- (5)ASP.NET Core 中的静态文件
1.前言 当我们创建Core项目的时候,Web根目录下会有个wwwroot文件目录,wwwroot文件目录里面默认有HTML.CSS.IMG.JavaScript等文件,而这些文件都是Core提供给客 ...
- 在ASP.NET Core中使用百度在线编辑器UEditor
在ASP.NET Core中使用百度在线编辑器UEditor 0x00 起因 最近需要一个在线编辑器,之前听人说过百度的UEditor不错,去官网下了一个.不过服务端只有ASP.NET版的,如果是为了 ...
- ASP.NET Core中的依赖注入(1):控制反转(IoC)
ASP.NET Core在启动以及后续针对每个请求的处理过程中的各个环节都需要相应的组件提供相应的服务,为了方便对这些组件进行定制,ASP.NET通过定义接口的方式对它们进行了"标准化&qu ...
随机推荐
- 3、尚硅谷_SSM高级整合_使用ajax操作实现增加员工的功能
20.尚硅谷_SSM高级整合_新增_创建员工新增的模态框.avi 1.接下来当我们点击增加按钮的时候会弹出一个员工信息的对话框 知识点1:当点击新增的时候会弹出一个bootstrap的一个模态对话框 ...
- 动态自动配置Bean
概览 接口Condition 用于基于条件的自动配置,和注解@Conditional配合使用,可实现JavaBean的动态自动配置 自定义实现动态配置Bean 定义一个接口和两个实现类 定义两个Con ...
- SQL注入之注入点的寻找
注入点的判断 判断一个链接是否存在注入漏洞,可以通过对其传入的参数(但不仅仅只限于参数,还有cookie注入,HTTP头注入等) 进行构造,然后对服务器返回的内容进行判断来查看是否存在注入点. 注入点 ...
- 暑假集训日记Day xx
Day 1 6.23 今天算是第一天吧 (毕竟昨天被迫做了半天苦力) 充实而丰满的一天:上午做题 下午讲题 晚上改错(考试是原题和我会做有什么关系吗) 早起跑操还阔以(比之前距离短就很快乐) 然后练了 ...
- Web安全之验证码绕过
一,验证码绕过(on client) 首先让burpsuite处于抓包状态,打开pikachu的验证码绕过(on client)随意输入账号和密码,验证码先不输入,点击login,会提示验证码错误 然 ...
- python实现简单的SVM
# -*- coding: utf-8 -*- from sklearn.svm import SVC import numpy as np print(X.shape,Y.shape) X = np ...
- Ubuntu18.04 IP配置问题
18.04 LTS 提供了通过 netplan.io 轻松配置网络连接 参考 Ubuntu18.04 发行release cn.ubuntu.com/server
- Redis系列(九):数据结构Hash之HDEL、HEXISTS、HGETALL、HKEYS、HLEN、HVALS命令
1.HDEL 从 key 指定的哈希集中移除指定的域.在哈希集中不存在的域将被忽略. 如果 key 指定的哈希集不存在,它将被认为是一个空的哈希集,该命令将返回0. 时间复杂度:O(N) N是被删除的 ...
- nginx location 知识知多少
写在之前 众所周知 nginx location 路由转发规则多种多样,尤其是 [ = | ~ | ~* | ^~ ] 这些前缀是什么意思.root 与 alias 是否可以区分开,nginx 作为反 ...
- 使用原生js来控制、修改CSS伪元素的方法总汇, 例如:before和:after
在网页中,如果需要使用辅助性/装饰性的内容的时候,我们不应该直接写在HTML中,这样会影响真正的内容,这就需要使用伪元素了,这是由于css的纯粹语义化是没有意义的.在使用伪元素的时候,会发现js并不真 ...