又拍云 REST API 的 C# 异步客户端,支持文件上传、下载、复制、移动、删除,目录创建与列表查询,以及空间用量查询。
本项目由 AI 开发。
- .NET 6.0
- .NET Standard 2.0
如果已发布到 NuGet,可以通过包管理器安装:
dotnet add package Upyun如果使用源码开发,可以直接引用项目:
dotnet add reference ./Upyun/Upyun.csprojusing Upyun;
using var client = new UpyunClient(
bucket: "your-bucket",
operatorName: "your-operator",
password: "your-password");
await client.UploadFileAsync(
path: "/images/hello.txt",
content: System.Text.Encoding.UTF8.GetBytes("hello upyun"),
contentType: "text/plain");
byte[] fileBytes = await client.DownloadFileAsync("/images/hello.txt");bucket 为又拍云服务名称,operatorName 和 password 为服务操作员名称与密码。默认接入点为 https://v0.api.upyun.com,如需自定义可以在构造函数中传入 endpoint。
在 ASP.NET Core 等长期运行的应用中,建议复用 HttpClient:
using System.Net.Http;
using Upyun;
HttpClient httpClient = new HttpClient();
var client = new UpyunClient(
bucket: "your-bucket",
operatorName: "your-operator",
password: "your-password",
httpClient: httpClient);通过该构造函数传入的 HttpClient 不会被 UpyunClient.Dispose() 释放,生命周期由调用方管理。
可以通过 IHttpClientFactory 管理 HttpClient 生命周期,并把 UpyunClient 注册为服务:
using Upyun;
builder.Services.AddHttpClient<UpyunClient>((serviceProvider, httpClient) =>
{
IConfiguration configuration = serviceProvider.GetRequiredService<IConfiguration>();
return new UpyunClient(
bucket: configuration["Upyun:Bucket"],
operatorName: configuration["Upyun:OperatorName"],
password: configuration["Upyun:Password"],
httpClient: httpClient);
});配置示例:
{
"Upyun": {
"Bucket": "your-bucket",
"OperatorName": "your-operator",
"Password": "your-password"
}
}之后即可通过依赖注入使用:
public sealed class FileService
{
private readonly UpyunClient _client;
public FileService(UpyunClient client)
{
_client = client;
}
public Task UploadAsync(byte[] content)
{
return _client.UploadFileAsync("/docs/readme.txt", content, "text/plain");
}
}上传本地文件:
await client.UploadFileAsync(
path: "/backup/logo.png",
localFilePath: "./Logo.png",
contentType: "image/png");上传字节数组并附加文件元信息:
await client.UploadFileAsync(
path: "/docs/readme.txt",
content: System.Text.Encoding.UTF8.GetBytes("hello"),
contentType: "text/plain",
metadata: new Dictionary<string, string>
{
{ "source", "sdk" }
},
ttl: 30);metadata 中的键名会自动添加 x-upyun-meta- 前缀;ttl 请通过单独参数传入,不要放在 metadata 中。ttl 单位为天,最大支持 180 天。
上传流:
using FileStream stream = File.OpenRead("./video.mp4");
await client.UploadFileAsync(
path: "/videos/video.mp4",
content: stream,
contentLength: stream.Length,
contentType: "video/mp4");当流不可定位时,必须显式传入 contentLength。
下载到字节数组:
byte[] content = await client.DownloadFileAsync("/docs/readme.txt");下载到指定流:
using FileStream output = File.Create("./readme.txt");
await client.DownloadFileAsync("/docs/readme.txt", output);await client.CopyFileAsync(
sourcePath: "/docs/readme.txt",
destinationPath: "/docs/readme-copy.txt");
await client.MoveFileAsync(
sourcePath: "/docs/readme-copy.txt",
destinationPath: "/docs/readme-moved.txt");
await client.DeleteFileAsync("/docs/readme-moved.txt");创建目录:
await client.CreateDirectoryAsync("/docs");删除空目录:
await client.DeleteDirectoryAsync("/docs/empty-folder");又拍云只允许删除空目录,非空目录需要先删除里面的文件或子目录。
获取文件或目录信息:
using Upyun.Models;
UpyunFileSystem info = await client.GetFileInfoAsync("/docs/readme.txt");
if (info is UpyunFile file)
{
Console.WriteLine(file.Type);
Console.WriteLine(file.Length);
Console.WriteLine(file.LastModifiedTime);
Console.WriteLine(file.ContentMd5);
}
else if (info is UpyunDirectory directory)
{
Console.WriteLine(directory.Name);
Console.WriteLine(directory.LastModifiedTime);
}分页列出目录:
using Upyun.Models;
string iter = null;
bool isEnd;
do
{
UpyunDirectoryList list = await client.GetDirectoryListAsync(
path: "/docs",
iter: iter,
limit: 100,
order: UpyunListOrder.Asc);
foreach (UpyunFileSystem item in list.Files)
{
if (item is UpyunDirectory directory)
{
Console.WriteLine($"DIR\t{directory.LastModifiedTime:O}\t{directory.Name}");
}
else if (item is UpyunFile file)
{
Console.WriteLine($"FILE\t{file.Type}\t{file.Length}\t{file.LastModifiedTime:O}\t{file.Name}");
}
}
iter = list.Iter;
isEnd = list.IsEnd;
}
while (!isEnd);long usageBytes = await client.GetUsageAsync();
Console.WriteLine($"Usage: {usageBytes} bytes");当又拍云返回非成功状态码,或响应内容无法解析时,SDK 会抛出 UpyunException:
try
{
await client.DownloadFileAsync("/not-found.txt");
}
catch (UpyunException exception)
{
Console.WriteLine(exception.StatusCode);
Console.WriteLine(exception.ResponseContent);
}测试项目会访问真实又拍云服务。运行前需要为 Upyun.Test 配置 User Secrets:
dotnet user-secrets set "Bucket" "your-bucket" --project ./Upyun.Test
dotnet user-secrets set "OperatorName" "your-operator" --project ./Upyun.Test
dotnet user-secrets set "Password" "your-password" --project ./Upyun.Test
dotnet test测试会在服务中创建 /upyun-sdk-tests 下的临时目录和文件,并在测试结束时清理。