1. CodeWF.EventBus

EventBus(事件总线),用于解耦模块之间的通讯。本库(CodeWF.EventBus)适用于进程内消息传递(无其他外部依赖),与大家普遍使用的MediatR通知功能类似,但MediatR库侧重于ASP.NET Core设计使用,本库优势:

  1. 设计可在各种模板项目使用,如 WPF、Winform、Avalonia UI、ASP.NET Core 等。
  2. 支持使用了 IOC 容器的项目,当然也支持未使用任何 IOC 容器的模板项目。
  3. 参考MASA Framework增强消息处理能力:
[Event]
public class MessageHandler
{
private readonly ITimeService timeService; public MessageHandler(ITimeService timeService)
{
this.timeService = timeService;
} [EventHandler(Order = 3)]
public void ReceiveAutoCreateProductMessage3(CreateProductMessage message)
{
AddLog($"MessageHandler Received message 3 \"{message}\"");
} [EventHandler(Order = 1)]
public void ReceiveAutoDeleteProductMessage(DeleteProductMessage message)
{
AddLog($"MessageHandler Received message \"{message}\"");
} [EventHandler(Order = 2)]
public void ReceiveAutoCreateProductMessage2(CreateProductMessage message)
{
AddLog($"MessageHandler Received message 2 \"{message}\"");
} private void AddLog(string message)
{
Console.WriteLine($"{timeService.GetTime()}: {message}\r\n");
}
}

2. 怎么使用事件总线?

首先请搜索 NuGet 包CodeWF.EventBus并安装,下面细说使用方法。

2.1. 添加事件总线

2.1.1. 使用了 IOC

如果是 ASP.NET Core 程序,比如 MVC、Razor Pages、Blazor Server 等,,在Program中添加如下代码:

// ....

// 1、注册事件总线,将标注`EventHandler`特性方法的类采用单例方式注入IOC容器
EventBusExtensions.AddEventBus(
(t1, t2) => builder.Services.AddSingleton(t1, t2),
t => builder.Services.AddSingleton(t),
typeof(Program).Assembly); var app = builder.Build(); // ... // 2、将上面已经注入IOC容器的类取出、关联处理方法到事件总线管理
EventBusExtensions.UseEventBus((t) => app.Services.GetRequiredService(t), typeof(Program).Assembly); // ...
  • AddEventBus方法会扫描传入的程序集列表,将标注Event特性的类下又标注EventHandler特性方法的类采用单例方式注入 IOC 容器。
  • UseEventBus方法会将上一步注入的类通过 IOC 单例获取到实例,将实例的消息处理方法注册到消息管理队列中去,待收到消息发布时,会从消息管理队列中查找消息处理方法并调用,达到消息通知的功能。

如果使用的其他 IOC,比如 WPF 中使用了 Prism 框架,写法如下:

protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
IContainer? container = containerRegistry.GetContainer(); // ... // Register EventBus
EventBusExtensions.AddEventBus(
(t1,t2)=> containerRegistry.RegisterSingleton(t1,t2),
t=> containerRegistry.RegisterSingleton(t),
typeof(App).Assembly); // ... // Use EventBus
EventBusExtensions.UseEventBus(t => container.Resolve(t), typeof(App).Assembly);
}

根据 IOC 注册单例、获取服务的 API 不同,做相应修改即可。

2.1.2. 未使用 IOC

未使用 IOC 容器,比如默认的 WPF、Winform、AvaloniaUI、控制台程序不包含 IOC 容器,不做事件服务注册操作,功能使用上和使用IOC只差自动订阅功能,其他功能一样。

2.2. 定义消息(事件类型)

消息即需要发布或订阅的事件类型,消息需要继承自CodeWF.EventBus.Message

public class CreateProductMessage : CodeWF.EventBus.Message
{
public string Name { get; } public CreateProductMessage(object sender, string name) : base(sender)
{
Name = name;
} public override string ToString()
{
return $"Create product message ->Product name:{Name}";
}
} public class DeleteProductMessage : CodeWF.EventBus.Message
{
public string Id { get; } public DeleteProductMessage(object sender, string id) : base(sender)
{
Id = id;
} public override string ToString()
{
return $"Delete product message ->Product ID:{Id}";
}
}

2.3. 订阅消息(事件)

2.3.1. 自动订阅

B/S程序中,一般将事件处理程序单独封装到一个类中,如下代码:

[Event]
public class MessageHandler
{
private readonly ITimeService timeService; public MessageHandler(ITimeService timeService)
{
this.timeService = timeService;
} [EventHandler(Order = 3)]
public void ReceiveAutoCreateProductMessage3(CreateProductMessage message)
{
AddLog($"MessageHandler Received message 3 \"{message}\"");
} [EventHandler(Order = 1)]
public void ReceiveAutoDeleteProductMessage(DeleteProductMessage message)
{
AddLog($"MessageHandler Received message \"{message}\"");
} [EventHandler(Order = 2)]
public void ReceiveAutoCreateProductMessage2(CreateProductMessage message)
{
AddLog($"MessageHandler Received message 2 \"{message}\"");
}
}
  • MessageHandler添加了Event特性,在 IOC 注入时标识为可以做为单例注入。
  • 标注了EventHandler特性的方法拥有处理消息的能力,该方法只能有一个事件类型参数。

使用 IOC 容器的程序会自动将标注Event特性的类做为单例注入容器,事件总线收到消息通知时自动查找标注EventHandle特性的方法进行调用,达到消息通知的功能。

2.3.2. 手动订阅

对于未标注Event特性的类,可手动注册消息处理程序,如下图是未使用 IOC,手动注册示例:

internal class MessageHandler
{
internal void ManuSubscribe()
{
Messenger.Default.Subscribe<CreateProductMessage>(this, ReceiveManuCreateProductMessage);
Messenger.Default.Subscribe<DeleteProductMessage>(this, ReceiveManuDeleteProductMessage);
} void ReceiveManuCreateProductMessage(CreateProductMessage message)
{
AddLog($"Received manually registered \"{message}\"");
} void ReceiveManuDeleteProductMessage(DeleteProductMessage message)
{
AddLog($"Received manually registered \"{message}\"");
}
}

上面挨个注册处理方法有时会过于啰嗦,可以简化:

internal class MessageHandler
{
internal void AutoSubscribe()
{
Messenger.Default.Subscribe(this);
} [EventHandler(Order = 3)]
private void ReceiveAutoCreateProductMessage3(CreateProductMessage message)
{
AddLog($"Received automatic subscription message 3 \"({message}\"");
} [EventHandler(Order = 1)]
private void ReceiveAutoDeleteProductMessage(DeleteProductMessage message)
{
AddLog($"Received automatic subscription message \"{message}\"");
} [EventHandler(Order = 2)]
private void ReceiveAutoCreateProductMessage2(CreateProductMessage message)
{
AddLog($"Received automatic subscription message 2 \"{message}\"");
}
}

使用了 IOC,可以注入IMessenger服务替换Messenger.Default使用,MessengerIMessenger接口的默认实现,Messenger.Default是单例引用。

public class MessageTestViewModel : ViewModelBase
{
private readonly IMessenger _messenger; public MessageTestViewModel(IMessenger messenger)
{
_messenger = messenger;
_messenger.Subscribe(this);
} [EventHandler]
public void ReceiveEventBusMessage(TestMessage message)
{
_notificationService?.Show("CodeWF EventBus",
$"模块【Test】收到{nameof(TestMessage)},Name: {message.Name}, Time: {message.CurrentTime}");
}
}

手动订阅可以在 WPF 的 ViewModel 中使用(代码如上),也可以在 IOC 其他生命周期的服务中使用:

public class TimeService : ITimeService
{
private readonly IMessenger _messenger; public TimeService(IMessenger messenger)
{
_messenger = messenger; _messenger.Subscribe(this);
} [EventHandler]
public void ReceiveEventBusMessage(TestMessage message)
{
}
}

手动注册可运用在无法或不需要单例注入的情况使用。

2.4. 发布消息

发布就比较简单:

_messenger.Publish(this, new TestMessage(this, nameof(MessageTestViewModel), TestClass.CurrentTime()));

比如在B/S控制器的Action使用:

[ApiController]
[Route("[controller]")]
public class EventController : ControllerBase
{
private readonly ILogger<EventController> _logger;
private readonly IMessenger _messenger; public EventController(ILogger<EventController> logger, IMessenger messenger)
{
_logger = logger;
_messenger = messenger;
} [HttpPost]
public void Add()
{
_messenger.Publish(this, new CreateProductMessage(this, $"{DateTime.Now:HHmmss}号产品"));
} [HttpDelete]
public void Delete()
{
_messenger.Publish(this, new DeleteProductMessage(this, $"{DateTime.Now:HHmmss}号"));
}
}

WPF/Avalonia UIViewModel中使用:

public class MessageTestViewModel : ViewModelBase
{
private readonly IMessenger _messenger; public MessageTestViewModel(IMessenger messenger)
{
_messenger = messenger;
} public Task ExecuteEventBusAsync()
{
_messenger.Publish(this, new TestMessage(this, nameof(MessageTestViewModel), TestClass.CurrentTime()));
return Task.CompletedTask;
}
}

2.5. 取消订阅消息(事件)

支持消息处理程序的注销:

  1. 注销指定处理程序:Messenger.Default.Unsubscribe<CreateProductMessage>(this, ReceiveManuCreateProductMessage)
  2. 注销指定类的所有处理程序:Messenger.Default.Unsubscribe(this)

3. 总结

CodeWF.EventBus,一款灵活的事件总线库,实现模块间解耦通信。支持多种.NET 项目类型,如 Avalonia UI、WPF、WinForms、ASP.NET Core 等。采用简洁设计,轻松实现事件的发布与订阅。通过有序的消息处理,确保事件得到妥善处理。

简化您的代码,提升系统可维护性。

立即体验 CodeWF.EventBus,让事件处理更加高效!

仓库地址 https://github.com/dotnet9/CodeWF.EventBus,具体使用可参考Demo如下:

  1. 控制台:ConsoleDemo
  2. WPF: WPFDemo
  3. AvaloniaUI + Prism:Tools.CodeWF
  4. Web API:WebAPIDemo

开发过程中参考不少开源项目,他们是:

  1. Messenger | MvvmCross
  2. Prism.Events
  3. MediatR
  4. MASA Framework

CodeWF.EventBus:轻量级事件总线,让通信更流畅的更多相关文章

  1. ABP EventBus(事件总线)

    事件总线就是订阅/发布模式的一种实现    事件总线就是为了降低耦合 1.比如在winform中  到处都是事件 触发事件的对象  sender 事件的数据    e 事件的处理逻辑  方法体 通过E ...

  2. EventBus事件总线(牛x版)

    事件总线: public interface IEventBus { void Trigger<TEvent>(TEvent eventData, string topic = null) ...

  3. ABP之事件总线(3)

    承接上一篇时间总线的学习,在上一篇中我们实现了取消显式注册事件的方式,采用使用反射的方式.这样的好处可以解除Publisher和Scriber的显式依赖,但是问题又来了,因为我们只有Publisher ...

  4. C#事件总线

    目录 简介 实现事件总线 定义事件基类 定义事件参数基类 定义EventBus 使用事件总线 事件及事件参数 定义发布者 定义订阅者 实际使用 总结 参考资料 简介 事件总线是对发布-订阅模式的一种实 ...

  5. .Net 事件总线之Autofac解耦

    事件总线是通过一个中间服务,剥离了常规事件的发布与订阅(消费)强依赖关系的一种技术实现.事件总线的基础知识可参考圣杰的博客[事件总线知多少] 本片博客不再详细概述事件总线基础知识,核心点放置使用Aut ...

  6. Vue.js 2.x中事件总线(EvevntBus)及element-ui中全屏loading的使用

    事件总线(Event Bus)可以在vue项目的index.js文件中创建,也可以在一个独立的.vue文件中创建.使用时,在各个子组件中引入该组件即可. 项目中的全屏loading较多时,可以在根组件 ...

  7. .NET 事件总线,简化项目、类库、线程、服务等之间的通信,代码更少,质量更好。‎

    Jaina .NET 事件总线,简化项目.类库.线程.服务等之间的通信,代码更少,质量更好.‎ 安装 Package Manager Install-Package Jaina .NET CLI do ...

  8. Android学习系列(43)--使用事件总线框架EventBus和Otto

    事件总线框架 针对事件提供统一订阅,发布以达到组件间通信的解决方案. 原理 观察者模式. EventBus和Otto 先看EventBus的官方定义: Android optimized event ...

  9. Guava: 事件总线EventBus

    EventBus 直译过来就是事件总线,它使用发布订阅模式支持组件之间的通信,不需要显式地注册回调,比观察者模式更灵活,可用于替换Java中传统的事件监听模式,EventBus的作用就是解耦,它不是通 ...

  10. EventBus 事件总线 案例

    简介 地址:https://github.com/greenrobot/EventBus EventBus是一个[发布 / 订阅]的事件总线.简单点说,就是两人[约定]好怎么通信,一人发布消息,另外一 ...

随机推荐

  1. java:找不到符号(使用lombok)

    1.背景 启动报错: Error:(76, 34) java: 找不到符号 符号: 方法 getOrderNo() 位置: 类型为XXXXX.request.coupon.SubmitOrderObj ...

  2. Notes for uc/OS-III User Guide

    1. Architecture F2-1(1) The application code consists of project or product files. For convenience, ...

  3. Windows中Powershell中的 rm -rf 等效命令

    Remove-Item  -Recurse  -Force  <要删除的目录> 可以简写为: rm -r -fo  <要删除目录>

  4. 从源码分析 SpringBoot 的 LoggingSystem → 它是如何绑定日志组件的

    开心一刻 今天心情不好,想约哥们喝点 我:心情不好,给你女朋友说一声,来我家,过来喝点 哥们:行!我给她说一声 我:你想吃啥?我点外卖 哥们:你俩定吧,我已经让她过去了 我:???我踏马让你过来!和她 ...

  5. 性能、成本与 POSIX 兼容性比较: JuiceFS vs EFS vs FSx for Lustre

    JuiceFS 是一款为云环境设计的分布式高性能文件系统.Amazon EFS 易于使用且可伸缩,适用于多种应用.Amazon FSx for Lustre 则是面向处理快速和大规模数据工作负载的高性 ...

  6. RuleLinKClient - 再也不担心表达引擎宕机了

    原来有这么多时间 六月的那么一天,天气比以往时候都更凉爽,媳妇边收拾桌子,边漫不经心的对我说:你最近好像都没怎么阅读了. 正刷着新闻我,如同被一记响亮的晴空霹雳击中一般,不知所措.是了,最近几月诸事凑 ...

  7. elementUI的日期时间控件实现分钟固定步长

    日期时间控件实现固定步长,例如5分钟间隔.10分钟间隔 一.效果图 二.实现方法 通过日期时间控件的箭头来控制步长的显示与否,具体代码详见

  8. 鸿蒙(HarmonyOS)常见的三种弹窗方式

    最近有一个想法,做一个针对鸿蒙官方API的工具箱项目,介绍常用的控件,以及在项目中如何使用,今天介绍Harmony中如何实现弹窗功能. 警告弹窗 警告弹窗是一个App中非常常用的弹窗,例如: 删除一条 ...

  9. CTC联结时间分类算法: 连接主义时间分类: 用递归神经网络标记未分割序列数据《Connectionist Temporal Classification: Labelling Unsegmented Sequence Data with Recurrent Neural Networks》(语音、文本识别、RNN端到端训练序列数据的方法)

    11月6号例会汇报. 糊弄的看了一个算法-CTC算法,没有汇报论文,因为没看论文(我导知道后,应该会锤死我...) 当然,汇报完之后,被我导腾讯会议通过网线批了我一顿,PPT做的太烂了!字太多,听不到 ...

  10. Asp.net Core – CSS Isolation

    前言 ASP.NET Core 6.0 Razor Pages 新功能, 我是用 webpack 做打包的, 所以这个对我没有什么帮助. 但是了解一下是可以的. 希望 .NET 会继续发展的更好, 多 ...