主题:如何在ASP.NET Core中自定义Azure Storage File Provider
作者: Lamond Lu
地址: https://www.cnblogs.com/lwqlun/p/10406566.html
项目源代码: https://github.com/lamondlu/AzureFileProvider

背景
ASP.NET Core是一个扩展性非常高的框架,开发人员可以根据自己的需求扩展出想要的功能。File Provider是ASP.NET Core中的一个重要组件,通过这个组件,开发人员可以暴露一组文件,并允许应用程序像访问静态文件一样访问暴露的文件。
ASP.NET Core中内置了3种File Provider
- PhysicalFileProvider- 用来访问和应用程序部署在一起的静态文件
- ManifestEmbeddedFileProvider- 用来访问程序集中的内嵌文件
- CompositeFileProvider- 将多个File Provider合并使用
那么如何自定义一个File Provider呢?比如如何将Azure Files Storage中的文件暴露给ASP.NET Core应用程序。今天我们来演示一下,如果通过实现IFileProvider 接口来实现一个Azure Files Storage Provider。
本文中只针对Azure Files Storage, Azure Blob Storage的实现可以参见Filip w的博文
创建.NET Core Library项目
首先我们使用Visual Studio 2017,创建一个Class Library项目, 命名为AzureFileProvider

为了使用IFileProvider接口和Azure Storage服务,这里我们需要使用Nuget引入2个库
- Microsoft.AspNetCore.App 
- WindowsAzure.Storage 
创建AzureFileProvider
为了创建一个ASP.NET Core支持的File Provider, 我们就需要自己创建一个类,并让它实现IFileProvider接口。
这里首先我们创建一个类AzureFileProvider, 它实现了IFileProvider接口

从以上代码中,我们可以了解到,IFileProvider接口定义了3个需要实现方法
- GetDirectoryContents- 这个方法是用来获取指定目录下的内容的
- GetFileInfo- 这个方法使用来获取指定文件内容的
- Watch- 这个方法是用来监听文件变更的,这个暂时不需要实现它
实现GetDirectoryContents方法
为了实现GetDirectoryContents方法,我们需要首先创建一个IDirectoryContents接口的实现类, 因为它是这个方法的返回类型。
我们创建一个类AzureStorageDirectoryContents, 它实现了IDirectoryContents接口。

代码解释:
这里
IDirectoryContents其实就是为了显示指定目录中的文件结构
IFileInfo接口对象既可以表示文件也可以表示子目录,这个接口的2个实现我会在后面说明
这里我们通过构造函数,将指定文件夹内的文件结构注入到了
AzureStorageDirectoryContents雷中。
下面我们就可以来添加GetDirectoryContents方法的实现了。

代码解释:
这里我们通过构造函数为
AzureFileProvider类注入了一个Azure Files Storage强类型配置类AzureStorageSetting, 它的数据源是appSettings.json, 后续我们会通过强类型配置将其注入
GetRootDirectory方法是通过Azure Files Storage配置,获得Azure Files Storage中文件集合的根目录
GetDirectoryContents中subpath.Substring(1)代码的作用是去除subpath带的第一个“/”。如果不去除,会读取不到文件
这里我们使用了
ListFilesAndDirectoriesSegmentedAsync方法获取了指定目录中所有的文件和目录
如果是文件,我们会实例化一个
AzureFileInfo对象,如果是一个目录,我们会实例化一个AzureDirectoryInfo对象
最终我们将读取到的所有文件和目录信息通过
AzureStorageDirectoryContents类的构造函数注入。
创建AzureFileInfo和AzureDirectoryInfo
为了区分文件和目录,我们创建2个新类AzureFileInfo和AzureDirectoryInfo。 他们都实现了IFileInfo接口。
AzureFileInfo

代码解释
这里我们通过
AzureFileInfo的构造函数传入了一个CloudFile对象, 这个对象将作为Name,PhysicalPath,LastModified等属性的数据源。
我们使用
CloudFile对象DownloadRangeToStreamAsync, 将其对应的文件流下载。注意这里加载文件流之后,需要将文件流的Position置0(即流的头部)
文件的长度即文件流的长度
强制设置
IsDirectory属性为false, 因为当前处理的是文件
AzureDirectoryInfo

代码解释
这里我们通过
AzureDirectoryInfo的构造函数传入了一个CloudFileDirectory对象, 这个对象将作为Name,PhysicalPath,LastModified等属性的数据源。
强制设置
IsDirectory属性为true, 因为当前处理的是目录
这里我们没有实现
Length属性和CreateReadStream, 因为我们处理的是目录, 这2个属性没有必要实现。
实现GetFileInfo方法
相对于GetDirectoryContents方法的实现,GetFileInfo方法就简单多了,我们只需要根据当前指定的subpath, 将文件信息返回即可。

如何启用AzureFileProvider
下面我们来试验一下我们编写的AzureFileProvider是否能运行成功。
首先我们创建一个默认ASP.NET Core Api项目,并引用上一步中编译好的程序集AzureFileProvider.dll。
appSettings.json中, 我们需要定义Azure Files Storage的配置
例:

第二步,我们需要修改Startup.cs文件的Configure方法。

代码解释
这里我们使用强类型配置绑定,获取了appSettings.json中的Azure Files Storage的配置
在配置静态文件中间件部分,我们通过
StaticFileOptions配置对象,指定了当前应用使用AzureFileProvider。
为了演示效果,我这里也启用了DirectoryBrowser中间件,即可以使用网页查看目录结构。这个功能比较危险,在正式项目很少使用。所以正式使用时,最好将这段代码删掉。
最终效果
现在我们启动当前项目, 访问"/files", 即可查看到当前指定Azure Files Storage中的所有文件和目录

项目源代码
https://github.com/lamondlu/AzureFileProvider
Nuget程序集
以上类库,我已经发布到了Nuget上, 如果你不想每次都把前面的代码写一遍,可以直接安装这个程序集来使用。
Install-Package LamondLu.AzureFileProvider