Crm 域统一了客户关系管理(CRM)平台的联系人与商机管理能力。HubSpot 和 Dynamics 365 两家供应商共享同一个 ICrmService 接口,但数据模型与鉴权机制差异显著:HubSpot 用 Bearer Private App Token 配合 properties 封装,Dynamics 365 用 Azure AD Bearer 走 Dataverse OData v4。
域结构
Bitzsoft.Integrations.Crm ← 抽象层├── Bitzsoft.Integrations.Crm.HubSpot ← HubSpot(Private App Token,CRM API v3)├── Bitzsoft.Integrations.Crm.Dynamics365 ← Dynamics 365(Azure AD,Dataverse OData v4)└── Bitzsoft.Integrations.Crm.All ← 聚合包标准三层包模式。
统一接口(8 方法)
ICrmService 围绕”联系人(Contact)“和”商机(Deal/Opportunity)“两个核心概念组织,共 8 个方法:
public interface ICrmService{ string ProviderName { get; }
// 联系人 CRUD + 列表(5) Task<ContactInfo> CreateContactAsync(CreateContactRequest request, CancellationToken cancellationToken = default); Task<ContactInfo> GetContactAsync(string contactId, CancellationToken cancellationToken = default); Task<ContactInfo> UpdateContactAsync(string contactId, UpdateContactRequest request, CancellationToken cancellationToken = default); Task DeleteContactAsync(string contactId, CancellationToken cancellationToken = default); Task<List<ContactInfo>> ListContactsAsync(ListContactsRequest request, CancellationToken cancellationToken = default);
// 商机(3) Task<DealInfo> CreateDealAsync(CreateDealRequest request, CancellationToken cancellationToken = default); Task<List<DealInfo>> ListDealsAsync(ListDealsRequest request, CancellationToken cancellationToken = default); Task<DealInfo> UpdateDealStageAsync(string dealId, string stage, CancellationToken cancellationToken = default);}查询类方法(Create / Get / Update / List)返回强类型模型,操作类方法(Delete)为无返回 Task,失败抛 CrmException。
鉴权模型
两家供应商都走 Bearer,但凭证来源与数据访问层完全不同:
| 供应商 | 鉴权机制 | Token 注入 | API 体系 | 数据模型 |
|---|---|---|---|---|
| HubSpot | Private App Access Token | Authorization: Bearer {token} 头 | CRM API v3(api.hubapi.com/crm/v3) | properties 封装(自定义字段包) |
| Dynamics 365 | Azure AD Client Credentials | Authorization: Bearer {token} 头 | Dataverse OData v4({org}.crm.dynamics.com/api/data/v9.2) | 实体属性扁平 |
供应商清单
| 供应商 | Provider ID | API 基地址 | Stability | DI 方法 |
|---|---|---|---|---|
| HubSpot | hubspot | api.hubapi.com/crm/v3 | Preview | AddHubSpotCrm() |
| Dynamics 365 | dynamics-365 | {org}.crm.dynamics.com/api/data/v9.2 | Preview | AddDynamics365Crm() |
HubSpot 是面向中小企业的增长型 CRM,Dynamics 365 是面向中大型企业的微软 CRM 套件。
注册
单厂商
// ① HubSpot(Private App Token,CRM API v3)builder.Services.AddHubSpotCrm(builder.Configuration.GetSection("Crm:HubSpot"));
// ② Dynamics 365(Azure AD Bearer → Dataverse OData v4)builder.Services.AddDynamics365Crm(builder.Configuration.GetSection("Crm:Dynamics365"));全量聚合
builder.Services.AddBitzsoftCrmAll(builder.Configuration, "Crm");按配置节存在性自动注册,appsettings.json 只需写出启用的供应商:
{ "Crm": { "HubSpot": { "AccessToken": "pat-...", "BaseUrl": "https://api.hubapi.com" }, "Dynamics365": { "TenantId": "...", "ClientId": "...", "ClientSecret": "...", "InstanceUrl": "https://yourorg.crm.dynamics.com" } }}消费
联系人管理
public class ContactSyncService(IIntegrationProviderResolver<ICrmService> providers){ public async Task<ContactInfo> UpsertContactAsync(string vendor, string email, string firstName, string lastName, string company) { var crm = providers.GetRequired(vendor); // "hubspot" / "dynamics-365" return await crm.CreateContactAsync(new CreateContactRequest { Email = email, FirstName = firstName, LastName = lastName, Company = company, }); }}商机与阶段推进
// 创建商机(关联联系人)var deal = await crm.CreateDealAsync(new CreateDealRequest{ Name = "Enterprise License - ACME", Amount = 50000m, ContactId = contactId, Stage = "qualified", CloseDate = DateTimeOffset.UtcNow.AddDays(30),});
// 推进销售阶段(pipeline stage)await crm.UpdateDealStageAsync(deal.Id, stage: "presentation-scheduled");
// 列表查询(按阶段过滤)var openDeals = await crm.ListDealsAsync(new ListDealsRequest{ Stage = "negotiation", PageIndex = 1, PageSize = 20,});多厂商路由
public class CrmRouter(IIntegrationProviderResolver<ICrmService> providers){ public async Task<ContactInfo> GetContactAsync(string source, string contactId) { var crm = providers.GetRequired(source); // "hubspot" / "dynamics-365" return await crm.GetContactAsync(contactId); }}