ASP.NET Core File Providers
By Steve Smith
ASP.NET Core通过对File Providers的使用实现了对文件系统访问的抽象。
File Provider 抽象
File Providers是文件系统之上的一层抽象。它的主要接口是IFileProvider
。IFileProvider
公开了相应方法用来获取文件信息(IFileInfo
), 目录信息(IDirectoryContents
),以及设置更改通知(通过使用一个IChangeToken
)。
IFileInfo
接口提供了操作单个文件和目录的方法和属性。它有两个boolean
属性,Exists
和IsDirectory
,以及两个描述文件的两个属性Name
和Length
(按字节),还包括一个LastModified
日期属性。你还可以通过CreateReadStream
方法读取文件内容。
File Provider 实现
有三种对于IFileProvider
的实现可供选择:物理式,嵌入式和复合式。物理式用于访问实际系统中的文件。嵌入式用于访问嵌入在程序集中的文件。 复合式则是对前两种方式的组合使用。
PhysicalFileProvider
PhysicalFileProvider
提供了对物理文件系统的访问。它封装了System.IO.File
类型,范围限定到一个目录及其子目录的所有路径。这类作用域会限制访问某个目录及其子目录,防止作用域以外的其他操作访问文件系统。当实例化此类provider时,你必须为它提供一个目录路径,以供服务器拿来当做由这个provider发出的所有请求的基础路径(这个provider会限制路径以外的访问请求)。在一个ASP.NET Core应用,你可以直接实例化出一个PhysicalFileProvider
provider,或者你也可以通过在控制器和服务中使用构造函数依赖注入的方式,请求一个IFileProvider
接口。后者生成的解决方案通常更灵活以及更便于测试。
要创建一个PhysicalFileProvider
其实很简单,只需要对其实化,再传递给它一个物理路径。之后你就可以通过它的目录遍历内容或提供子路径获取特定文件的信息。
IFileProvider provider = new PhysicalFileProvider(applicationRoot);
IDirectoryContents contents = provider.GetDirectoryContents(""); // the applicationRoot contents
IFileInfo fileInfo = provider.GetFileInfo("wwwroot/js/site.js"); // a file under applicationRoot
为了在控制器中请求一个provider,需要在控制器的构造函数中指定类型参数并赋值给本地属性。之后你就可以在你的动作器方法中使用本地实例了。
public class HomeController : Controller
{
private readonly IFileProvider _fileProvider;
public HomeController(IFileProvider fileProvider)
{
_fileProvider = fileProvider;
}
public IActionResult Index()
{
var contents = _fileProvider.GetDirectoryContents("");
return View(contents);
}
}
在应用的Startup
类中创建provider的代码如下:
using System.Linq;
using System.Reflection;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Logging;
namespace FileProviderSample
{
public class Startup
{
private IHostingEnvironment _hostingEnvironment;
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
_hostingEnvironment = env;
}
public IConfigurationRoot Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc();
var physicalProvider = _hostingEnvironment.ContentRootFileProvider;
var embeddedProvider = new EmbeddedFileProvider(Assembly.GetEntryAssembly());
var compositeProvider = new CompositeFileProvider(physicalProvider, embeddedProvider);
// choose one provider to use for the app and register it
//services.AddSingleton<IFileProvider>(physicalProvider);
//services.AddSingleton<IFileProvider>(embeddedProvider);
services.AddSingleton<IFileProvider>(compositeProvider);
}
}
}
在 Index.chhtml 视图中,可以遍历操作IDirectoryContents
模型参数
@using Microsoft.Extensions.FileProviders
@model IDirectoryContents
<h2>Folder Contents</h2>
<ul>
@foreach (IFileInfo item in Model)
{
if (item.IsDirectory)
{
<li><strong>@item.Name</strong></li>
}
else
{
<li>@item.Name - @item.Length bytes</li>
}
}
</ul>
结果如下:
EmbeddedFileProvider
EmbeddedFileProvider
用于访问嵌入到程序集中的文件。在.NET Core中,你可以通过修改 project.json 文件的buildOptions
属性参数来把文件嵌入到程序集中。
"buildOptions": {
"emitEntryPoint": true,
"preserveCompilationContext": true,
"embed": [
"Resource.txt",
"**/*.js"
]
}
当你把文件嵌入到程序集中时,你可以使用通配符模式。这些模式可以被用来匹配一个或多个文件。
Note 把项目中所有的.js文件都嵌入到项目程序集里的情况是不太可能发生的,以上示例仅作为demo给出。
当创建一个EmbeddedFileProvider
时,请在其构造函数中传入一个程序集实例供其读取。
var embeddedProvider = new EmbeddedFileProvider(Assembly.GetEntryAssembly());
以上的代码片段描述了如何创建一个能访问当前工作程序集的EmbeddedFileProvider
类型变量。
使用EmbeddedFileProvider
更新示例项目代码后的输出结果如下:
Note 如上图所示,嵌入式资源不会公开目录。相反的,资源路径(经由资源的命名空间)会被嵌入到它的文件名中并以
.
作为分隔符。Tip
EmbeddedFileProvider
构造器接受一个可选的baseNamespace
参数,指定此参数将限定GetDirectoryContents
方法调用该命名空间下的资源。
CompositeFileProvider
CompositeFileProvider
联合IFileProvider
实例公开了一个单一的接口,用以和来自多种provider的文件工作。当创建一个CompositeFileProvider
时,你可以为它的构造函数传入一个或多个IFileProvider
实例。
var physicalProvider = _hostingEnvironment.ContentRootFileProvider;
var embeddedProvider = new EmbeddedFileProvider(Assembly.GetEntryAssembly());
var compositeProvider = new CompositeFileProvider(physicalProvider, embeddedProvider);
使用包含物理式provider(在前)和嵌入式provider的CompositeFileProvider
更新示例项目代码后的输出结果如下:
查看更改
IFileProvider
的Watch
方法能用来查看一个或多个文件/目录的更改信息。Watch
方法接受一个路径字符串,它也可以使用通配符模式来指定多个文件,Watch
方法最终返回一个IChangeToken
。这个token公开了一个HasChanged
属性用以检视状态,公开了一个RegisterChangeCallback
方法,此方法会在指定的路径字符串检测到更改时被调用。请注意每个更改token只调用其关联回调以响应单次更改。为了使监控持续,你可以使用如下所示的TaskCompletionSource
方法,或者重建IChangeToken
以响应更改。
在这个文章的示例中,无论何时当文本文件内容发生修改,按如下代码配置的console应用都会显示相应的信息。
using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Primitives;
namespace WatchConsole
{
public class Program
{
private static PhysicalFileProvider _fileProvider =
new PhysicalFileProvider(Directory.GetCurrentDirectory());
public static void Main(string[] args)
{
Console.WriteLine("Monitoring quotes.txt for changes (ctrl-c to quit)...");
while (true)
{
MainAsync().GetAwaiter().GetResult();
}
}
private static async Task MainAsync()
{
IChangeToken token = _fileProvider.Watch("quotes.txt");
var tcs = new TaskCompletionSource<object>();
token.RegisterChangeCallback(state =>
((TaskCompletionSource<object>)state).TrySetResult(null), tcs);
await tcs.Task.ConfigureAwait(false);
Console.WriteLine("quotes.txt changed");
}
}
}
以下是执行过几次文本保存动作后的运行结果截图:
Note 有一些文件系统,例如Docker容器和网络共享,可能不能很可靠地发送更改通知。设置环境变量
DOTNET_USE_POLLINGFILEWATCHER
的值为1
或true
,使得每四秒轮询一次文件系统的变更。
通配符模式
文件系统路径规则使用叫作globbing patterns的通配符模式,这类简单模式可以被用来指定文件组。这两个通配符分别是*
和**
。
*
*
表示在当前文件夹级别上匹配任何文件名称或文件扩展名。匹配以文件路径字符串中的/
和.
符号结尾。
**
**
表示在多个目录级别上匹配任何文件名称或文件扩展名。可用于在一个目录层次结构中递归地匹配多个文件。
通配符模式示例
directory/file.txt
在指定的文件夹中匹配指定的文件。
directory/*.txt
在指定的文件夹中匹配所有以.txt
扩展名结尾的文件。
directory/*/project.json
在指定的directory
文件夹下的一级目录位置中匹配所有符合project.json
名称的文件
directory/**/*.txt
在指定的directory
文件夹下的所有位置中匹配所有以.txt
扩展名结尾的文件。
在ASP.NET Core中File Provider的用法
ASP.NET Core有几个组件使用file provider功能。IHostingEnvironment
以IFileProvider
接口类型公开了应用的目录根和Web根。静态文件中间件使用file provider来定位静态文件。Razor更是大量使用IFileProvider
来定位视图。Dotnet的发布功能使用file provider和通配符模式来指定需要跟随发布的文件。
在应用程序中使用的建议
如果你的ASP.NET Core应用需要访问文件系统,你可以通过依赖注入创建IFileProvider
接口实例,然后再通过前文所示的相应方法执行访问。当应用启动的时候,这些方法允许你一次性配置provider并减少应用初始化时生成的实例类型数目。
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- R语言如何解决线性混合模型中畸形拟合(Singular fit)的问题
- Android如何在Gradle中更改APK文件名详解
- 面试中常见的 C 语言与 C++ 区别的问题
- Linux系统实现ansible自动化安装配置httpd的方法
- 常用Linux发行版镜像源配置小结
- Linux如何处理文件已删除但空间不释放的问题
- 解析linux或android添加文件系统的属性接口的方法
- linux查看软件的安装位置简单方法
- 使用 bind 设置 DNS 服务器的方法
- Linux jdk安装及环境变量配置教程(jdk-8u144-linux-x64.tar.gz)
- centos6.6 下 安装 php7 + nginx环境的方法
- 如何优雅地删除 Linux 中的垃圾文件的方法
- Ubuntu18.04 安装 Anaconda3的教程详解
- VScode Remote SSH通过远程编辑与调试代码
- Ubuntu18.04下安装配置SSH服务的方法步骤