6. 对象存储
什么是对象存储
在工作中,我们经常需要将文件内容(文件或二进制流)存储在应用程序中,例如你可能要保存商品的封面图片。Masa框架为此提供了对象存储的功能,并对功能抽象,抽象给我们带来的好处:
- 存储的无关性(不关心存储平台时阿里云OSS还是腾讯云的COS)
- 更换存储平台成本更低(仅需要更改下存储的提供者,业务侵染低)
- 支持自定义存储提供者(仅需要自行实现
IClient
)
- 阿里云: 在阿里云OSS存储服务上存储
如何制作自定义存储程序?快速入门 Masa.BuildingBlocks.Storage.ObjectStorage是对象存储服务的抽象包,你可以在项目中使用它来进行编写代码,最后在
Program.cs
中选择一个存储提供程序使用即可- 安装.Net 6.0
- 新建ASP.NET Core 空项目
Assignment.OSS
,并安装Masa.Contrib.Storage.ObjectStorage.Aliyun
dotnet new web -o Assignment.OSS cd Assignment.OSS dotnet add package Masa.Contrib.Storage.ObjectStorage.Aliyun --version 0.5.0-preview.2
- 修改
Program.cs
builder.Services.AddAliyunStorage(); #region 或者通过代码指定传入阿里云存储配置信息使用,无需使用配置文件 // builder.Services.AddAliyunStorage(new AliyunStorageOptions() // { //AccessKeyId = "Replace-With-Your-AccessKeyId", //AccessKeySecret = "Replace-With-Your-AccessKeySecret", //Endpoint = "Replace-With-Your-Endpoint", //RoleArn = "Replace-With-Your-RoleArn", //RoleSessionName = "Replace-With-Your-RoleSessionName", //Sts = new AliyunStsOptions() //{ //RegionId = "Replace-With-Your-Sts-RegionId", //DurationSeconds = 3600, //EarlyExpires = 10 //} // }, "storage1-test"); #endregion
- 修改
appsettings.json
,增加阿里云配置
{ "Aliyun": { "AccessKeyId": "Replace-With-Your-AccessKeyId", "AccessKeySecret": "Replace-With-Your-AccessKeySecret", "Sts": { "RegionId": "Replace-With-Your-Sts-RegionId", "DurationSeconds": 3600, "EarlyExpires": 10 }, "Storage": { "Endpoint": "Replace-With-Your-Endpoint", "RoleArn": "Replace-With-Your-RoleArn", "RoleSessionName": "Replace-With-Your-RoleSessionName", "TemporaryCredentialsCacheKey": "Aliyun.Storage.TemporaryCredentials", "Policy": "", "BucketNames" : { "DefaultBucketName" : "storage1-test"//默认BucketName,非必填项,仅在使用IClientContainer时需要指定 } } } }
- 新增上传文件服务
app.MapPost("/upload", async (HttpRequest request, IClient client) => { var form = await request.ReadFormAsync(); var formFile = form.Files["file"]; if (formFile == null) throw new FileNotFoundException("Can't upload empty file"); await client.PutObjectAsync("storage1-test", formFile.FileName, formFile.OpenReadStream()); });
IClient
是用来存储和读取对象的主要接口,可以在项目的任意地方通过DI获取到IClient
来上传、下载或删除指定BucketName
下的对象,也可用于判断对象是否存在,获取临时凭证等。- 上传对象
app.MapPost("/upload", async (HttpRequest request, IClient client) => { var form = await request.ReadFormAsync(); var formFile = form.Files["file"]; if (formFile == null) throw new FileNotFoundException("Can't upload empty file"); await client.PutObjectAsync("storage1-test", formFile.FileName, formFile.OpenReadStream()); });
Form表单提交,key为file,类型为文件上传
- 删除对象
public class DeleteRequest { public string Key { get; set; } }app.MapDelete("/delete", async (IClient client, [FromBody] DeleteRequest request) => { await client.DeleteObjectAsync("storage1-test", request.Key); });
- 判断对象是否存在
app.MapGet("/exist", async (IClient client, string key) => { await client.ObjectExistsAsync("storage1-test", key); });
- 返回对象数据的流
app.MapGet("/download", async (IClient client, string key, string path) => { await client.GetObjectAsync("storage1-test", key, stream => { //下载文件到指定路径 using var requestStream = stream; byte[] buf = new byte[1024]; var fs = File.Open(path, FileMode.OpenOrCreate); int len; while ((len = requestStream.Read(buf, 0, 1024)) != 0) { fs.Write(buf, 0, len); } fs.Close(); }); });
- 获取临时凭证(STS)
app.MapGet("/GetSts", (IClient client) => { client.GetSecurityToken(); });
阿里云、腾讯云存储等平台使用STS来获取临时凭证
- 获取临时凭证(字符串类型的临时凭证)
app.MapGet("/GetToken", (IClient client) => { client.GetToken(); });
七牛云等存储平台使用较多
IBucketNameProvider
是用来获取BucketName的接口,通过IBucketNameProvider
可以获取指定存储空间的BucketName,为IClientContainer
提供BucketName能力,在业务项目中不会使用到IClientContainer
IClientContainer
对象存储容器,用来存储和读取对象的主要接口,一个应用程序下可能会存在管理多个BucketName,通过使用IClientContainer
,像管理DbContext
一样管理不同Bucket
的对象,不需要在项目中频繁指定BucketName
,在同一个应用程序中,有且只有一个默认ClientContainer,可以通过DI获取IClientContainer
来使用,例如:- 上传对象(上传到默认
Bucket
)
app.MapPost("/upload", async (HttpRequest request, IClientContainer clientContainer) => { var form = await request.ReadFormAsync(); var formFile = form.Files["file"]; if (formFile == null) throw new FileNotFoundException("Can't upload empty file"); await clientContainer.PutObjectAsync(formFile.FileName, formFile.OpenReadStream()); });
- 上传到指定
Bucket
[BucketName("picture")] public class PictureContainer {}builder.Services.Configure(option => { option.BucketNames = new BucketNames(new List
() { new("DefaultBucketName", "storage1-test"),//默认BucketName new("picture", "storage1-picture")//指定别名为picture的BucketName为storage1-picture }); }); app.MapPost("/upload", async (HttpRequest request, IClientContainer clientContainer) => { var form = await request.ReadFormAsync(); var formFile = form.Files["file"]; if (formFile == null) throw new FileNotFoundException("Can't upload empty file"); await clientContainer.PutObjectAsync(formFile.FileName, formFile.OpenReadStream()); });
IClientFactory
对象存储提供者工厂,通过指定BucketName
,创建指定的IClientContainer创建对象存储提供程序 以适配腾讯云存储为例:
- 新建类库
Masa.Contrib.Storage.ObjectStorage.Tencent
- 选中
Masa.Contrib.Storage.ObjectStorage.Tencent
并新建类DefaultStorageClient
,并实现IClient
- 由于腾讯云存储提供Sts临时凭证,所以仅需要实现
GetSecurityToken
方法即可,GetToken
方法可抛出不支持的异常,并在文档说明即可 - 新建类
ServiceCollectionExtensions
,并提供对IServiceCollection
的扩展方法AddTencentStorage
,例如:
public static IServiceCollection AddTencentStorage( this IServiceCollection services, TencentStorageOptions options, string? defaultBucketName = null) { //todo: 添加腾讯云存储的客户端 if (defaultBucketName != null) { services.Configure(option => { option.BucketNames = new BucketNames(new List
() { new(BucketNames.DEFAULT_BUCKET_NAME, defaultBucketName) }); }); services.TryAddSingleton (serviceProvider => new DefaultClientContainer(serviceProvider.GetRequiredService (), defaultBucketName)); } services.TryAddSingleton (); services.TryAddSingleton (); services.TryAddSingleton (); return services; }
Bucket
中本章源码 Assignment06
https://github.com/zhenlei520...
开源地址 MASA.BuildingBlocks:https://github.com/masastack/...
MASA.Contrib:https://github.com/masastack/...
MASA.Utils:https://github.com/masastack/...
MASA.EShop:https://github.com/masalabs/M...
MASA.Blazor:https://github.com/BlazorComp...
如果你对我们的 MASA Framework 感兴趣,无论是代码贡献、使用、提 Issue,欢迎联系我们
【6. 对象存储】
推荐阅读
- 什么是hpaPaaS平台(低代码和hpaPaaS是什么关系?)
- 知识管理技术是什么(有用吗?)
- 技术分享 | MySQL(max_allowed_packet 影响了什么())
- 什么是“企业级”低代码(成为企业级低代码必须具备的5种能力)
- 生得一副好皮囊
- 阿里云有奖体验(块存储快速入门)
- 数据资产管理(数据到底有没有价值,有什么价值())
- (译文)我是女权主义者,我也做过整容。这为什么是个问题()
- CSS3|什么是BFC,BFC的使用
- 为什么要用无聊的小事来消耗彼此的感情和精力