Bitzsoft.Integrations.GoogleWorkspace
1.0.0-alpha.10
dotnet add package Bitzsoft.Integrations.GoogleWorkspace --version 1.0.0-alpha.10
NuGet\Install-Package Bitzsoft.Integrations.GoogleWorkspace -Version 1.0.0-alpha.10
<PackageReference Include="Bitzsoft.Integrations.GoogleWorkspace" Version="1.0.0-alpha.10" />
<PackageVersion Include="Bitzsoft.Integrations.GoogleWorkspace" Version="1.0.0-alpha.10" />
<PackageReference Include="Bitzsoft.Integrations.GoogleWorkspace" />
paket add Bitzsoft.Integrations.GoogleWorkspace --version 1.0.0-alpha.10
#r "nuget: Bitzsoft.Integrations.GoogleWorkspace, 1.0.0-alpha.10"
#:package Bitzsoft.Integrations.GoogleWorkspace@1.0.0-alpha.10
#addin nuget:?package=Bitzsoft.Integrations.GoogleWorkspace&version=1.0.0-alpha.10&prerelease
#tool nuget:?package=Bitzsoft.Integrations.GoogleWorkspace&version=1.0.0-alpha.10&prerelease
Bitzsoft.Integrations.GoogleWorkspace
Google Workspace Admin SDK Directory、Gmail v1、Calendar v3 与 Drive v3 的多租户连接器,面向 ToB 组织目录、协作邮箱、企业日历和文档协作场景, 支持 .NET 5、.NET 8 和 .NET 10。
安装与前置条件
dotnet add package Bitzsoft.Integrations.GoogleWorkspace
生产宿主必须提供服务账号凭据解析器,并在 Google Workspace 管理控制台完成 Domain-wide Delegation 与最小 scope 授权。
已实现
- OAuth 2.0 JWT Bearer 服务账号授权;
- 强制域级委派管理员(JWT
sub),缺少时不会发出 token 请求; - users.list / users.get;
- groups.list / members.list;
- 用户
suspended状态赋值; - 用户、组、成员的开放字段模型与完整
RawJSON; - 不透明
nextPageToken分页与租户/profile/凭据隔离 token cache; - 读取与用户写入使用两套最小权限 scope;
- Gmail profile、message list/get、完整 MIME/Raw 与 history 增量;
- Gmail messages 全量基线、可恢复分页和 history 增量
ISyncPageSource; - 增量删除、并发删除与过滤移出使用 tombstone,单页重复变更会折叠;
- message 水化并发可配置且强制限制在 1–16,不限制单封响应正文大小;
- 原始 RFC 2822 send(不做隐式重试);
- Gmail Cloud Pub/Sub watch / stop;
- Cloud Pub/Sub wrapped push 的 Google OIDC 验签、可信 audience / 服务账号 / subscription / mailbox 绑定;
- Webhook Inbox 原始报文留存、可变
deliveryAttempt语义去重和类型化 Gmail history 水位解析。 - CalendarList list 与 events list / get;
- Calendar event 创建:调用方提供确定性 base32hex event ID,并显式选择
sendUpdates; - 可选 Google Meet 创建请求、参与人、周期规则、全天/定时事件和取消 tombstone;
- Calendar 开放字段模型与完整
RawJSON,不限制描述或响应正文大小。 - Drive files.list / files.get、共享盘/allDrives 查询和
incompleteSearch显式暴露; - Drive changes.getStartPageToken / changes.list,文件移除、共享盘变更、
独立 change token 与完整
RawJSON; - Drive files 全量基线、changes 增量、可恢复分页和 tombstone
ISyncPageSource; - Drive blob 流式下载、Range / ETag 条件读取和 Google Workspace 文档导出;
- Drive 预生成 file ID、可恢复上传会话、256 KiB 分片、服务端 Range 对账和 会话 URL 轮换;
- Drive 文件读取与 app-created 文件写入使用独立最小权限 scope,上传分片 不做隐式重试。
请求和响应正文不会被隐式截断或限制大小。OAuth token 请求/响应属于凭据, 会逐请求显式禁止正文日志;普通 Admin SDK 业务正文仍保持完整。
凭据
宿主通过 IIntegrationCredentialResolver 为
Productivity:google-workspace 提供:
OAuthJwtIssuer:服务账号 email;OAuthJwtPrivateKey:PKCS#8 PEM RSA 私钥;OAuthJwtKeyId:服务账号私钥 ID,可选;OAuthJwtSubject:默认被模拟的 Workspace 主体;Directory 固定场景可用。
Gmail、Calendar 和 Drive 应在 GoogleWorkspaceRequestContext 传入
delegatedSubject。同一服务账号可以按调用委派不同用户,token cache 以
主体 SHA-256 指纹隔离,不在缓存键或 ToString() 中保存邮箱明文。
除创建服务账号外,Workspace 超级管理员还必须在 Admin Console 中为该 服务账号 client ID 授权实际使用的域级委派 scopes。连接器不会扩大 Admin Console 已批准的权限。
只读目录使用:
admin.directory.user.readonlyadmin.directory.group.readonlyadmin.directory.group.member.readonly
停用/恢复用户单独使用 admin.directory.user,不会让只读调用复用写 token。
注册
固定 Google 公网端点:
services.AddBitzsoftGoogleWorkspace(new GoogleWorkspaceEndpoint());
固定单邮箱同步可同时注册显式委派主体:
services.AddBitzsoftGoogleWorkspace(
new GoogleWorkspaceEndpoint(),
syncProfiles: null,
gmailSyncProfiles: new[]
{
new GoogleWorkspaceGmailSyncProfile(
delegatedSubject: "alice@example.com",
credentialName: "workspace-service-account")
});
固定单日历的 CalendarEvents 同步 profile 应显式绑定委派主体和 Calendar ID:
services.AddBitzsoftGoogleWorkspace(
new GoogleWorkspaceEndpoint(),
syncProfiles: null,
gmailSyncProfiles: null,
pubSubPushProfiles: null,
calendarSyncProfiles: new[]
{
new GoogleWorkspaceCalendarSyncProfile(
delegatedSubject: "alice@example.com",
calendarId: "team#calendar@example.com",
credentialName: "workspace-service-account")
});
固定委派用户或单个共享盘的 DriveFiles 同步也应显式注册。共享盘使用
driveId;委派用户的 My Drive 则省略该参数:
services.AddBitzsoftGoogleWorkspace(
new GoogleWorkspaceEndpoint(),
syncProfiles: null,
gmailSyncProfiles: null,
pubSubPushProfiles: null,
calendarSyncProfiles: null,
driveSyncProfiles: new[]
{
new GoogleWorkspaceDriveSyncProfile(
delegatedSubject: "alice@example.com",
driveId: "shared-drive-id",
credentialName: "workspace-service-account")
});
多租户私有代理或不同 profile 可由宿主实现
IGoogleWorkspaceEndpointResolver 与
IGoogleWorkspaceDirectorySyncProfileResolver。多邮箱同步还应实现
IGoogleWorkspaceGmailSyncProfileResolver;多日历或多 Drive 范围还应实现
IGoogleWorkspaceCalendarSyncProfileResolver 和
IGoogleWorkspaceDriveSyncProfileResolver。通常按
SyncJobKey.SinkName 选择委派邮箱、Calendar ID 或共享盘。需要同时自定义所有
resolver 时使用六泛型参数重载。
services.AddBitzsoftGoogleWorkspace<
TenantGoogleWorkspaceEndpointResolver,
TenantGoogleWorkspaceDirectorySyncProfileResolver,
TenantGoogleWorkspaceGmailSyncProfileResolver,
TenantGoogleWorkspacePubSubPushProfileResolver,
TenantGoogleWorkspaceCalendarSyncProfileResolver,
TenantGoogleWorkspaceDriveSyncProfileResolver>();
如果只有 Calendar 或 Drive 需要动态路由,也可以先按标准 DI 注册对应的
profile resolver;随后调用连接器注册时使用的 TryAdd 不会覆盖宿主实现。
凭据解析器仍按每次调用的 GoogleWorkspaceRequestContext 解析,注册固定端点
不会把服务账号密钥放入 singleton。
固定端点注册会把 Drive API 与 upload API 的精确 origin 加入文件传输
allow-list。动态端点解析器或额外 CDN 必须由宿主在连接器注册前显式注册
IGoogleWorkspaceTransferUrlPolicy;后续 TryAdd 不会覆盖宿主策略:
services.AddSingleton<IGoogleWorkspaceTransferUrlPolicy>(
new GoogleWorkspaceTransferUrlPolicy(
additionalAllowedOrigins: new[]
{
new Uri("https://workspace-proxy.example.com:8443/")
}));
官方 googleapis.com、googleusercontent.com 与
drive.usercontent.google.com 默认受信;相似后缀、userinfo、fragment、
默认策略下的 IP 地址及未显式配置的非标准端口会在请求前拒绝。userinfo 与
fragment 即使配置了 origin 也不会放行。HTTP 只可在显式开发选项下用于
loopback。
Gmail Pub/Sub push
Cloud Pub/Sub subscription 应启用 authenticated push,并用专用服务账号签发 OIDC token。固定 endpoint 可把所有可信绑定一起注册:
services.AddInMemoryWebhookInfrastructure(); // 仅开发/测试
services.AddBitzsoftGoogleWorkspace(
new GoogleWorkspaceEndpoint(),
syncProfiles: null,
gmailSyncProfiles: new[]
{
new GoogleWorkspaceGmailSyncProfile("alice@example.com")
},
pubSubPushProfiles: new[]
{
new GoogleWorkspacePubSubPushProfile(
expectedAudience:
"https://integrations.example.com/webhooks/google/gmail",
expectedServiceAccountEmail:
"pubsub-push@project.iam.gserviceaccount.com",
expectedSubscription:
"projects/project/subscriptions/gmail-events",
expectedMailbox: "alice@example.com",
endpointId: "alice-gmail")
});
生产环境必须用数据库实现替换进程内 Inbox/replay store,并以
WebhookRoute.EndpointId 从可信路由选择 profile。多租户宿主应实现
IGoogleWorkspacePubSubPushProfileResolver,不要从请求正文反向选择
audience、服务账号、subscription 或邮箱。
HTTP 入口应保留请求原始 bytes 和全部 Header,构造 WebhookRequest 后交给
IWebhookGateway.ReceiveAsync。只有返回 Accepted 或 Duplicate 才应向
Pub/Sub 返回 2xx;验签依赖的 Google 证书暂时不可用、Inbox 持久化失败等异常
应返回非 2xx 让 Pub/Sub 重试。验签失败可按宿主安全策略返回 4xx。
var result = await gateway.ReceiveAsync(
new WebhookRoute(
tenantId: "tenant-a",
providerKey: GoogleWorkspaceConstants.ProviderKey,
endpointId: "alice-gmail"),
request,
cancellationToken);
if (result.Envelope is not null)
{
var notification =
GoogleGmailPushNotification.Parse(result.Envelope);
// 以 notification.HistoryId 触发/合并 Gmail Incremental sync。
}
Pub/Sub messageId 与 subscription 形成稳定 Inbox identity;
deliveryAttempt 只作为诊断扩展,不参与语义摘要。每次投递的原始正文及
PayloadSha256 均保持不变并完整留存。Gmail/Google 可能延迟或丢弃通知,
因此 push 只是加速器,仍需定期执行 history 增量同步并在 watch 到期前续订。
调用
var context = new GoogleWorkspaceRequestContext(
tenantId: "tenant-a",
credentialName: "workspace-service-account");
var users = await directory.ListUsersAsync(
context,
new GoogleWorkspaceUserQuery(maxResults: 200),
cancellationToken: cancellationToken);
await directory.SetUserSuspendedAsync(
context,
"user-id-or-primary-email",
suspended: true,
cancellationToken);
Gmail 使用显式委派主体,并始终访问 users/me,避免 URL 用户与 JWT
sub 不一致:
var mailboxContext = new GoogleWorkspaceRequestContext(
tenantId: "tenant-a",
credentialName: "workspace-service-account",
delegatedSubject: "alice@example.com");
var profile = await gmail.GetProfileAsync(
mailboxContext,
cancellationToken);
var history = await gmail.ListHistoryAsync(
mailboxContext,
new GoogleGmailHistoryQuery(profile.HistoryId),
cancellationToken: cancellationToken);
Gmail historyId 是邮箱增量水位,不是分页 token。过期 404 会返回
GoogleWorkspaceException.IsIncrementalCursorExpired = true,此时必须
重新建立全量消息基线。Gmail watch 只向 Cloud Pub/Sub 发布邮箱和
historyId 水位;通知到达后仍需调用 history API,并在到期前续订。
Calendar 也必须使用显式委派主体:
var calendars = await calendar.ListCalendarsAsync(
mailboxContext,
cancellationToken: cancellationToken);
var created = await calendar.CreateEventAsync(
mailboxContext,
calendarId: "primary",
new GoogleCalendarEventCreateRequest(
eventId: "4f4d9a2c6b8e0",
start: GoogleCalendarEventDateTime.Timed(startsAt),
end: GoogleCalendarEventDateTime.Timed(endsAt),
sendUpdates: GoogleCalendarSendUpdates.All,
summary: "Customer review",
conferenceRequestId: "crm-opportunity-42"),
cancellationToken);
Calendar 读取使用 calendar.readonly,event 创建单独使用
calendar.events。创建不会做 transport 自动重试,也不会伪造服务端不支持的
Idempotency-Key;网络结果不确定时应按调用方提供的 event ID 执行 get
对账。sendUpdates 必须由业务显式选择,避免默认值悄悄发送或抑制通知。
Drive 文件与 change feed 同样使用显式委派主体:
var files = await drive.ListFilesAsync(
mailboxContext,
new GoogleDriveFileQuery(
corpus: GoogleDriveCorpus.Drive,
driveId: "shared-drive-id",
query: "trashed = false"),
cancellationToken: cancellationToken);
var start = await drive.GetStartPageTokenAsync(
mailboxContext,
new GoogleDriveChangeQuery(driveId: "shared-drive-id"),
cancellationToken);
files.list 默认会返回回收站项目;业务若不要回收站内容,必须像示例一样
显式提供 trashed = false。incompleteSearch=true 表示 allDrives 查询遗漏
了部分语料,调用方不得把该页当作完整基线。files 分页 token 通常只在数小时
内有效,而 change token 是长期水位;两者使用不同类型,不能互换或记录到日志。
共享盘查询会强制 supportsAllDrives=true,不一致的 corpus/driveId 参数在
网络请求前失败。
blob 下载返回拥有底层 HTTP lease 的流式响应,调用方必须释放。连接器不会 限制或截断文件正文;Range、ETag 和 abuse 确认必须显式选择:
await using var download = await drive.OpenFileContentAsync(
mailboxContext,
fileId: "drive-file-id",
new GoogleDriveDownloadOptions(
rangeStart: 0,
rangeEnd: 1024 * 1024 - 1,
ifNoneMatch: "\"etag\""),
cancellationToken);
await using var source = await download.OpenBodyStreamAsync(
cancellationToken);
await source.CopyToAsync(destination, cancellationToken);
acknowledgeAbuse 默认关闭,且 Google 只允许文件所有者或共享盘 organizer
确认。下载/导出发生重定向时,连接器不会向目标转发 OAuth Authorization
或 Cookie,并会先执行 SSRF allow-list 校验。导出接口自身不增加大小上限,
但 Google files.export 当前有 10 MB 上游限制。
可恢复上传只覆盖普通 blob,不隐式执行 Google Workspace 文档转换。先生成
file ID,再以 drive.file scope 创建会话,可以在初始化结果不确定时按 ID
对账,避免盲目创建重复文件:
var generated = await drive.GenerateFileIdsAsync(
mailboxContext,
cancellationToken: cancellationToken);
var upload = new GoogleDriveResumableUploadRequest(
generated.Ids.Single(),
name: "archive.bin",
contentType: "application/octet-stream",
contentLength: content.Length,
parents: new[] { "parent-folder-id" });
var session = await drive.CreateResumableUploadSessionAsync(
mailboxContext,
upload,
cancellationToken);
const int fragmentSize = 8 * 1024 * 1024; // 256 KiB 的整数倍
long offset = 0;
while (offset < session.TotalLength)
{
content.Position = offset; // 示例使用可重放的 seekable 流
var length = Math.Min(
fragmentSize,
session.TotalLength - offset);
var progress = await drive.UploadFragmentAsync(
mailboxContext,
session,
content,
offset,
length,
cancellationToken);
session = progress.Session;
offset = progress.NextOffset;
}
上传 session URL 是约一周有效的 bearer secret。只有
ExportUploadUrl() 会显式导出它;宿主必须把 URL 加密,并将
ExportContextBinding()、内容类型、总长度和到期时间作为同一会话记录持久化,
不得进入日志或遥测。恢复时 RestoreResumableUploadSession 会校验该不可逆
绑定是否仍属于相同租户、profile、凭据名和委派主体;每次查询/上传也会复核。
非末片必须是 256 KiB 的整数倍;底层严格只读取本次声明的字节数,因此同一
seekable 大流可连续发送多个分片。
网络结果不确定时不能盲目重试,应先调用 QueryUploadStatusAsync,以服务端
确认的 NextOffset 重新定位可重放内容流;不可重放流必须由业务重新取得。
GoogleWorkspacePageToken 必须原样用于下一页,不应解析、持久化到日志或拼接
新的查询条件。Google 当前只保证 Directory 分页 token 有限期有效,过期后应
重新开始全量枚举。
写入语义
SetUserSuspendedAsync 使用 users.update 的状态赋值 PUT。重复设置相同目标
状态是幂等的,但 transport 不做自动重试;网络结果不确定时应调用 users.get
核对最终状态,再由业务操作台账决定是否补偿。
同步
Directory 没有被认证为可靠 delta feed。通用 ISyncPageSource 因而只接受
Directory 的显式 SyncMode.Full,并在最终页清除旧 delta cursor:
var request = new SyncRunRequest(
jobKey,
mode: SyncMode.Full,
pageSize: 200);
var result = await engine.RunAsync(
request,
workspaceSource,
sink,
reconciler,
cancellationToken);
必须提供与 Sink 一致的 reconciler,只有完整消费所有页后才能判断缺失记录。
Directory 不要使用 SyncMode.Automatic:首次运行虽会解析为 Full,但后续
会解析为 Incremental 并被明确拒绝。Users 最大页大小按 500、Groups 按 200
自动收敛;page token 只在当前全量运行内使用。
Gmail 的 stream 名为 GmailMessages。首次 Automatic 运行执行全量
messages.list + messages.get,最终提交独立的 history delta cursor;后续
运行调用 history.list。分页 continuation 同时保留原始基线,暂停恢复不会把
page token 误当成 delta cursor。history 404/410 会以
gmail_history_expired 失败,宿主应显式发起新的 Full 基线。
Gmail 搜索查询 q 无法由 history feed 安全重现,因此使用查询时必须设置
enableIncremental: false;最终页不会提交 delta cursor,后续 Automatic
仍会执行 Full。标签过滤可做增量同步,但连接器需要读取邮箱 history 后按当前
标签生成记录或 tombstone,API 调用量会高于无过滤同步。
Calendar 的 stream 名为 CalendarEvents。首次 Automatic 运行完整枚举
events,并且只在最终页提交 nextSyncToken;后续运行使用该 token 获取
增量。增量多页的每一个请求都会同时保留原始 committed sync token,分页
continuation 不会冒充新的 delta 水位。取消事件映射为 tombstone,410 以
calendar_sync_token_expired 失败,宿主必须显式发起新的 Full 基线。
Calendar continuation 和 delta cursor 会绑定 endpoint、凭据名、委派主体、
Calendar ID 及查询形状的不可逆摘要。同步中途修改 profile 会以
cursor_invalid 失败,不会把旧 page/sync token 用到另一个日历。完整 cursor
还会保留首次实际 maxResults;恢复或增量运行即使收到不同的
SyncRunRequest.PageSize,也不会改变 Google 要求稳定的查询形状。cursor 和
正文均不会写入 ToString();事件原始 JSON 和大字段仍不做大小截断。
默认 singleEvents: false,同步周期事件主记录与例外,避免无界展开重复实例。
需要实例级仓库时可显式启用,并在整个 cursor 生命周期保持 profile 不变。
Calendar 全量和增量都使用 showDeleted=true,确保取消实例不会丢失。
Drive 的 stream 名为 DriveFiles。Full 会先取得
changes.getStartPageToken,再用固定的 trashed = false 查询枚举
files.list;这样全量期间发生的变更可能在首次增量中重放,但不会出现
“取得全量结果后、建立增量水位前”的漏数窗口。仅支持能与 change feed
一一对应的范围:委派用户的 user corpus,或显式 driveId 的共享盘
corpus;appDataFolder 只允许委派用户范围。任意搜索 q 不进入同步
profile,因为 changes.list 无法可靠重现任意搜索谓词。
全量分页 continuation 会同时保存原始 change baseline、首次实际页大小和
files page token;最终页提交的仍是全量开始前取得的 baseline。files page
token 通常只在数小时内有效,被 Google 拒绝时以
drive_file_page_token_invalid 失败,必须重新执行 Full。
incompleteSearch=true 也会以 drive_incomplete_search 失败关闭,不能把
不完整结果提交为基线。
后续 Automatic 运行使用 changes.list。文件移除、失去访问权限以及进入回收站
都会映射为 tombstone;非文件的共享盘变更被忽略,同一页对同一文件的多次变更
折叠为最后状态。增量 continuation 始终绑定原 committed change token,不会
把中间 page token 提交成新水位;只有最终页的 newStartPageToken 会提交。
Google 文档说明 change token 不会过期,但若服务端实际以 400/410 拒绝,
连接器仍会稳定返回 drive_change_token_invalid 并要求重新 Full。
Drive cursor 绑定 endpoint profile、凭据名、委派主体、共享盘 ID 和 space
的不可逆摘要。恢复时改变任何范围都会以 cursor_invalid 失败;cursor、
metadata 和 ToString() 都不会暴露委派邮箱、共享盘 ID 或原始 Google token。
边界
- 当前覆盖 Admin SDK Directory、Gmail v1、Calendar v3、Drive v3 文件元数据 与 change-feed typed client、文件下载/导出和可恢复 blob 上传,以及 Calendar events 和 Drive files 可恢复全量/增量同步;
- Drive 原生文档转换上传、权限/共享管理和真实商业租户契约认证仍在后续 子切片;
- Gmail send 没有原生幂等键,连接器不做隐式重试;结果不确定时应按 RFC Message-ID 对账;
- Directory API 没有被本包声明为增量变更源;不得把 page token 当 delta cursor;
- 服务账号 JSON 文件不应整体进入配置或日志,只应将所需字段写入 Vault/KMS 背后的凭据解析器;
- 尚未完成真实 Workspace 商业租户的 sandbox 契约认证,因此当前能力应按 Preview 管理。
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 is compatible. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Bitzsoft.Integrations.Compatibility (>= 1.0.0-alpha.10)
- Bitzsoft.Integrations.Core (>= 1.0.0-alpha.10)
- Bitzsoft.Integrations.Rest (>= 1.0.0-alpha.10)
- Bitzsoft.Integrations.Sync (>= 1.0.0-alpha.10)
- Bitzsoft.Integrations.Webhooks (>= 1.0.0-alpha.10)
- Google.Apis.Auth (>= 1.75.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.10)
-
net5.0
- Bitzsoft.Integrations.Compatibility (>= 1.0.0-alpha.10)
- Bitzsoft.Integrations.Core (>= 1.0.0-alpha.10)
- Bitzsoft.Integrations.Rest (>= 1.0.0-alpha.10)
- Bitzsoft.Integrations.Sync (>= 1.0.0-alpha.10)
- Bitzsoft.Integrations.Webhooks (>= 1.0.0-alpha.10)
- Google.Apis.Auth (>= 1.62.1)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 5.0.0)
-
net8.0
- Bitzsoft.Integrations.Compatibility (>= 1.0.0-alpha.10)
- Bitzsoft.Integrations.Core (>= 1.0.0-alpha.10)
- Bitzsoft.Integrations.Rest (>= 1.0.0-alpha.10)
- Bitzsoft.Integrations.Sync (>= 1.0.0-alpha.10)
- Bitzsoft.Integrations.Webhooks (>= 1.0.0-alpha.10)
- Google.Apis.Auth (>= 1.75.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.10)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Bitzsoft.Integrations.GoogleWorkspace:
| Package | Downloads |
|---|---|
|
Bitzsoft.Integrations.All
Bitzsoft 第三方集成聚合包 — net5.0 包含传统连接器,net8.0+ 额外包含受上游 TFM 限制的 AI 模块 |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.0-alpha.10 | 51 | 7/26/2026 |