Bitzsoft.Integrations.OutboundCall 1.0.4

dotnet add package Bitzsoft.Integrations.OutboundCall --version 1.0.4
                    
NuGet\Install-Package Bitzsoft.Integrations.OutboundCall -Version 1.0.4
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Bitzsoft.Integrations.OutboundCall" Version="1.0.4" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Bitzsoft.Integrations.OutboundCall" Version="1.0.4" />
                    
Directory.Packages.props
<PackageReference Include="Bitzsoft.Integrations.OutboundCall" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Bitzsoft.Integrations.OutboundCall --version 1.0.4
                    
#r "nuget: Bitzsoft.Integrations.OutboundCall, 1.0.4"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Bitzsoft.Integrations.OutboundCall@1.0.4
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Bitzsoft.Integrations.OutboundCall&version=1.0.4
                    
Install as a Cake Addin
#tool nuget:?package=Bitzsoft.Integrations.OutboundCall&version=1.0.4
                    
Install as a Cake Tool

Bitzsoft.Integrations.OutboundCall

外呼服务抽象层 — 统一 IOutboundCallService 接口、号码工具(清洗 / 分类 / 校验)、境内外分离、白名单 / 黑名单控制、per-call 活动编排引擎。

功能特性

  • 统一外呼接口 IOutboundCallService:创建活动、导入名单、启动 / 暂停 / 恢复 / 停止、活动列表 / 详情、话单查询
  • 号码校验 PhoneNumberValidator:内置 150+ 国家 / 地区 ITU 号码长度表,支持全角字符、中文 / 英文标签前缀、/ , ; 空格换行分隔符等多种容错场景,自动识别 +86 / 0086 / (+86) 等区号前缀组合
  • 号码批量分类 PhoneNumberClassifier:将混合号码列表按区号自动分为境内(86)与境外两组,返回统一清洗格式
  • 白名单 / 黑名单过滤 CallListFilter:创建活动前自动过滤号码,支持后缀匹配;非生产环境可强制要求白名单,防止误呼叫真实客户
  • 境内外分离:OutboundCallOptions.GetCallers / GetSdkAppId / GetIvrId 按 PhoneRegion 自动选择主叫号码、应用 ID、IVR 流程
  • per-call 编排引擎 CampaignDialer + CampaignRuntime:为无原生 campaign 概念的供应商(Twilio 等)提供串行拨号 + CPS 节流 + 暂停 / 恢复断点(代次守卫)+ 停止的内存活动编排
  • 统一异常模型 OutboundCallException:携带供应商标识、错误码、请求 ID,便于问题溯源
  • 供应商标识 ProviderName:每个实现暴露固定标识(如 Tencent / Aliyun),用于日志区分与异常溯源

安装

.NET CLI

dotnet add package Bitzsoft.Integrations.OutboundCall

PackageReference

<PackageReference Include="Bitzsoft.Integrations.OutboundCall" Version="1.0.0" />

配置

抽象层本身不注册服务,但 OutboundCallOptions 是所有供应商实现共享的配置契约,供应商实现通过 services.Configure<OutboundCallOptions>(...) 绑定。以下 JSON 是该选项类的完整字段(节名由各供应商扩展方法决定,通常为 OutboundCall)。

appsettings.json

{
  "OutboundCall": {
    "AccessKeyId": "your-secret-id",
    "AccessKeySecret": "your-secret-key",
    "Region": "ap-guangzhou",
    "Endpoint": null,
    "SdkAppId": "1400818883",
    "Callers": [ "008602160662606" ],
    "OverseaCallers": [ "0085230087235" ],
    "CnIvrId": 21232,
    "EnIvrId": 21408,
    "OverseaSdkAppId": "1400818885",
    "OverseaCnIvrId": null,
    "OverseaEnIvrId": null,
    "Whitelist": [ "5678" ],
    "Blacklist": [ "008613800000000" ],
    "RequireWhitelistInNonProduction": true,
    "ExtraProperties": {}
  }
}
配置项 说明 必填 默认值
AccessKeyId API 密钥 ID(腾讯 SecretId / 阿里 AccessKeyId / 容联 AccountSid) 是 空字符串
AccessKeySecret API 密钥(腾讯 SecretKey / 阿里 AccessKeySecret / 容联 AuthToken) 是 空字符串
Region 地域(如 ap-guangzhou / cn-hangzhou / cn-north-4) 否 空字符串(各供应商使用各自默认地域)
Endpoint API 端点覆盖 否 null(各供应商使用内置默认端点)
SdkAppId 应用 ID(腾讯 SdkAppId / 阿里 InstanceId / 容联 AppId) 视供应商 null
Callers 境内主叫号码列表(中国大陆外呼) 是 空列表
OverseaCallers 境外主叫号码列表(海外外呼) 否 空列表
CnIvrId 中文 IVR 流程 ID(境内呼叫) 视供应商 null
EnIvrId 英文 IVR 流程 ID(境外呼叫) 视供应商 null
OverseaSdkAppId 境外独立应用 ID(与境内不同时使用) 否 null
OverseaCnIvrId 境外中文 IVR 流程 ID 否 null
OverseaEnIvrId 境外英文 IVR 流程 ID 否 null
Whitelist 外呼白名单(仅允许呼叫这些号码,支持后缀匹配) 否 null
Blacklist 外呼黑名单(禁止呼叫这些号码) 否 null
RequireWhitelistInNonProduction 非生产环境是否强制要求白名单 否 true
ExtraProperties 供应商特有扩展参数 否 null

注册服务

抽象层不提供 AddBitzsoft* 扩展方法。实际注册由各供应商实现包完成,例如:

腾讯云(从 IConfiguration 绑定)

using Bitzsoft.Integrations.OutboundCall;

// 由供应商扩展方法读取该配置节
builder.Configuration.GetSection("OutboundCall");

通过 Options 直接构造(测试 / 号码工具场景)

抽象层的号码工具、过滤器、编排引擎均为静态类或可直接实例化的类型,无需 DI 即可使用:

using Bitzsoft.Integrations.OutboundCall;
using Bitzsoft.Integrations.OutboundCall.PhoneNumber;

// 直接调用静态号码工具,无需注册服务
var (mainland, oversea) = PhoneNumberClassifier.Classify(rawPhones);

var options = new OutboundCallOptions
{
    Whitelist = new() { "5678" },
    Blacklist = new() { "008613800000000" }
};
var filtered = CallListFilter.Filter(callees, options);

使用示例

号码清洗 + 分类(批量)

using Bitzsoft.Integrations.OutboundCall.PhoneNumber;

var rawPhones = new[]
{
    "0086-138-1234 5678",
    "+12125550123",
    "(+852)30087235",
    "电话:13900000000"
};

// 1. 批量解析,自动全角转半角、剥离标签、识别区号、长度校验
var records = PhoneNumberValidator.ExtractAll(rawPhones);
foreach (var r in records)
{
    // r.FullNumber    "008613812345678" / "+12125550123"
    // r.RegionCode    "86" / "1"
    // r.Region        PhoneRegion.Mainland / PhoneRegion.Overseas
    // r.IsValid       true
}

// 2. 一键分类为境内 / 境外两组(去重)
var (mainland, oversea) = PhoneNumberClassifier.Classify(rawPhones);
// mainland: ["008613812345678", "008613900000000"]
// oversea:  ["+12125550123", "+85230087235"]

单个号码校验

var isValid = PhoneNumberValidator.IsValid("008613812345678");      // true
var (regionCode, ok) = PhoneNumberValidator.IdentifyRegion("12025550123"); // ("1", true)

白名单 / 黑名单过滤

using Microsoft.Extensions.Logging;

var options = new OutboundCallOptions
{
    Whitelist = new() { "5678" },               // 后缀匹配:仅允许以 5678 结尾
    Blacklist = new() { "008613800000000" }     // 精确 / 后缀匹配:禁止该号
};

var callees = new[] { "008613812345678", "008613800000000", "00861399995678" };
// 过滤顺序:黑名单优先排除 → 白名单仅保留
var filtered = CallListFilter.Filter(callees, options, logger);
// 结果:["008613812345678", "00861399995678"]

统一外呼接口(消费方)

using Bitzsoft.Integrations.OutboundCall;
using Bitzsoft.Integrations.OutboundCall.Dtos;

public class ReminderService
{
    private readonly IOutboundCallService _outbound;

    public ReminderService(IOutboundCallService outbound) => _outbound = outbound;

    public async Task RunAsync(string[] rawPhones)
    {
        var (mainland, oversea) = PhoneNumberClassifier.Classify(rawPhones);

        // 创建境内活动
        var resp = await _outbound.CreateCampaignAsync(new CreateCampaignRequest
        {
            Name = "催办-境内",
            Region = PhoneRegion.Mainland,
            Callees = mainland.ToList(),
            MaxAttempts = 2,
            NotBefore = DateTimeOffset.UtcNow,
            NotAfter = DateTimeOffset.UtcNow.AddHours(2)
        });

        // 暂停 / 恢复 / 停止
        await _outbound.PauseCampaignAsync(resp.CampaignId);
        await _outbound.ResumeCampaignAsync(resp.CampaignId);
        await _outbound.StopCampaignAsync(resp.CampaignId);

        // 查询活动列表
        var campaigns = await _outbound.ListCampaignsAsync(pageIndex: 1, pageSize: 20);

        // 查询话单
        var records = await _outbound.QueryCallRecordsAsync(new QueryCallRecordsRequest
        {
            CampaignId = resp.CampaignId,
            PageSize = 50
        });
    }
}

per-call 活动编排引擎(供应商内部使用)

using Bitzsoft.Integrations.OutboundCall.PerCall;

var runtime = new CampaignRuntime
{
    Name = "通知外呼",
    Region = PhoneRegion.Overseas,
    Contacts = new() { "+12025550123", "+12025550124" }
};

var dialer = new CampaignDialer(logger);

// 注入实际的呼叫创建逻辑(含 429 退避),由各供应商实现提供
CallCreator creator = async (callee, ct) =>
{
    var sid = await MyProviderCreateCallAsync(callee, ct);
    return new CallAttempt(true, sid, null, null);
};

dialer.StartAsync(runtime, creator, cps: 1, new CancellationTokenSource());

// 暂停(保留断点)→ 恢复(从断点继续)→ 停止(终态)
dialer.Pause(runtime);
dialer.Resume(runtime, creator, cps: 1);
dialer.Stop(runtime);

核心类型一览

接口与选项

类型 说明
IOutboundCallService 外呼服务统一抽象(创建 / 导入 / 启停 / 查询 / 话单)
OutboundCallOptions 全供应商共享配置(鉴权 / 境内外主叫分离 / IVR / 白名单)
OutboundCallException 外呼异常(含供应商标识 Provider、错误码 ErrorCode、请求 ID RequestId)
PhoneRegion 号码区域枚举:Mainland / Overseas / Unknown

号码工具

类型 说明
PhoneNumberValidator 静态号码校验器(Extract / ExtractAll / IsValid / IdentifyRegion,150+ 国家长度表)
PhoneNumberClassifier 静态批量分类器(Classify → 境内 / 境外两组)
PhoneNumberRecord 解析结果(FullNumber / RegionCode / Region / IsValid / CleanNumber)

过滤与编排

类型 说明
CallListFilter 静态白名单 / 黑名单过滤器(黑名单优先,后缀匹配)
CampaignDialer per-call 供应商的活动编排引擎(CPS 节流、代次守卫、暂停 / 恢复断点)
CampaignRuntime per-call 活动内存运行态(联系人队列、状态、断点索引、代次)
CallAttempt 单次呼叫尝试结果(Initiated / CallSid / ErrorCode)
CallCreator 委托:单个被叫的呼叫创建(由供应商注入,含退避重试)

请求 / 响应 DTO

类型 说明
CreateCampaignRequest 创建活动请求(Name / Region / Callees / NotBefore / NotAfter / MaxAttempts / StrategyType / QueueId)
CreateCampaignResponse 创建活动响应(CampaignId / Success / ErrorMessage)
ImportContactsRequest 导入名单请求(CampaignId / Contacts)
StartCampaignRequest 启动活动请求(CampaignId)
CampaignInfo 活动信息(CampaignId / Name / Status / CalleeCount / CalledCount / AnsweredCount)
CampaignStatus 活动状态枚举:Pending / Running / Paused / Completed / Stopped / Failed / Unknown
CallRecord 通话记录(CallId / Caller / Callee / StartTime / DurationSeconds / Status / RecordUrl)
QueryCallRecordsRequest 话单查询请求(CampaignId / 时间范围 / 分页)
OutboundCallResult 通用操作结果(Success / ErrorMessage / RequestId)

安全说明

以下安全职责由宿主应用与各供应商实现承担,抽象层不内置实现。

  • 凭据注入:AccessKeyId / AccessKeySecret 必须通过环境变量或 Secret Manager 注入,禁止硬编码在源代码或配置文件中
  • 白名单(防误呼):开发 / 测试环境务必配置 Whitelist,RequireWhitelistInNonProduction 默认 true,非白名单号码将在创建活动时自动过滤跳过
  • 号码脱敏:PhoneNumberValidator 处理后的 FullNumber 为明文号码,宿主应用在日志、持久化时应按需脱敏
  • 主叫号码合法性:境内外主叫号码分离(Callers / OverseaCallers)需符合各国家 / 地区电信监管要求

依赖

包 说明
Microsoft.Extensions.Logging.Abstractions 日志抽象(ILogger)
Microsoft.Extensions.Options 选项模式(IOptionsMonitor<OutboundCallOptions>)

相关包

Product 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (8)

Showing the top 5 NuGet packages that depend on Bitzsoft.Integrations.OutboundCall:

Package Downloads
Bitzsoft.Integrations.OutboundCall.All

外呼服务聚合包 — 包含全部供应商实现(腾讯云/阿里云/火山引擎/容联云/华为云/国际 Twilio/Vonage)

Bitzsoft.Integrations.OutboundCall.Tencent

腾讯云外呼实现 — 手写 TC3-HMAC-SHA256 签名 + HttpClient,实现 IOutboundCallService 统一接口,支持境内外分离与白名单

Bitzsoft.Integrations.OutboundCall.Aliyun

阿里云外呼实现 — 基于 CCC REST API,实现 IOutboundCallService 统一接口

Bitzsoft.Integrations.OutboundCall.Volcengine

火山引擎智能外呼实现 — 基于 AI 外呼机器人 REST API,实现 IOutboundCallService 统一接口

Bitzsoft.Integrations.OutboundCall.Huawei

华为云云客服外呼实现 — 基于 CEC REST API(AK/SK 签名),实现 IOutboundCallService 统一接口

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.4 175 9/23/2026
1.0.3 146 9/22/2026
1.0.2 283 8/29/2026
1.0.1 370 8/3/2026
1.0.0 354 8/2/2026
1.0.0-alpha.10 109 7/26/2026
1.0.0-alpha.9 102 7/12/2026
1.0.0-alpha.8 108 7/1/2026
1.0.0-alpha.7 119 6/16/2026
1.0.0-alpha.6 114 6/16/2026