1. 程式人生 > 其它 >.NET 事件匯流排,簡化專案、類庫、執行緒、服務等之間的通訊,程式碼更少,質量更好。‎

.NET 事件匯流排,簡化專案、類庫、執行緒、服務等之間的通訊,程式碼更少,質量更好。‎

Jaina

.NET 事件匯流排,簡化專案、類庫、執行緒、服務等之間的通訊,程式碼更少,質量更好。‎

安裝

Install-Package Jaina
dotnet add package Jaina

快速入門

我們在主頁上有不少例子,這是讓您入門的第一個:

  1. 定義事件訂閱者 ToDoEventSubscriber
// 實現 IEventSubscriber 介面
public class ToDoEventSubscriber : IEventSubscriber
{
    private readonly ILogger<ToDoEventSubscriber> _logger;
    public ToDoEventSubscriber(ILogger<ToDoEventSubscriber> logger)
    {
        _logger = logger;
    }
    // 標記 [EventSubscribe(事件 Id)] 特性
    [EventSubscribe("ToDo:Create")]
    public async Task CreateToDo(EventHandlerExecutingContext context)
    {
        var todo = context.Source;
        _logger.LogInformation("建立一個 ToDo:{Name}", todo.Payload);
        await Task.CompletedTask;
    }
}
  1. 建立控制器 ToDoController,依賴注入 IEventPublisher 服務:
[Route("api/[controller]/[action]")]
[ApiController]
public class ToDoController : ControllerBase
{
    // 依賴注入事件釋出者 IEventPublisher
    private readonly IEventPublisher _eventPublisher;
    public ToDoController(IEventPublisher eventPublisher)
    {
        _eventPublisher = eventPublisher;
    }
    // 釋出 ToDo:Create 訊息
    [HttpPost]
    public async Task CreateDoTo(string name)
    {
        await _eventPublisher.PublishAsync(new ChannelEventSource("ToDo:Create", name));
    }
}
  1. Startup.cs 註冊 EventBus 服務:
public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        // 註冊 EventBus 服務
        services.AddEventBus(buidler =>
        {
            // 註冊 ToDo 事件訂閱者
            buidler.AddSubscriber<ToDoEventSubscriber>();
        });
        // ....
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        // ....
    }
}
  1. 執行專案:
info: Jaina.Samples.ToDoEventSubscriber[0]
      建立一個 ToDo:Jaina

高階教程

1. 自定義事件源 IEventSource

Jaina 使用 IEventSource 作為訊息載體,任何實現該介面的類都可以充當訊息載體。

如需自定義,只需實現 IEventSource 介面即可:

public class ToDoEventSource : IEventSource
{
    // 自定義屬性
    public string ToDoName { get; }

    /// <summary>
    /// 事件 Id
    /// </summary>
    public string EventId { get; }

    /// <summary>
    /// 事件承載(攜帶)資料
    /// </summary>
    public object Payload { get; }

    /// <summary>
    /// 取消任務 Token
    /// </summary>
    /// <remarks>用於取消本次訊息處理</remarks>
    public CancellationToken CancellationToken { get; }

    /// <summary>
    /// 事件建立時間
    /// </summary>
    public DateTime CreatedTime { get; } = DateTime.UtcNow; 
}

使用:

await _eventPublisher.PublishAsync(new ToDoEventSource {
    EventId = "ToDo:Create",
    ToDoName = "我的 ToDo Name"
});

2. 自定義事件源儲存器 IEventSourceStorer

Jaina 預設採用 Channel 作為事件源 IEventSource 儲存器,開發者可以使用任何訊息佇列元件進行替換,如 Kafka、RabbitMQ、ActiveMQ 等,也可以使用部分資料庫 Redis、SQL Server、MySql 實現。

如需自定義,只需實現 IEventSourceStorer 介面即可:

public class RedisEventSourceStorer : IEventSourceStorer
{
    private readonly IRedisClient _redisClient;

    public RedisEventSourceStorer(IRedisClient redisClient)
    {
        _redisClient = redisClient;
    }

    // 往 Redis 中寫入一條
    public async ValueTask WriteAsync(IEventSource eventSource, CancellationToken cancellationToken)
    {
        await _redisClient.WriteAsync(...., cancellationToken);
    }
    
    // 從 Redis 中讀取一條
    public async ValueTask<IEventSource> ReadAsync(CancellationToken cancellationToken)
    {
       return await _redisClient.ReadAsync(...., cancellationToken);
    }
}

最後,在註冊 EventBus 服務中替換預設 IEventSourceStorer

services.AddEventBus(buidler =>
{
    // 替換事件源儲存器
    buidler.ReplaceStorer<RedisEventSourceStorer>();
});

3. 自定義事件釋出者 IEventPublisher

Jaina 預設內建基於 Channel 的事件釋出者 ChannelEventPublisher

如需自定義,只需實現 IEventPublisher 介面即可:

public class ToDoEventPublisher : IEventPublisher
{
    private readonly IEventSourceStorer _eventSourceStorer;
    
    public ChannelEventPublisher(IEventSourceStorer eventSourceStorer)
    {
        _eventSourceStorer = eventSourceStorer;
    }
    
    public async Task PublishAsync(IEventSource eventSource)
    {
        await _eventSourceStorer.WriteAsync(eventSource, eventSource.CancellationToken);
    }
}

最後,在註冊 EventBus 服務中替換預設 IEventPublisher

services.AddEventBus(buidler =>
{
    // 替換事件源儲存器
    buidler.ReplacePublisher<ToDoEventPublisher>();
});

4. 新增事件執行監視器 IEventHandlerMonitor

Jaina 提供了 IEventHandlerMonitor 監視器介面,實現該介面可以監視所有訂閱事件,包括 執行之前、執行之後,執行異常,共享上下文資料

如新增 ToDoEventHandlerMonitor

public class ToDoEventHandlerMonitor : IEventHandlerMonitor
{
    private readonly ILogger<ToDoEventHandlerMonitor> _logger;
    public ToDoEventHandlerMonitor(ILogger<ToDoEventHandlerMonitor> logger)
    {
        _logger = logger;
    }

    public Task OnExecutingAsync(EventHandlerExecutingContext context)
    {
        _logger.LogInformation("執行之前:{EventId}", context.Source.EventId);
        return Task.CompletedTask;
    }

    public Task OnExecutedAsync(EventHandlerExecutedContext context)
    {
        _logger.LogInformation("執行之後:{EventId}", context.Source.EventId);

        if (context.Exception != null)
        {
            _logger.LogError(context.Exception, "執行出錯啦:{EventId}", context.Source.EventId);
        }

        return Task.CompletedTask;
    }
}

最後,在註冊 EventBus 服務中註冊 ToDoEventHandlerMonitor

services.AddEventBus(buidler =>
{
    // 主鍵事件執行監視器
    buidler.AddMonitor<ToDoEventHandlerMonitor>();
});

5. 自定義事件處理程式執行器 IEventHandlerExecutor

Jaina 提供了 IEventHandlerExecutor 執行器介面,可以讓開發者自定義事件處理函式執行策略,如 超時控制,失敗重試、熔斷等等

如新增 RetryEventHandlerExecutor

public class RetryEventHandlerExecutor : IEventHandlerExecutor
{
    public async Task ExecuteAsync(EventHandlerExecutingContext context, Func<EventHandlerExecutingContext, Task> handler)
    {
        // 如果執行失敗,每隔 1s 重試,最多三次
        await Retry(async () => {
            await handler(context);
        }, 3, 1000);
    }
}

最後,在註冊 EventBus 服務中註冊 RetryEventHandlerExecutor

services.AddEventBus(buidler =>
{
    // 主鍵事件執行監視器
    buidler.AddExecutor<RetryEventHandlerExecutor>();
});

文件

您可以在主頁找到 Jaina 文件。

貢獻

該儲存庫的主要目的是繼續發展 Jaina 核心,使其更快、更易於使用。Jaina 的開發在 Gitee 上公開進行,我們感謝社群貢獻錯誤修復和改進。

許可證

Jaina 採用 MulanPSL-2.0 開源許可證。

Copyright (c) 2020-2021 百小僧, Baiqian Co.,Ltd.
Jaina is licensed under Mulan PSL v2.
You can use this software according to the terms andconditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
            https://gitee.com/dotnetchina/Jaina/blob/master/LICENSE
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUTWARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
https://www.chinadot.net