想象一下,当你的工厂有成百上千个传感器需要实时监控时,传统的轮询方式已经力不从心。据统计,采用事件驱动架构的系统在高并发场景下性能提升可达300%以上,响应时间缩短至毫秒级。今天,我们就用C#手把手构建一个完整的IoT设备监控系统,让你彻底掌握事件驱动的精髓!
在传统的IoT系统开发中,我们经常遇到这些痛点:
事件驱动架构完美解决了这些问题,让系统变得松耦合、高性能、易扩展。
graph TB
subgraph "UI Layer 用户界面层"
MainForm[主窗体<br/>FrmMain]
DeviceForm[设备控制窗体<br/>FrmDeviceControl]
end
subgraph "Service Layer 服务层"
DeviceManager[设备管理器<br/>DeviceManager]
DataLogger[数据记录服务<br/>DataLogger]
end
subgraph "Event System 事件系统"
EventBus[事件总线<br/>EventBus]
IEvent[事件接口<br/>IEvent]
BaseEvent[事件基类<br/>BaseEvent]
end
subgraph "Device Layer 设备层"
IDevice[设备接口<br/>IDevice]
TempSensor[温度传感器<br/>TemperatureSensor]
HumiSensor[湿度传感器<br/>HumiditySensor]
end
subgraph "Event Types 事件类型"
DeviceEvents[设备事件<br/>DeviceEvents]
SystemEvents[系统事件<br/>SystemEvents]
end
MainForm --> EventBus
DeviceForm --> EventBus
DeviceManager --> EventBus
DataLogger --> EventBus
TempSensor --> EventBus
HumiSensor --> EventBus
TempSensor -.-> IDevice
HumiSensor -.-> IDevice
DeviceEvents -.-> BaseEvent
SystemEvents -.-> BaseEvent
BaseEvent -.-> IEvent
DeviceManager --> TempSensor
DeviceManager --> HumiSensor
首先,我们定义事件的基础接口和抽象类:
C#/// <summary>
/// 事件基础接口 - 所有事件的根接口
/// </summary>
public interface IEvent
{
DateTime Timestamp { get; } // 事件发生时间
string EventId { get; } // 唯一事件标识
}
/// <summary>
/// 事件基础抽象类 - 提供通用实现
/// </summary>
public abstract class BaseEvent : IEvent
{
public DateTime Timestamp { get; }
public string EventId { get; }
protected BaseEvent()
{
Timestamp = DateTime.Now; // 自动记录时间戳
EventId = Guid.NewGuid().ToString(); // 生成唯一ID
}
}
设计亮点:
事件总线是整个系统的核心,负责事件的订阅、发布和分发:
C#public interface IEventBus
{
void Subscribe<T>(Action<T> handler) where T : IEvent; // 订阅事件
void Unsubscribe<T>(Action<T> handler) where T : IEvent; // 取消订阅
void Publish<T>(T eventItem) where T : IEvent; // 发布事件
void Clear(); // 清空所有订阅
}
/// <summary>
/// 线程安全的事件总线实现
/// </summary>
public class EventBus : IEventBus
{
private readonly ConcurrentDictionary<Type, List<object>> _handlers;
private readonly object _lock = new object();
public EventBus()
{
_handlers = new ConcurrentDictionary<Type, List<object>>();
}
public void Subscribe<T>(Action<T> handler) where T : IEvent
{
lock (_lock)
{
var eventType = typeof(T);
if (!_handlers.ContainsKey(eventType))
{
_handlers[eventType] = new List<object>();
}
_handlers[eventType].Add(handler);
}
}
public void Publish<T>(T eventItem) where T : IEvent
{
var eventType = typeof(T);
if (_handlers.ContainsKey(eventType))
{
var handlers = _handlers[eventType].ToList();
// 关键:确保在UI线程上执行,避免跨线程异常
if (Application.OpenForms.Count > 0)
{
var mainForm = Application.OpenForms[0];
if (mainForm.InvokeRequired)
{
mainForm.Invoke(new Action(() => ExecuteHandlers(handlers, eventItem)));
}
else
{
ExecuteHandlers(handlers, eventItem);
}
}
}
}
private void ExecuteHandlers<T>(List<object> handlers, T eventItem) where T : IEvent
{
foreach (var handler in handlers)
{
try
{
((Action<T>)handler)(eventItem);
}
catch (Exception ex)
{
// 重要:异常隔离,一个处理器异常不影响其他处理器
System.Diagnostics.Debug.WriteLine($"事件处理器执行异常: {ex.Message}");
}
}
}
}
核心技巧:
ConcurrentDictionary
保证线程安全设计一个通用的设备接口,让所有IoT设备都遵循统一标准:
C#/// <summary>
/// 统一设备接口 - 所有IoT设备的标准
/// </summary>
public interface IDevice : IDisposable
{
string DeviceId { get; } // 设备唯一标识
string DeviceName { get; } // 设备名称
bool IsConnected { get; } // 连接状态
bool IsRunning { get; } // 运行状态
void Initialize(IEventBus eventBus); // 初始化事件总线
void Start(); // 启动设备
void Stop(); // 停止设备
void Connect(); // 连接设备
void Disconnect(); // 断开设备
}
C#/// <summary>
/// 温度传感器 - 事件驱动的设备实现典范
/// </summary>
public class TemperatureSensor : IDevice
{
private readonly Random _random;
private IEventBus _eventBus;
private CancellationTokenSource _cancellationTokenSource;
private Task _dataGenerationTask;
public string DeviceId { get; }
public string DeviceName { get; }
public bool IsConnected { get; private set; }
public bool IsRunning { get; private set; }
public TemperatureSensor(string deviceId, string deviceName)
{
DeviceId = deviceId;
DeviceName = deviceName;
_random = new Random();
}
public void Initialize(IEventBus eventBus)
{
_eventBus = eventBus ?? throw new ArgumentNullException(nameof(eventBus));
}
public void Start()
{
if (!IsConnected) Connect();
if (!IsRunning)
{
IsRunning = true;
_cancellationTokenSource = new CancellationTokenSource();
_dataGenerationTask = Task.Run(GenerateData, _cancellationTokenSource.Token);
// 发布系统日志事件
_eventBus?.Publish(new SystemLogEvent($"温度传感器 {DeviceName} 开始采集数据", LogLevel.Info));
}
}
/// <summary>
/// 核心方法:异步数据生成,持续发布事件
/// </summary>
private async Task GenerateData()
{
double currentTemp = 25.0; // 基础温度
while (!_cancellationTokenSource.Token.IsCancellationRequested)
{
try
{
// 模拟真实的温度波动
currentTemp += (_random.NextDouble() - 0.5) * 2.0;
currentTemp = Math.Max(-10, Math.Min(50, currentTemp));
// 发布数据更新事件 - 这里体现了事件驱动的核心
_eventBus?.Publish(new DeviceDataUpdatedEvent(
DeviceId, DeviceName, Math.Round(currentTemp, 1), "°C", "Temperature"));
// 智能报警逻辑
if (currentTemp > 35)
{
_eventBus?.Publish(new DeviceAlarmEvent(
DeviceId, DeviceName, $"温度过高: {currentTemp:F1}°C", AlarmLevel.Warning));
}
await Task.Delay(2000, _cancellationTokenSource.Token);
}
catch (OperationCanceledException)
{
break; // 正常取消
}
catch (Exception ex)
{
// 异常处理也通过事件机制
_eventBus?.Publish(new SystemLogEvent($"温度传感器数据生成异常: {ex.Message}", LogLevel.Error));
await Task.Delay(5000, _cancellationTokenSource.Token);
}
}
}
}
定义完整的事件体系,覆盖设备监控的各个方面:
C#/// <summary>
/// 设备数据更新事件 - 最频繁的事件类型
/// </summary>
public class DeviceDataUpdatedEvent : BaseEvent
{
public string DeviceId { get; }
public string DeviceName { get; }
public double Value { get; }
public string Unit { get; }
public string DataType { get; }
public DeviceDataUpdatedEvent(string deviceId, string deviceName, double value, string unit, string dataType)
{
DeviceId = deviceId;
DeviceName = deviceName;
Value = value;
Unit = unit;
DataType = dataType;
}
}
/// <summary>
/// 设备报警事件 - 关键业务事件
/// </summary>
public class DeviceAlarmEvent : BaseEvent
{
public string DeviceId { get; }
public string DeviceName { get; }
public string AlarmMessage { get; }
public AlarmLevel Level { get; }
public DeviceAlarmEvent(string deviceId, string deviceName, string alarmMessage, AlarmLevel level)
{
DeviceId = deviceId;
DeviceName = deviceName;
AlarmMessage = alarmMessage;
Level = level;
}
}
public enum AlarmLevel
{
Info, // 信息
Warning, // 警告
Error, // 错误
Critical // 严重
}
在主窗体中展示事件驱动的威力:
C#public partial class FrmMain : Form
{
private readonly IEventBus _eventBus;
private readonly DeviceManager _deviceManager;
private readonly Dictionary<string, double> _latestDeviceData;
public FrmMain()
{
InitializeComponent();
_eventBus = new Events.EventBus();
_deviceManager = new DeviceManager(_eventBus);
_latestDeviceData = new Dictionary<string, double>();
SubscribeToEvents(); // 订阅所有感兴趣的事件
InitializeDevices(); // 初始化设备
}
/// <summary>
/// 事件订阅 - 系统响应能力的核心
/// </summary>
private void SubscribeToEvents()
{
_eventBus.Subscribe<DeviceDataUpdatedEvent>(OnDeviceDataUpdated);
_eventBus.Subscribe<DeviceConnectionChangedEvent>(OnDeviceConnectionChanged);
_eventBus.Subscribe<DeviceAlarmEvent>(OnDeviceAlarm);
_eventBus.Subscribe<SystemLogEvent>(OnSystemLog);
}
/// <summary>
/// 处理设备数据更新 - 实时响应数据变化
/// </summary>
private void OnDeviceDataUpdated(DeviceDataUpdatedEvent eventData)
{
_latestDeviceData[eventData.DeviceId] = eventData.Value;
UpdateDeviceList(); // 自动更新界面
// 添加到数据日志列表
var logItem = new ListViewItem(eventData.Timestamp.ToString("HH:mm:ss"));
logItem.SubItems.Add(eventData.DeviceName);
logItem.SubItems.Add(eventData.DataType);
logItem.SubItems.Add($"{eventData.Value:F1} {eventData.Unit}");
dataLogListView.Items.Insert(0, logItem);
// 性能优化:限制显示条数,避免内存泄漏
while (dataLogListView.Items.Count > 100)
{
dataLogListView.Items.RemoveAt(dataLogListView.Items.Count - 1);
}
}
/// <summary>
/// 处理设备报警 - 用户体验的关键
/// </summary>
private void OnDeviceAlarm(DeviceAlarmEvent eventData)
{
var logItem = new ListViewItem(eventData.Timestamp.ToString("HH:mm:ss"));
logItem.SubItems.Add(eventData.DeviceName);
logItem.SubItems.Add(eventData.Level.ToString());
logItem.SubItems.Add(eventData.AlarmMessage);
// 根据报警级别设置视觉提示
logItem.BackColor = eventData.Level switch
{
AlarmLevel.Warning => Color.Yellow,
AlarmLevel.Error => Color.Orange,
AlarmLevel.Critical => Color.Red,
_ => Color.White
};
alarmListView.Items.Insert(0, logItem);
// 系统托盘气泡提醒
notifyIcon.ShowBalloonTip(3000, "设备报警",
$"{eventData.DeviceName}: {eventData.AlarmMessage}",
ToolTipIcon.Warning);
}
}
async/await
ConcurrentDictionary
和锁机制Invoke
调度到UI线程这套架构可以广泛应用于:
通过这个完整的IoT监控系统,我们掌握了三个关键技术要点:
💡 想要完整源码? 这套事件驱动架构已经在多个企业项目中验证,如果你正在开发类似系统,这些代码模板绝对是你的效率神器!
🤝 分享交流: 你在项目中是如何处理设备管理和事件响应的?遇到过哪些技术难点?欢迎在评论区分享你的经验和问题!
觉得这篇文章对你有帮助?请转发给更多需要的C#开发同行,让我们一起构建更好的技术社区! 🚀
相关信息
通过网盘分享的文件:AppIotEvent.zip 链接: https://pan.baidu.com/s/1uP3YM65apVeyLmPuYH69Ww?pwd=a52k 提取码: a52k --来自百度网盘超级会员v9的分享
本文作者:技术老小子
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!