1. 项目背景与核心价值
这套C#编写的企信通源码,是我在2012年参与某大型制造企业OA系统升级时开发的通信模块。当时企业需要将原有的纸质审批流程全面电子化,但面临一个关键痛点:如何让不常登录OA系统的车间主任、外勤人员也能实时接收审批通知?这就是企信通诞生的背景。
企信通本质上是一个基于短信网关的中间件,主要解决三大问题:
- 系统通知的强制触达:相比邮件和站内信,短信打开率高出3-5倍
- 老旧设备的兼容性:车间里那些Windows XP机器也能通过短信交互
- 与FR平台的深度集成:支持通过短信直接触发工作流引擎
这套代码虽然基于VS2008开发,但核心设计至今仍然适用。最近帮朋友改造一个仓储管理系统时,我只用了3小时就将其集成到新系统中,足见其架构的灵活性。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心功能模块解析
2.1 短信网关通信层
采用经典的Socket长连接方案,通过心跳包维持连接。这里有个关键细节:连接断开后的指数退避重连机制。代码中是这样实现的:
csharp复制int retryDelay = 1000; // 初始1秒
while (!isConnected && retryCount < 5)
{
try {
socket.Connect(endpoint);
isConnected = true;
}
catch {
Thread.Sleep(retryDelay);
retryDelay *= 2; // 每次重试间隔翻倍
retryCount++;
}
}
注意:实际项目中建议将重试参数配置化,不同运营商网关的稳定性差异很大
2.2 数据库适配层
支持三种数据库模式:
- 直连模式:适用于高并发场景,直接操作OA系统主库
- 中间表模式:通过定时作业同步数据,适合跨安全域部署
- 内存队列模式:使用ConcurrentQueue做缓冲,应对突发流量
实测在200TPS压力下,内存队列模式能将数据库负载降低62%。
2.3 模板引擎
采用XSLT转换实现短信模板的动态渲染,这个设计现在看来可能有些过时,但在当时有两大优势:
- 可以利用现有的OA系统表单XML结构
- 避免在代码中拼接字符串导致的XSS风险
一个典型的请假审批模板示例:
xml复制<xsl:template match="/FormData">
您有新的请假申请:<xsl:value-of select="Applicant"/>申请<xsl:value-of select="Days"/>天假期,事由:<xsl:value-of select="Reason"/>
</xsl:template>
3. 典型集成场景实战
3.1 与OA系统的工作流集成
以K2工作流引擎为例,需要在Event节点添加如下处理逻辑:
csharp复制protected override void OnTaskAssigned(TaskEventArgs e)
{
var smsInfo = new {
Mobile = GetUserMobile(e.DestinationUser),
Content = BuildSMSContent(e.TaskData)
};
SmsQueue.Instance.Enqueue(smsInfo); // 入队异步发送
}
这里有个容易踩的坑:K2的上下文在异步操作中会丢失,必须在前置动作中完整序列化所需数据。
3.2 与FR报表平台的对接
通过注册FR的AfterRender事件,可以实现报表结果自动短信推送:
csharp复制frReport.AfterRender += (sender, e) => {
if (e.OutputFormat == "SMS") {
var recipients = GetSMSRecipients(e.Parameters);
var content = CompressReportToSMS(e.Result);
SmsSender.SendBatch(recipients, content);
}
};
重要提示:FR的报表结果可能包含敏感数据,务必在短信模板中配置内容过滤器
4. 现代化改造建议
虽然原始代码基于VS2008,但通过以下几个关键改造点可以适配现代环境:
4.1 依赖项升级路径
-
.NET Framework版本:
- 原始:.NET 3.5
- 推荐:通过兼容模式运行,或逐步迁移到.NET Core的System.Compat包
-
数据库访问层:
- 将ADO.NET替换为Dapper
- 连接字符串管理迁移到ConfigurationBuilder
4.2 容器化部署方案
原始安装程序是MSI打包,现代部署建议:
dockerfile复制FROM mcr.microsoft.com/dotnet/framework/runtime:4.8
COPY ./smsgateway /app
EXPOSE 8080
ENTRYPOINT ["SmsGateway.exe"]
4.3 性能优化实测数据
在8核16G的云主机上进行的对比测试:
| 场景 | 原始版本 | 优化后 | 提升幅度 |
|---|---|---|---|
| 峰值TPS | 215 | 498 | 131% |
| 内存占用 | 1.2GB | 680MB | 43%下降 |
| 冷启动时间 | 8.7s | 2.1s | 76%下降 |
关键优化点包括:
- 用ConcurrentDictionary替换Hashtable
- 引入ObjectPool复用网关连接
- 异步化日志写入
5. 常见问题排查指南
5.1 短信发送失败排查流程
- 检查网关状态:
csharp复制telnet smsgateway.example.com 8000 - 验证账号余额:
bash复制echo "BALANCE" | nc smsgateway.example.com 8000 - 分析日志序列:
- 搜索关键字:"ConnectionReset", "Timeout", "InvalidResponse"
5.2 编码问题典型表现
当遇到接收方显示乱码时,通常是以下原因之一:
- 数据库字段是varchar但内容包含Unicode字符
- 网关协议头未正确设置:
csharp复制byte[] header = new byte[] { 0x00, 0x03, // 协议版本 0x00, 0x08, // UTF-8编码标识 ... };
5.3 高并发场景下的线程安全
原始代码中的静态队列存在竞争条件风险,改造方案:
csharp复制// 旧代码(非线程安全)
private static Queue<SmsTask> _queue;
// 新方案
private static BlockingCollection<SmsTask> _queue = new(
new ConcurrentQueue<SmsTask>(),
boundedCapacity: 10000);
6. 扩展应用场景
6.1 与MES系统集成案例
在某汽车零部件工厂,我们将企信通改造为:
- 设备异常自动告警
- 质检结果实时推送
- 生产批次状态查询
关键改进点是增加了Modbus TCP协议解析模块,使PLC设备也能触发短信。
6.2 二次开发接口设计
建议的扩展接口:
csharp复制public interface ISmsPlugin {
string TransformContent(string raw);
bool ShouldDeliver(SmsContext ctx);
void OnResponseReceived(SmsResponse res);
}
典型应用场景:
- 敏感信息脱敏
- 发送时段控制
- 送达回执处理
这套代码最让我自豪的不是技术本身,而是它展现的务实设计哲学:用20%的核心代码解决80%的实际问题。十年间我见过太多过度设计的通信中间件,而这个不足3000行的实现仍在多个生产环境稳定运行。
