Skip to content
Bitzsoft.Integrationsbitzsoft.integrations

Concept

CloudDrive 云盘

云盘域完整手册——ICloudDriveProvider 五区 18 方法、文件树/搜索/共享权限/版本管理、6 家云盘厂商与 NotSupportedException 能力差异。

Last updated

CloudDrive 域把企业网盘和个人云盘的文件操作能力收拢到一个接口背后。6 家厂商(阿里云盘、百度网盘、坚果云、Microsoft365 OneDrive、够快云库、爱数 AnyShare)共享同一个 ICloudDriveProvider,涵盖文件读写、文件夹管理、搜索、共享权限和版本管理五个区域。

域结构

Bitzsoft.Integrations.CloudDrive ← 抽象层
├── Bitzsoft.Integrations.CloudDrive.Aliyun ← 阿里云盘与相册(PDS)
├── Bitzsoft.Integrations.CloudDrive.Baidu ← 百度网盘
├── Bitzsoft.Integrations.CloudDrive.Nutstore ← 坚果云
├── Bitzsoft.Integrations.CloudDrive.Microsoft365 ← OneDrive(Microsoft Graph)
├── Bitzsoft.Integrations.CloudDrive.Gokuai ← 够快云库
├── Bitzsoft.Integrations.CloudDrive.AnyShare ← 爱数 AnyShare
└── Bitzsoft.Integrations.CloudDrive.All ← 聚合包

标准三层。

统一接口(18 方法,五区)

ICloudDriveProvider 按操作类型分成五个区域,共约 18 个方法:

public interface ICloudDriveProvider
{
string ProviderName { get; }
// ① 文件操作(6)
Task<UploadFileResult> UploadAsync(UploadFileRequest request, CancellationToken ct = default);
Task<Stream> DownloadAsync(string fileId, CancellationToken ct = default);
Task DeleteFileAsync(string fileId, CancellationToken ct = default);
Task<DriveFileInfo> MoveFileAsync(string fileId, string targetFolderId, string? newName = null, CancellationToken ct = default);
Task<DriveFileInfo> CopyFileAsync(string fileId, string targetFolderId, string? newName = null, CancellationToken ct = default);
Task<DriveFileInfo> GetFileInfoAsync(string fileId, CancellationToken ct = default);
// ② 文件夹操作(3)
Task<ListFilesResult> ListFilesAsync(string folderId, int pageIndex = 1, int pageSize = 50, CancellationToken ct = default);
Task<DriveFileInfo> CreateFolderAsync(CreateFolderRequest request, CancellationToken ct = default);
Task DeleteFolderAsync(string folderId, CancellationToken ct = default);
// ③ 搜索(1)
Task<ListFilesResult> SearchAsync(SearchFilesRequest request, CancellationToken ct = default);
// ④ 共享与权限(5)
Task<DriveShareLink> CreateShareLinkAsync(CreateShareLinkRequest request, CancellationToken ct = default);
Task DeleteShareLinkAsync(string fileId, string linkId, CancellationToken ct = default);
Task<IReadOnlyList<DrivePermission>> GetPermissionsAsync(string fileId, CancellationToken ct = default);
Task<DrivePermission> SetPermissionAsync(string fileId, DrivePermission permission, CancellationToken ct = default);
Task DeletePermissionAsync(string fileId, string permissionId, CancellationToken ct = default);
// ⑤ 版本管理(3)
Task<IReadOnlyList<DriveFileVersion>> ListVersionsAsync(string fileId, CancellationToken ct = default);
Task<Stream> DownloadVersionAsync(string fileId, string versionId, CancellationToken ct = default);
Task<DriveFileInfo> RestoreVersionAsync(string fileId, string versionId, CancellationToken ct = default);
}

接口的 XML 文档明确说明:受限于供应商 API 能力,部分操作可能抛 NotSupportedException,调用方应在使用前确认供应商支持所需操作。

错误处理:无 Result 包装

CloudDrive 域没有 Result 包装——接口直接返回模型对象,失败时抛 CloudDriveException

public sealed class CloudDriveException : IntegrationException
{
public string ProviderName => Provider ?? string.Empty;
public new string? ErrorCode => base.ErrorCode;
public new string? ProviderMessage => base.ProviderMessage;
public CloudDriveException(string providerName, string message,
string? errorCode = null, string? providerMessage = null, Exception? innerException = null)
: base(domain: "CloudDrive",
message: $"[{providerName}] {message}", ...) { }
}

上传与搜索请求模型

UploadFileRequestFolderId / FileName / Contentrequired 成员,连接器不会释放 Content 流(生命周期由调用方管理)。ContentLength 用于大文件上传策略判断,ConflictBehavior 控制重名时重命名/覆盖/跳过。

SearchFilesRequest 支持按关键词全局或指定文件夹范围搜索,可按文件类型、扩展名筛选,排序默认按修改时间:

public sealed class SearchFilesRequest
{
public required string Keyword { get; init; }
public string? FolderId { get; init; } // null = 全局搜索
public DriveFileType? FileType { get; init; } // File / Folder 筛选
public string? Extension { get; init; } // 扩展名筛选
public FileSortOrder SortBy { get; init; } = FileSortOrder.ModifiedTime;
public int PageIndex { get; init; } = 1;
public int PageSize { get; init; } = 50;
}

共享链接与权限

CreateShareLinkRequestShareLinkAccessLevel 枚举(不是字符串)控制访问级别:

public enum ShareLinkAccessLevel
{
View = 0, // 仅查看
Edit = 1, // 可编辑
Upload = 2, // 仅上传
Download = 3, // 仅下载
}

DriveShareLink 返回的链接可带密码、过期时间、最大访问次数(null 表示无限制),但不同厂商支持程度不一。DrivePermissionPermissionRole(Reader / Writer / Owner)描述角色,部分厂商支持独立的下载/预览权限开关(CanDownload / CanPreview)。

厂商清单

厂商Provider ID鉴权定位
阿里云盘aliyunOAuth 2.0 Bearer个人云盘 + 相册(PDS v2)
百度网盘baiduOAuth 2.0个人云盘
坚果云nutstore账号密码 / API Token个人与团队同步
OneDrivemicrosoft365OAuth 2.0(MS Graph)企业网盘
够快云库gokuaiAPI Token企业文档协作
爱数 AnyShareanyshare账号密码 / OAuth企业内容管理

各家对共享链接和权限模型的支持程度不一,阿里云 Descriptor 明确记录 PDS API 不提供独立权限管理接口,文件版本管理契约尚未确认。全部 Preview 稳定性。

注册

单厂商

// ① 坚果云
builder.Services.AddBitzsoftNutstoreCloudDrive(builder.Configuration.GetSection("CloudDrive:Nutstore"));
// ② OneDrive(走 Microsoft Graph)
builder.Services.AddBitzsoftMicrosoft365CloudDrive(builder.Configuration.GetSection("CloudDrive:Microsoft365"));

多厂商聚合

builder.Services.AddBitzsoftCloudDriveAll(builder.Configuration, "CloudDrive");

配置:

{
"CloudDrive": {
"Aliyun": { "ClientId": "...", "ClientSecret": "...", "RedirectUri": "..." },
"Microsoft365": { "TenantId": "...", "ClientId": "...", "ClientSecret": "..." }
}
}

消费

文件上传与列表

public class DriveService(ICloudDriveProvider drive)
{
// ① 上传文件到指定文件夹
public async Task<DriveFileInfo> UploadAsync(string folderId, string fileName, Stream content)
{
var result = await drive.UploadAsync(new UploadFileRequest
{
FolderId = folderId,
FileName = fileName,
Content = content,
});
return result.FileInfo;
}
// ② 列出文件夹内容(分页)
public async Task<ListFilesResult> ListAsync(string folderId, int page = 1)
=> await drive.ListFilesAsync(folderId, pageIndex: page, pageSize: 50);
}

共享链接与版本回滚

public class SharingService(ICloudDriveProvider drive)
{
// ① 创建只读共享链接
public async Task<DriveShareLink> ShareAsync(string fileId)
{
return await drive.CreateShareLinkAsync(new CreateShareLinkRequest
{
FileId = fileId,
AccessLevel = ShareLinkAccessLevel.View, // 仅查看
// Password / ExpireTime / MaxAccessCount 部分厂商不支持
});
}
// ② 回滚到历史版本
public async Task<DriveFileInfo> RollbackAsync(string fileId, string versionId)
=> await drive.RestoreVersionAsync(fileId, versionId);
}

多厂商路由

public class DriveRouter(IIntegrationProviderResolver<ICloudDriveProvider> drives)
{
public async Task<DriveFileInfo> UploadAsync(string platform, string folderId, string fileName, Stream content)
{
var drive = drives.GetRequired(platform); // "aliyun" / "nutstore" / "microsoft365" ...
var result = await drive.UploadAsync(new UploadFileRequest { FolderId = folderId, FileName = fileName, Content = content });
return result.FileInfo;
}
}

相关

100%

滚轮或按钮缩放 · 放大后拖动画面 · 双击切换 100% / 200%