CodeWF.EventBus:轻量级事件总线,让通信更流畅

1. CodeWF.EventBus

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

  1. 设计可在各种模板项目使用,如WPF、Winform、AvaloniaUI、ASP.NET Core等,主要参考了Prism.Events设计;
  2. 参考MASA Framework增强消息处理能力:
internal class MessageHandler
{
    [EventHandler(Order = 3)]
    private void ReceiveAutoCreateProductMessage3(CreateProductMessage message)
    {
        AddLog($"收到自动订阅消息3({message}”");
    }

    [EventHandler(Order = 1)]
    private void ReceiveAutoDeleteProductMessage(DeleteProductMessage message)
    {
        AddLog($"收到自动订阅消息({message}”");
    }

    [EventHandler(Order = 2)]
    private void ReceiveAutoCreateProductMessage2(CreateProductMessage message)
    {
        AddLog($"收到自动订阅消息2({message}”");
    }
}

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 $"创建产品消息-》产品名称:{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 $"删除产品消息-》产品Id:{Id}";
    }
}

定义好消息,这里我们有两种方式使用事件总线,非IOC和IOC方式:

  1. 非IOC方式:需要安装CodeWF.EventBus包,适用于未使用IOC的模板程序,比如WPF、Winform、AvaloniaUI、控制台程序,当然ASP.NET Core也能用。
  2. IOC方式:需要安装CodeWF.AspNetCore.EventBus包,适合于在ASP.NET Core程序中使用。

2.1. 非IOC方式使用

适合于未使用IOC方式使用事件总线,比如在WPF、Winform、AvaloniaUI、控制台等程序中直接使用事件帮助类的静态实例,下面是使用步骤。

创建项目(不限于项目类型,比如控制台程序),通过NuGet引入CodeWF.EventBus包:

Install-Package CodeWF.EventBus -Version 1.0.1

创建消息处理程序,这里参考了Prism.Events设计,可订阅消息、取消订阅消息、发布消息,适合于手工指定处理方法:

internal class MessageHandler
{
    internal void ManuSubscribe()
    {
        Messenger.Default.Subscribe<CreateProductMessage>(this, ReceiveManuCreateProductMessage);
        Messenger.Default.Subscribe<DeleteProductMessage>(this, ReceiveManuDeleteProductMessage);
    }

    internal void ManuUnsubscribe()
    {
        Messenger.Default.Unsubscribe<CreateProductMessage>(this, ReceiveManuCreateProductMessage);
        Messenger.Default.Unsubscribe<DeleteProductMessage>(this, ReceiveManuDeleteProductMessage);
    }

    internal void Publish()
    {
        Messenger.Default.Publish(this, new CreateProductMessage(this, $"{DateTime.Now:HHmmss}号产品"));
        Messenger.Default.Publish(this, new DeleteProductMessage(this, $"{DateTime.Now:HHmmss}号"));
    }

    void ReceiveManuCreateProductMessage(CreateProductMessage message)
    {
        AddLog($"收到手动注册的{message}");
    }

    void ReceiveManuDeleteProductMessage(DeleteProductMessage message)
    {
        AddLog($"收到手动注册的{message}");
    }

    private void AddLog(string message)
    {
        Console.WriteLine($"{DateTime.Now:HH:mm:ss fff} {message}\r\n");
    }
}

最后是消息使用:

using ConsoleDemo.EventBus;

var handler = new MessageHandler();

Console.WriteLine("1、未注册时发布消息:");
handler.Publish();
Console.WriteLine();

Console.WriteLine("2、手动注册后发布消息:");
handler.ManuSubscribe();
handler.Publish();

Console.WriteLine("3、取消手动注册后发布消息:");
handler.ManuUnsubscribe();
handler.Publish();

Console.ReadKey();

如果消息较多,也可使用自动注册消息处理方法,我们修改处理程序:

internal class MessageHandler
{
    internal void AutoSubscribe()
    {
        Messenger.Default.Subscribe(this);
    }

    internal void AutoUnsubscribe()
    {
        Messenger.Default.Unsubscribe(this);
    }

    internal void Publish()
    {
        Messenger.Default.Publish(this, new CreateProductMessage(this, $"{DateTime.Now:HHmmss}号产品"));
        Messenger.Default.Publish(this, new DeleteProductMessage(this, $"{DateTime.Now:HHmmss}号"));
    }

    [EventHandler(Order = 3)]
    private void ReceiveAutoCreateProductMessage3(CreateProductMessage message)
    {
        AddLog($"收到自动订阅消息3({message}”");
    }

    [EventHandler(Order = 1)]
    private void ReceiveAutoDeleteProductMessage(DeleteProductMessage message)
    {
        AddLog($"收到自动订阅消息({message}”");
    }

    [EventHandler(Order = 2)]
    private void ReceiveAutoCreateProductMessage2(CreateProductMessage message)
    {
        AddLog($"收到自动订阅消息2({message}”");
    }

    private void AddLog(string message)
    {
        Console.WriteLine($"{DateTime.Now:HH:mm:ss fff} {message}\r\n");
    }
}

[EventHandler(Order = 0)] 定义消息的执行顺序。每个消息都可以匹配多个处理程序。一个类中可以有多个消息处理方法,可以订阅同一个消息,也可以订阅不同的消息。

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

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

消息使用:

using ConsoleDemo.EventBus;

var handler = new MessageHandler();

Console.WriteLine("1、未注册时发布消息:");
handler.Publish();
Console.WriteLine();

Console.WriteLine("2、自动注册后发布消息:");
handler.AutoSubscribe();
handler.Publish();

Console.WriteLine("3、取消自动注册后发布消息:");
handler.AutoUnsubscribe();
handler.Publish();

Console.ReadKey();

2.2. IOC方式使用

适合于在ASP.NET Core程序中使用,下面是使用步骤。

创建项目(ASP.NET Core模块项目,比如Web API、MVC、Razor Page、Blazor Server等),通过NuGet引入CodeWF.AspNetCore.EventBus:

Install-Package CodeWF.AspNetCore.EventBus -Version 1.0.1

创建消息处理程序,处理类中可以正常使用构造函数注入IOC服务:

public class MessageHandler
{
    private readonly ITimeService timeService;

    public MessageHandler(ITimeService timeService)
    {
        this.timeService = timeService;
    }
    [EventHandler(Order = 3)]
    public void ReceiveAutoCreateProductMessage3(CreateProductMessage message)
    {
        AddLog($"收到消息3({message}”");
    }

    [EventHandler(Order = 1)]
    public void ReceiveAutoDeleteProductMessage(DeleteProductMessage message)
    {
        AddLog($"收到消息({message}”");
    }

    [EventHandler(Order = 2)]
    public void ReceiveAutoCreateProductMessage2(CreateProductMessage message)
    {
        AddLog($"收到消息2({message}”");
    }

    private void AddLog(string message)
    {
        Console.WriteLine($"{timeService.GetTime()}: {message}\r\n");
    }
}
public interface ITimeService
{
    string GetTime();
}

public class TimeService : ITimeService
{
    public string GetTime()
    {
        return DateTime.Now.ToString("HH:mm:ss fff");
    }
}

在Program中注册事件总线:

using CodeWF.AspNetCore.EventBus;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

// 用于测试事件处理类正常使用IOC功能
builder.Services.AddSingleton<ITimeService, TimeService>();

// 1、注册事件总线,将标注`EventHandler`特性方法的类采用单例方式注入IOC容器
builder.Services.AddEventBus();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseAuthorization();
app.MapControllers();

// 2、将上面已经注入IOC容器的类取出、关联处理方法到事件总线管理
app.UseEventBus();

app.Run();

在控制器或其他服务可以发布消息,上面的处理程序会接收处理:

[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}号"));
    }
}

3. 总结

CodeWF.EventBus,一款灵活的事件总线库,实现模块间解耦通信。支持多种.NET项目类型,如WPF、WinForms、ASP.NET Core等。采用简洁设计,轻松实现事件的发布与订阅。通过有序的消息处理,确保事件得到妥善处理。简化您的代码,提升系统可维护性。立即体验CodeWF.EventBus,让事件处理更加高效!

仓库地址是https://github.com/dotnet9/CodeWF.EventBus,开发过程中参考不少开源项目,他们是:

  1. Prism.Events
  2. MediatR
  3. MASA Framework
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容