原文地址:FileProvider

By Steve Smith

ASP.NET Core通过对File Providers的使用实现了对文件系统访问的抽象。

查看或下载示例代码

File Provider 抽象

File Providers是文件系统之上的一层抽象。它的主要接口是IFileProviderIFileProvider公开了相应方法用来获取文件信息(IFileInfo), 目录信息(IDirectoryContents),以及设置更改通知(通过使用一个IChangeToken)。

IFileInfo接口提供了操作单个文件和目录的方法和属性。它有两个boolean属性,ExistsIsDirectory,以及两个描述文件的两个属性NameLength(按字节),还包括一个LastModified日期属性。你还可以通过CreateReadStream方法读取文件内容。

File Provider 实现

有三种对于IFileProvider的实现可供选择:物理式,嵌入式和复合式。物理式用于访问实际系统中的文件。嵌入式用于访问嵌入在程序集中的文件。 复合式则是对前两种方式的组合使用。

PhysicalFileProvider

PhysicalFileProvider提供了对物理文件系统的访问。它封装了System.IO.File类型,范围限定到一个目录及其子目录的所有路径。这类作用域会限制访问某个目录及其子目录,防止作用域以外的其他操作访问文件系统。当实例化此类provider时,你必须为它提供一个目录路径,以供服务器拿来当做由这个provider发出的所有请求的基础路径(这个provider会限制路径以外的访问请求)。在一个ASP.NET Core应用,你可以直接实例化出一个PhysicalFileProvider provider,或者你也可以通过在控制器和服务中使用构造函数依赖注入的方式,请求一个IFileProvider接口。后者生成的解决方案通常更灵活以及更便于测试。

要创建一个PhysicalFileProvider其实很简单,只需要对其实化,再传递给它一个物理路径。之后你就可以通过它的目录遍历内容或提供子路径获取特定文件的信息。

  1. IFileProvider provider = new PhysicalFileProvider(applicationRoot);
  2. IDirectoryContents contents = provider.GetDirectoryContents(""); // the applicationRoot contents
  3. IFileInfo fileInfo = provider.GetFileInfo("wwwroot/js/site.js"); // a file under applicationRoot

为了在控制器中请求一个provider,需要在控制器的构造函数中指定类型参数并赋值给本地属性。之后你就可以在你的动作器方法中使用本地实例了。

  1. public class HomeController : Controller
  2. {
  3. private readonly IFileProvider _fileProvider;
  4. public HomeController(IFileProvider fileProvider)
  5. {
  6. _fileProvider = fileProvider;
  7. }
  8. public IActionResult Index()
  9. {
  10. var contents = _fileProvider.GetDirectoryContents("");
  11. return View(contents);
  12. }
  13. }

在应用的Startup类中创建provider的代码如下:

  1. using System.Linq;
  2. using System.Reflection;
  3. using Microsoft.AspNetCore.Builder;
  4. using Microsoft.AspNetCore.Hosting;
  5. using Microsoft.Extensions.Configuration;
  6. using Microsoft.Extensions.DependencyInjection;
  7. using Microsoft.Extensions.FileProviders;
  8. using Microsoft.Extensions.Logging;
  9. namespace FileProviderSample
  10. {
  11. public class Startup
  12. {
  13. private IHostingEnvironment _hostingEnvironment;
  14. public Startup(IHostingEnvironment env)
  15. {
  16. var builder = new ConfigurationBuilder()
  17. .SetBasePath(env.ContentRootPath)
  18. .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
  19. .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
  20. .AddEnvironmentVariables();
  21. Configuration = builder.Build();
  22. _hostingEnvironment = env;
  23. }
  24. public IConfigurationRoot Configuration { get; }
  25. // This method gets called by the runtime. Use this method to add services to the container.
  26. public void ConfigureServices(IServiceCollection services)
  27. {
  28. // Add framework services.
  29. services.AddMvc();
  30. var physicalProvider = _hostingEnvironment.ContentRootFileProvider;
  31. var embeddedProvider = new EmbeddedFileProvider(Assembly.GetEntryAssembly());
  32. var compositeProvider = new CompositeFileProvider(physicalProvider, embeddedProvider);
  33. // choose one provider to use for the app and register it
  34. //services.AddSingleton<IFileProvider>(physicalProvider);
  35. //services.AddSingleton<IFileProvider>(embeddedProvider);
  36. services.AddSingleton<IFileProvider>(compositeProvider);
  37. }
  38. }
  39. }

Index.chhtml 视图中,可以遍历操作IDirectoryContents模型参数

  1. @using Microsoft.Extensions.FileProviders
  2. @model IDirectoryContents
  3. <h2>Folder Contents</h2>
  4. <ul>
  5. @foreach (IFileInfo item in Model)
  6. {
  7. if (item.IsDirectory)
  8. {
  9. <li><strong>@item.Name</strong></li>
  10. }
  11. else
  12. {
  13. <li>@item.Name - @item.Length bytes</li>
  14. }
  15. }
  16. </ul>

结果如下:

EmbeddedFileProvider

EmbeddedFileProvider用于访问嵌入到程序集中的文件。在.NET Core中,你可以通过修改 project.json 文件的buildOptions属性参数来把文件嵌入到程序集中。

  1. "buildOptions": {
  2. "emitEntryPoint": true,
  3. "preserveCompilationContext": true,
  4. "embed": [
  5. "Resource.txt",
  6. "**/*.js"
  7. ]
  8. }

当你把文件嵌入到程序集中时,你可以使用通配符模式。这些模式可以被用来匹配一个或多个文件。

Note

把项目中所有的.js文件都嵌入到项目程序集里的情况是不太可能发生的,以上示例仅作为demo给出。

当创建一个EmbeddedFileProvider时,请在其构造函数中传入一个程序集实例供其读取。

  1. var embeddedProvider = new EmbeddedFileProvider(Assembly.GetEntryAssembly());

以上的代码片段描述了如何创建一个能访问当前工作程序集的EmbeddedFileProvider类型变量。

使用EmbeddedFileProvider更新示例项目代码后的输出结果如下:

Note

如上图所示,嵌入式资源不会公开目录。相反的,资源路径(经由资源的命名空间)会被嵌入到它的文件名中并以.作为分隔符。

Tip

EmbeddedFileProvider构造器接受一个可选的baseNamespace参数,指定此参数将限定GetDirectoryContents方法调用该命名空间下的资源。

CompositeFileProvider

CompositeFileProvider联合IFileProvider实例公开了一个单一的接口,用以和来自多种provider的文件工作。当创建一个CompositeFileProvider时,你可以为它的构造函数传入一个或多个IFileProvider实例。

  1. var physicalProvider = _hostingEnvironment.ContentRootFileProvider;
  2. var embeddedProvider = new EmbeddedFileProvider(Assembly.GetEntryAssembly());
  3. var compositeProvider = new CompositeFileProvider(physicalProvider, embeddedProvider);

使用包含物理式provider(在前)和嵌入式provider的CompositeFileProvider更新示例项目代码后的输出结果如下:

查看更改

IFileProviderWatch方法能用来查看一个或多个文件/目录的更改信息。Watch方法接受一个路径字符串,它也可以使用通配符模式来指定多个文件,Watch方法最终返回一个IChangeToken。这个token公开了一个HasChanged属性用以检视状态,公开了一个RegisterChangeCallback方法,此方法会在指定的路径字符串检测到更改时被调用。请注意每个更改token只调用其关联回调以响应单次更改。为了使监控持续,你可以使用如下所示的TaskCompletionSource方法,或者重建IChangeToken以响应更改。

在这个文章的示例中,无论何时当文本文件内容发生修改,按如下代码配置的console应用都会显示相应的信息。

  1. using System;
  2. using System.IO;
  3. using System.Threading.Tasks;
  4. using Microsoft.Extensions.FileProviders;
  5. using Microsoft.Extensions.Primitives;
  6. namespace WatchConsole
  7. {
  8. public class Program
  9. {
  10. private static PhysicalFileProvider _fileProvider =
  11. new PhysicalFileProvider(Directory.GetCurrentDirectory());
  12. public static void Main(string[] args)
  13. {
  14. Console.WriteLine("Monitoring quotes.txt for changes (ctrl-c to quit)...");
  15. while (true)
  16. {
  17. MainAsync().GetAwaiter().GetResult();
  18. }
  19. }
  20. private static async Task MainAsync()
  21. {
  22. IChangeToken token = _fileProvider.Watch("quotes.txt");
  23. var tcs = new TaskCompletionSource<object>();
  24. token.RegisterChangeCallback(state =>
  25. ((TaskCompletionSource<object>)state).TrySetResult(null), tcs);
  26. await tcs.Task.ConfigureAwait(false);
  27. Console.WriteLine("quotes.txt changed");
  28. }
  29. }
  30. }

以下是执行过几次文本保存动作后的运行结果截图:

Note

有一些文件系统,例如Docker容器和网络共享,可能不能很可靠地发送更改通知。设置环境变量DOTNET_USE_POLLINGFILEWATCHER的值为1true,使得每四秒轮询一次文件系统的变更。

通配符模式

文件系统路径规则使用叫作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功能。IHostingEnvironmentIFileProvider接口类型公开了应用的目录根和Web根。静态文件中间件使用file provider来定位静态文件。Razor更是大量使用IFileProvider来定位视图。Dotnet的发布功能使用file provider和通配符模式来指定需要跟随发布的文件。

在应用程序中使用的建议

如果你的ASP.NET Core应用需要访问文件系统,你可以通过依赖注入创建IFileProvider接口实例,然后再通过前文所示的相应方法执行访问。当应用启动的时候,这些方法允许你一次性配置provider并减少应用初始化时生成的实例类型数目。

ASP.NET Core File Providers的更多相关文章

  1. Asp.Net Core File的操作

    FileOption 内置类(通过服务注入) 该操作类的功能是实现对文件的删除,修改查询功能,该类基本完成了对文件的操作,同样是用最简单的代码实现了文件操作功能.

  2. [ASP.NET Core] Static File Middleware

    前言 本篇文章介绍ASP.NET Core里,用来处理静态档案的Middleware,为自己留个纪录也希望能帮助到有需要的开发人员. ASP.NET Core官网 结构 一个Web站台最基本的功能,就 ...

  3. 如何在ASP.NET Core中自定义Azure Storage File Provider

    文章标题:如何在ASP.NET Core中自定义Azure Storage File Provider 作者:Lamond Lu 地址:https://www.cnblogs.com/lwqlun/p ...

  4. Asp.net core 学习笔记 ( IIS, static file 性能优化 )

    更新 : 2019-02-06 最后还是把 rewrite 给替换掉了. 所以 rewrite url 也不依赖 iis 了咯. refer : https://docs.microsoft.com/ ...

  5. 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 ...

  6. [转]File uploads in ASP.NET Core

    本文转自:https://docs.microsoft.com/en-us/aspnet/core/mvc/models/file-uploads By Steve Smith ASP.NET MVC ...

  7. 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/ ...

  8. 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 ...

  9. ASP.NET Core 1.0: 指定Static File中的文件作为default page

    指定一个网站的default page是很容易的事情.譬如IIS Management中,可以通过default page来指定,而默认的index.html, index.htm之类,则早已经被设置 ...

随机推荐

  1. 玩转spring boot——开篇

    很久没写博客了,而这一转眼就是7年.这段时间并不是我没学习东西,而是园友们的技术提高的非常快,这反而让我不知道该写些什么.我做程序已经有十几年之久了,可以说是彻彻底底的“程序老炮”,至于技术怎么样?我 ...

  2. Spring的数据库开发

                                Spring JDBC框架操作mysql数据库 Spring中的JDBC为我们省去连接和关闭数据库的代码,我们着重关注对数据库的操作.Sprin ...

  3. EC笔记:第4部分:21、必须返回对象时,别返回引用

    使用应用可以大幅减少构造函数与析构函数的调用次数,但是引用不可以滥用. 如下: struct St { int a; }; St &func(){ St t; return t; } 在返回t ...

  4. angularjs 1 开发简单案例(包含common.js,service.js,controller.js,page)

    common.js var app = angular.module('app', ['ngFileUpload']) .factory('SV_Common', function ($http) { ...

  5. Ognl表达式基本原理和使用方法

    Ognl表达式基本原理和使用方法 1.Ognl表达式语言 1.1.概述 OGNL表达式 OGNL是Object Graphic Navigation Language(对象图导航语言)的缩写,他是一个 ...

  6. Xamarin.Android之SQLiteOpenHelper

    一.前言 在手机中进行网络连接不仅是耗时也是耗电的,而耗电却是致命的.所以我们就需要数据库帮助我们存储离线数据,以便在用户未使用网络的情况下也可以能够使用应用的部分功能,而在需要网络连接的功能上采用提 ...

  7. CentOs7 +Jexus 5.8.2部署Asp.Net Core WebApi 1.0生产环境

    Jexus 是一款运行于 Linux 平台,以支持  ASP.NET.PHP 为特色的集高安全性和高性能为一体的 WEB 服务器和反向代理服务器.最新版 5.8.2 已经发布,有如下更新: 1,现在大 ...

  8. 介绍一位OWin服务器新成员TinyFox

    TinyFox 是一款支持OWIN标准的WEB应用的高性能的HTTP服务器,是Jexus Web Server的"姊妹篇".TinyFox本身的功能是html服务器,所有的WEB应 ...

  9. js中几种实用的跨域方法原理详解(转)

    今天研究js跨域问题的时候发现一篇好博,非常详细地讲解了js几种跨域方法的原理,特分享一下. 原博地址:http://www.cnblogs.com/2050/p/3191744.html 下面正文开 ...

  10. React 其实比 MVVM 架构更加卡顿

    React 号称通过引入 Virtual DOM 带来了性能的提升,而其实 React 之所以需要 Virtual DOM,是因为它的架构下,state 的变更是全量的,然后触发 render 返回全 ...