对象存储 - 磊_磊
source link: https://www.cnblogs.com/zhenlei520/p/16470089.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
什么是对象存储
在工作中,我们经常需要将文件内容(文件或二进制流)存储在应用程序中,例如你可能要保存商品的封面图片。Masa框架为此提供了对象存储的功能,并对功能抽象,抽象给我们带来的好处:
- 存储的无关性(不关心存储平台时阿里云OSS还是腾讯云的COS)
- 更换存储平台成本更低(仅需要更改下存储的提供者,业务侵染低)
- 支持自定义存储提供者(仅需要自行实现
IClient
)
对象存储提供程序
- 阿里云: 在阿里云OSS存储服务上存储
目前仅支持阿里云存储,后续将逐步提供更多的云存储平台支持,如果您有喜欢的其它云存储平台,欢迎提建议,或者自己实现它并为Masa框架做出贡献
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
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(); });
-
获取临时凭证(字符串类型的临时凭证)
app.MapGet("/GetToken", (IClient client) => { client.GetToken(); });
七牛云等存储平台使用较多
IBucketNameProvider
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<StorageOptions>(option => { option.BucketNames = new BucketNames(new List<KeyValuePair<string, string>>() { new("DefaultBucketName", "storage1-test"),//默认BucketName new("picture", "storage1-picture")//指定别名为picture的BucketName为storage1-picture }); }); app.MapPost("/upload", async (HttpRequest request, IClientContainer<PictureContainer> 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
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<StorageOptions>(option => { option.BucketNames = new BucketNames(new List<KeyValuePair<string, string>>() { new(BucketNames.DEFAULT_BUCKET_NAME, defaultBucketName) }); }); services.TryAddSingleton<IClientContainer>(serviceProvider => new DefaultClientContainer(serviceProvider.GetRequiredService<IClient>(), defaultBucketName)); } services.TryAddSingleton<IClientFactory, DefaultClientFactory>(); services.TryAddSingleton<ICredentialProvider, DefaultCredentialProvider>(); services.TryAddSingleton<IClient, DefaultStorageClient>(); return services; }
目前对象存储暂时并未支持多租户、多环境,后续根据情况逐步完善增加多租户、多环境支持,以适配不同的租户、不同的环境下的对象存储到指定的Bucket
中
Assignment06
https://github.com/zhenlei520/MasaFramework.Practice
MASA.BuildingBlocks:https://github.com/masastack/MASA.BuildingBlocks
MASA.Contrib:https://github.com/masastack/MASA.Contrib
MASA.Utils:https://github.com/masastack/MASA.Utils
MASA.EShop:https://github.com/masalabs/MASA.EShop
MASA.Blazor:https://github.com/BlazorComponent/MASA.Blazor
如果你对我们的 MASA Framework 感兴趣,无论是代码贡献、使用、提 Issue,欢迎联系我们
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK