土牛亲自录制的本文介绍视频
Abp中文网(https://cn.abp.io/)提供翻译字幕
基于ASP.NET Core的模块化设计: 虚拟文件系统
简介
创建模块化的应用程序很困难. 构建模块化的用户界面更加困难. 需要单独开发模块的页面和组件,但是最后要把它们集成在一起像单个UI一样
创建这样的模块化架构之前需要构建一个强大的基础设施,这就是我们在开源的ABP[1]项目中尝试做的事情
在本文中我会重点介绍虚拟文件系统,它是模块化基础设施的组要组成部分,并解释我们为什么需要它,以及如何在ASP.NET CORE的基础之上开发虚拟文件系统
本文的视频演示请看这里[2]
用户界面组件
典型的ASP.NET CORE MVC Web应用程序UI由静态和动态资源组成
静态资源包括JavaScript,css,image...等文件. 这些资源请求由Static Files中间件响应处理. 它们通常位于程序的wwwroot下
动态资源是Razor视图,页面和组件. 它们由Razor引擎处理,编译和呈现
静态和动态文件通常都位于物理文件系统中 (虽然最新的ASP.NET CORE有预编译选项,但要点是相同的)
模块化应用程序中的用户界面组件
在模块化应用程序中, UI组件分散到各个模块中, 通常嵌入到模块程序集中(DLL文件)中
静态文件中间件和Razor视图引擎无法处理分布在模块程序集之间的资源
虚拟文件系统
虚拟文件系统是一个适配器(包装器),使ASP.NET Core可以使用物理文件系统以外的资源
我们的虚拟文件系统实现可以使用三种类型的文件位置
•嵌入式文件: 位于DLL中的文件作为嵌入式资源. 这些资源在应用程序启动时注册到虚拟文件系统•物理文件: 位于web应用程序下的文件(静态资源的wwwroot文件夹,视图的根文件夹,页面..等). 它是向后兼容的•动态文件: 运行时生成的文件(例如动态js/css bundle文件)
动态文件可以覆盖物理文件, 物理文件可以覆盖嵌入文件(如果位于同一路径中). 通过这种方式应用程序可以覆盖模块的UI组件(如CSS文件,JS文件或视图)以便进行自定义
虚拟文件注册
模块应该在应用程序启动时向虚拟文件系统注册/添加自己的嵌入式资源.我们已经为此创建了VirtualFileSystemOptions. 用法示例:
context.Services.Configure<VirtualFileSystemOptions>(options =>
{
options
.FileSets
.AddEmbedded<MyModule>();
});
上方的代码将MyModule类的程序集中的所有嵌入资源添加到虚拟文件系统(VFS)中,当所有的模块都在VFS中注册后,我们就会在内存中的字典/集合中提供一个文件列表及其路径(嵌入式命名空间转换为路径)
IFileProvider接口
ASP.NET Core使用IFileProvider接口从文件系统中读取文件:
public interface IFileProvider
{
IFileInfo GetFileInfo(string subpath);
IDirectoryContents GetDirectoryContents(string subpath);
IChangeToken Watch(string filter);
}
•GetFileInfo方法从给定的路径读取文件信息和内容. 如果给定文件不存在,则返回NotFoundFileInfo•GetDirectoryContents方法用于获取目录中的文件和目录列表. 如果给定的目录不存在会返回NotFoundDirectoryContents (可以返回单例实例:NotFoundDirectoryContents.Singleton)•Watch方法用于在给定路径中文件或文件夹发生更改时收到通知. 过滤器可以包含通配符(如'*')
很显然我们应该实现这个接口从嵌入式/动态文件中返回文件,不过我不会在本文中分享实现部分,如果你想了解详细信息,请参阅我们的实现[3]和文档[4]
配置Razor视图引擎
当我们实现了虚拟文件系统,我们就可以配置RazorViewEngineOptions来添加新的自定义文件提供程序:
context.Services.Configure<RazorViewEngineOptions>(options =>
{
options.FileProviders.Insert(0, new MyVirtualFileProvider());
});
替换静态文件中间件
通常我们使用app.UseStaticFiles向浏览器提供物理文件,不过要使用虚拟文件系统,我们需要替换它. 这部分也很简单. 我们可以编写这个一个扩展方法:
public static void UseVirtualFiles(this IApplicationBuilder app)
{
app.UseStaticFiles(
new StaticFileOptions
{
FileProvider = new MyVirtualFileProvider()
}
);
}
MyVirtualFileProvider是我们示例的IFileProvider实现. 你可以将FileProvider设置为任何IFileProvider接口的实现类
最后我们使用UseVirtualFiles方法替换UseVirtualFiles:
app.UseVirtualFiles();
写在最后
我试图简单的描述为什么开发模块化的ASP.NET Core Mvc应用程序会需要虚拟文件系统以及如何实现它
我计划根据我的ABP框架[5]开发经验,在ASP.NET Core上发布更多模块化应用程序开发的文章
References
[1]
ABP: https://cn.abp.io[2]
这里: https://www.bilibili.com/video/av47031992?from=search&seid=6709357480596566187[3]
实现: https://github.com/abpframework/abp/tree/master/framework/src/Volo.Abp.VirtualFileSystem[4]
文档: https://cn.abp.io/documents/abp/latest/Virtual-File-System[5]
ABP框架: https://cn.abp.io/