如何在ASP.NET Core中自定义Azure Storage File Provider
文章标题:如何在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
接口
public class AzureFileProvider : IFileProvider
{
public IDirectoryContents GetDirectoryContents(string subpath)
{
throw new NotImplementedException();
}
public IFileInfo GetFileInfo(string subpath)
{
throw new NotImplementedException();
}
public IChangeToken Watch(string filter)
{
throw new NotImplementedException();
}
}
从以上代码中,我们可以了解到,IFileProvider
接口定义了3个需要实现方法
GetDirectoryContents
- 这个方法是用来获取指定目录下的内容的GetFileInfo
- 这个方法使用来获取指定文件内容的Watch
- 这个方法是用来监听文件变更的,这个暂时不需要实现它
实现GetDirectoryContents
方法
为了实现GetDirectoryContents
方法,我们需要首先创建一个IDirectoryContents
接口的实现类, 因为它是这个方法的返回类型。
我们创建一个类AzureStorageDirectoryContents
, 它实现了IDirectoryContents
接口。
public class AzureStorageDirectoryContents : IDirectoryContents
{
private List<IFileInfo> _listInfos;
public AzureStorageDirectoryContents(List<IFileInfo> listInfos)
{
_listInfos = listInfos;
}
public bool Exists
{
get
{
return true;
}
}
public IEnumerator<IFileInfo> GetEnumerator()
{
return _listInfos.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return _listInfos.GetEnumerator();
}
}
代码解释:
- 这里
IDirectoryContents
其实就是为了显示指定目录中的文件结构IFileInfo
接口对象既可以表示文件也可以表示子目录,这个接口的2个实现我会在后面说明- 这里我们通过构造函数,将指定文件夹内的文件结构注入到了
AzureStorageDirectoryContents
雷中。
下面我们就可以来添加GetDirectoryContents
方法的实现了
private AzureStorageSetting _setting = null;
public AzureFileProvider(AzureStorageSetting setting)
{
_setting = setting;
}
public IDirectoryContents GetDirectoryContents(string subpath)
{
var rootDirectory = GetRootDirectory();
var folderName = subpath.Substring(1);
CloudFileDirectory folder = null;
if (string.IsNullOrWhiteSpace(folderName))
{
folder = rootDirectory;
}
else
{
folder = rootDirectory.GetDirectoryReference(folderName);
}
var files = new List<IFileInfo>();
foreach (var item in folder
.ListFilesAndDirectoriesSegmentedAsync(new FileContinuationToken())
.Result
.Results)
{
if (item is CloudFile)
{
var file = item as CloudFile;
files.Add(new AzureFileInfo(file));
}
else if (item is CloudFileDirectory)
{
var directory = item as CloudFileDirectory;
files.Add(new AzureDirectoryInfo(directory));
}
}
return new AzureStorageDirectoryContents(files);
}
private CloudFileDirectory GetRootDirectory()
{
var shareName = _setting.ShareName;
var storageAccount = CloudStorageAccount.Parse(_setting.ConnectionString);
var fileClient = storageAccount.CreateCloudFileClient();
var share = fileClient.GetShareReference(shareName);
var rootDir = share.GetRootDirectoryReference();
return rootDir;
}
代码解释:
- 这里我们通过构造函数为
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
public class AzureFileInfo : IFileInfo
{
private CloudFile _file = null;
private MemoryStream _stream = new MemoryStream();
public AzureFileInfo(CloudFile file)
{
_file = file;
_file.DownloadRangeToStreamAsync(_stream, null, null).Wait();
_stream.Position = 0;
}
public bool Exists
{
get
{
return true;
}
}
public long Length
{
get
{
return _stream.Length;
}
}
public string PhysicalPath
{
get
{
return _file.Uri.AbsolutePath;
}
}
public string Name
{
get
{
return _file.Name;
}
}
public DateTimeOffset LastModified
{
get
{
return _file.Properties.LastModified.GetValueOrDefault();
}
}
public bool IsDirectory
{
get
{
return false;
}
}
public Stream CreateReadStream()
{
return _stream;
}
}
代码解释
- 这里我们通过
AzureFileInfo
的构造函数传入了一个CloudFile
对象, 这个对象将作为Name
,PhysicalPath
,LastModified
等属性的数据源。- 我们使用
CloudFile
对象DownloadRangeToStreamAsync
, 将其对应的文件流下载。注意这里加载文件流之后,需要将文件流的Position置0(即流的头部)- 文件的长度即文件流的长度
- 强制设置
IsDirectory
属性为false, 因为当前处理的是文件
AzureDirectoryInfo
public class AzureDirectoryInfo : IFileInfo
{
private CloudFileDirectory _directory = null;
public AzureDirectoryInfo(CloudFileDirectory directory)
{
_directory = directory;
}
public bool Exists
{
get
{
return true;
}
}
public long Length => throw new NotImplementedException();
public string PhysicalPath
{
get
{
return _directory.Uri.AbsolutePath;
}
}
public string Name
{
get
{
return _directory.Name;
}
}
public DateTimeOffset LastModified
{
get
{
return _directory.Properties.LastModified.GetValueOrDefault();
}
}
public bool IsDirectory
{
get
{
return true;
}
}
public Stream CreateReadStream()
{
throw new NotImplementedException();
}
}
代码解释
- 这里我们通过
AzureDirectoryInfo
的构造函数传入了一个CloudFileDirectory
对象, 这个对象将作为Name
,PhysicalPath
,LastModified
等属性的数据源。- 强制设置
IsDirectory
属性为true, 因为当前处理的是目录- 这里我们没有实现
Length
属性和CreateReadStream
, 因为我们处理的是目录, 这2个属性没有必要实现。
实现GetFileInfo
方法
相对于GetDirectoryContents
方法的实现,GetFileInfo
方法就简单多了,我们只需要根据当前指定的subpath, 将文件信息返回即可。
public IFileInfo GetFileInfo(string subpath)
{
var rootDirectory = GetRootDirectory();
var file = rootDirectory
.GetFileReference(subpath.Substring(1));
return new AzureFileInfo(file);
}
如何启用AzureFileProvider
下面我们来试验一下我们编写的AzureFileProvider是否能运行成功。
首先我们创建一个默认ASP.NET Core Api项目,并引用上一步中编译好的程序集AzureFileProvider.dll。
appSettings.json中, 我们需要定义Azure Files Storage的配置
例:
{
"Logging": {
"LogLevel": {
"Default": "Warning"
}
},
"AzureStorage": {
"ConnectionString": "DefaultEndpointsProtocol=https;AccountName=fdsffsdf;AccountKey=fdsfsdfs;EndpointSuffix=core.windows.net",
"ShareName": "testShare"
}
}
第二步,我们需要修改Startup.cs
文件的Configure
方法。
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
AzureStorageSetting o = new AzureStorageSetting();
Configuration.Bind("AzureStorage", o);
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new AzureFileProvider(o),
RequestPath = "/files"
});
app.UseDirectoryBrowser(new DirectoryBrowserOptions
{
FileProvider = new AzureFileProvider(o),
RequestPath = "/files"
});
app.UseMvc();
}
代码解释
- 这里我们使用强类型配置绑定,获取了appSettings.json中的Azure Files Storage的配置
- 在配置静态文件中间件部分,我们通过
StaticFileOptions
配置对象,指定了当前应用使用AzureFileProvider。- 为了演示效果,我这里也启用了DirectoryBrowser中间件,即可以使用网页查看目录结构。这个功能比较危险,在正式项目很少使用。所以正式使用时,最好将这段代码删掉。
最终效果
现在我们启动当前项目, 访问"/files", 即可查看到当前指定Azure Files Storage中的所有文件和目录
项目源代码
https://github.com/lamondlu/AzureFileProvider
Nuget程序集
以上类库,我已经发布到了Nuget上, 如果你不想每次都把前面的代码写一遍,可以直接安装这个程序集来使用。
Install-Package LamondLu.AzureFileProvider
如何在ASP.NET Core中自定义Azure Storage File Provider的更多相关文章
- 如何在ASP.NET Core中使用Azure Service Bus Queue
原文:USING AZURE SERVICE BUS QUEUES WITH ASP.NET CORE SERVICES 作者:damienbod 译文:如何在ASP.NET Core中使用Azure ...
- 如何在ASP.NET Core中实现CORS跨域
注:下载本文的完整代码示例请访问 > How to enable CORS(Cross-origin resource sharing) in ASP.NET Core 如何在ASP.NET C ...
- 如何在ASP.NET Core中实现一个基础的身份认证
注:本文提到的代码示例下载地址> How to achieve a basic authorization in ASP.NET Core 如何在ASP.NET Core中实现一个基础的身份认证 ...
- 如何在ASP.NET Core中应用Entity Framework
注:本文提到的代码示例下载地址> How to using Entity Framework DB first in ASP.NET Core 如何在ASP.NET Core中应用Entity ...
- [转]如何在ASP.NET Core中实现一个基础的身份认证
本文转自:http://www.cnblogs.com/onecodeonescript/p/6015512.html 注:本文提到的代码示例下载地址> How to achieve a bas ...
- 如何在ASP.NET Core中使用JSON Patch
原文: JSON Patch With ASP.NET Core 作者:.NET Core Tutorials 译文:如何在ASP.NET Core中使用JSON Patch 地址:https://w ...
- [翻译] 如何在 ASP.Net Core 中使用 Consul 来存储配置
[翻译] 如何在 ASP.Net Core 中使用 Consul 来存储配置 原文: USING CONSUL FOR STORING THE CONFIGURATION IN ASP.NET COR ...
- [译]如何在ASP.NET Core中实现面向切面编程(AOP)
原文地址:ASPECT ORIENTED PROGRAMMING USING PROXIES IN ASP.NET CORE 原文作者:ZANID HAYTAM 译文地址:如何在ASP.NET Cor ...
- 如何在 ASP.Net Core 中使用 Serilog
记录日志的一个作用就是方便对应用程序进行跟踪和排错调查,在实际应用上都是引入 日志框架,但如果你的 日志文件 包含非结构化的数据,那么查询起来将是一个噩梦,所以需要在记录日志的时候采用结构化方式. 将 ...
随机推荐
- 利用VMWare 11 在 Windows 8.1 下安装与优化 OS X 10.10
此文中相关工具点击我从百度网盘下载 一.安装 第一步安装参考百度经验:点击这里,鉴于其中提供的文件全部不能用,替换成了上面的,亲测Intel Core I5 4200M 可用. 二.优化 这里给出一些 ...
- 115个Java面试题和答案——终极列表(上)【转】
本文我们将要讨论Java面试中的各种不同类型的面试题,它们可以让雇主测试应聘者的Java和通用的面向对象编程的能力.下面的章节分为上下两篇,第一篇将要讨论面向对象编程和它的特点,关于Java和它的功能 ...
- vue组件的生命周期
先来张组件生命周期的示意图: 文档里是这样描述的:你不需要立马弄明白所有的东西,不过以后它会有帮助.传送门. Vue2.0的生命周期钩子一共有10个,同样结合官方文档作出了下表 生命周期钩子 详细 b ...
- SVN 使用方法
svn co http://路径(目录或文件的全路径) [本地目录全路径] --username 用户名 --password 密码svn co svn://路径(目录或文件的全路径) [本地目录全路 ...
- shell 常用命令语法简介
一.grep用法 ************************************** ++++++用一些特殊的函数来处理参数++++++ *$# 传递给函数的参数个数 *$* 显示所有传递给 ...
- Re:从零开始的领域驱动设计
领域驱动的火爆程度不用我赘述,但是即便其如此得耳熟能详,但大多数人对其的认识,还只是停留在知道它的缩写是DDD,知道它是一种软件思想,或者知道它和微服务有千丝万缕的关系.Eric Evans对DDD的 ...
- Ubuntu16.04下安装Chrome出现“未安装软件包 libappindicator1”问题的解决办法
1. 强制安装chrome sudo dpkg -i google-chrome-stable_current_i386.deb --force 2. 补齐依赖 sudo apt-get instal ...
- Python configparser 读取指定节点内容失败
# !/user/bin/python # -*- coding: utf-8 -*- import configparser # 生成一个config文件 config = configparser ...
- Linux.安装phantomjs
PhantomJS 是一个基于 WebKit 的服务器端 JavaScript API.它全面支持web而不需浏览器支持,其快速,原生支持各种Web标准: DOM 处理, CSS 选择器, JSON, ...
- ApplicationContextAware 接口的作用
接口说明:当一个类实现了这个接口之后,这个类就可以方便地获得 ApplicationContext 中的所有bean.换句话说,就是这个类可以直接获取Spring配置文件中,所有有引用到的bean对象 ...