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并减少应用初始化时生成的实例类型数目。
ASP.NET Core File Providers的更多相关文章
- Asp.Net Core File的操作
FileOption 内置类(通过服务注入) 该操作类的功能是实现对文件的删除,修改查询功能,该类基本完成了对文件的操作,同样是用最简单的代码实现了文件操作功能.
- [ASP.NET Core] Static File Middleware
前言 本篇文章介绍ASP.NET Core里,用来处理静态档案的Middleware,为自己留个纪录也希望能帮助到有需要的开发人员. ASP.NET Core官网 结构 一个Web站台最基本的功能,就 ...
- 如何在ASP.NET Core中自定义Azure Storage File Provider
文章标题:如何在ASP.NET Core中自定义Azure Storage File Provider 作者:Lamond Lu 地址:https://www.cnblogs.com/lwqlun/p ...
- Asp.net core 学习笔记 ( IIS, static file 性能优化 )
更新 : 2019-02-06 最后还是把 rewrite 给替换掉了. 所以 rewrite url 也不依赖 iis 了咯. refer : https://docs.microsoft.com/ ...
- ASP.Net Core 2.2 InProcess托管的Bug:unable to open database file
最近把项目更新到了ASP.Net Core 2.2,发布之后发现在IIS下使用SQLite数据库不行了,报异常说不能打开数据库."unable to open database file&q ...
- [转]File uploads in ASP.NET Core
本文转自:https://docs.microsoft.com/en-us/aspnet/core/mvc/models/file-uploads By Steve Smith ASP.NET MVC ...
- File upload in ASP.NET Core web API
参考1:File upload in ASP.NET Core web API https://www.janaks.com.np/file-upload-asp-net-core-web-api/ ...
- ASP.Net Core 2.2使用SQLite数据库unable to open database file
原文:ASP.Net Core 2.2使用SQLite数据库unable to open database file 最近把项目更新到了ASP.Net Core 2.2,发布之后发现在IIS下使用SQ ...
- ASP.NET Core 1.0: 指定Static File中的文件作为default page
指定一个网站的default page是很容易的事情.譬如IIS Management中,可以通过default page来指定,而默认的index.html, index.htm之类,则早已经被设置 ...
随机推荐
- webapp应用--模拟电子书翻页效果
前言: 现在移动互联网发展火热,手机上网的用户越来越多,甚至大有超过pc访问的趋势.所以,用web程序做出仿原生效果的移动应用,也变得越来越流行了.这种程序也就是我们常说的单页应用程序,它也有一个英文 ...
- AJAX操作数据
本文使用AJAX访问数据库文件,并显示在网页中.另外还有AJAX对数据库的删除操作,网页不加载,只刷新数据. 随意使用数据库中的一张表: 使用AJAX显示表中内容,首先打入body代码: <h1 ...
- PHP之Memcache缓存详解
Mem:memory缩写(内存):内存缓存 1. 断电或者重启服务器内存数据即消失,即临时数据: Memcache默认端口:11211 存入方式:key=>>value ...
- 【iOS】Xcode8+Swift3 纯代码模式实现 UICollectionView
开发环境 macOS Sierra 10.12.Xcode 8.0,如下图所示: 总体思路 1.建立空白的storyboard用于呈现列表 2.实现自定义单个单元格(继承自:UICollectionV ...
- ASP.NET中画图形验证码
context.Response.ContentType = "image/jpeg"; //生成随机的中文验证码 string yzm = "人口手大小多少上中下男女天 ...
- 企业shell面试题:获取51CTO博客列表倒序排序考试题
#!/bin/sh PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin HTMLFILE=/home/oldboy/ht ...
- CYQ.Data V5 从入门到放弃ORM系列:教程 - MProc类使用
MProc介绍 MProc:是一个用于执行SQL或存储过程的数据库操作类,它轻量高性能地类似于Dapper. MProc:它出现的场景很少,因为MAction自身就能处理掉90%-100%的数据操作( ...
- 让ASP.NET5在Jexus上飞呀飞
就在最近一段时间,“Visual Studio 2015 CTP 5”(以下简称CTP5)发布了,CTP5的发布不仅标志着新一代的VisualStudio正式发布又向前迈出了一步,还标志着距离ASP. ...
- Linux3 在VMware中搭建CentOS6.5虚拟机
前言: 本文主要是我在大家hadoop集群之前 ,需啊先安装CentOS虚拟机,记录在此,作为参考.如果能帮助到其他人,自然是更好啦. =========================== ...
- 对于前端,「微信小程序」其实不美好
微信小程序开放公测了,9月底我曾经写过一篇 「微信小程序」来了,其中最后一句:"谢天谢地,我居然还是个前端". 这种火爆的新事物总是令人激动,感谢这个时代. 但是,当我真作为开发者 ...