首頁>技術>

事件匯流排 是將訊息從傳送方傳輸到接收方的中介. 它在物件,服務和應用程式之間提供了一種鬆散耦合的通訊方式.

ABP框架提供了兩種事件匯流排型別;

釋出事件

以下介紹了兩種釋出本地事件的方法.

ILocalEventBus

可以注入 ILocalEventBus 並且使用釋出本地事件.

示例: 產品的存貨數量發生變化時釋出本地事件

using System;using System.Threading.Tasks;using Volo.Abp.DependencyInjection;using Volo.Abp.EventBus.Local;namespace AbpDemo{    public class MyService : ITransientDependency    {        private readonly ILocalEventBus _localEventBus;        public MyService(ILocalEventBus localEventBus)        {            _localEventBus = localEventBus;        }                public virtual async Task ChangeStockCountAsync(Guid productId, int newCount)        {            //TODO: IMPLEMENT YOUR LOGIC...                        //PUBLISH THE EVENT            await _localEventBus.PublishAsync(                new StockCountChangedEvent                {                    ProductId = productId,                    NewCount = newCount                }            );        }    }}

PublishAsync 方法需要一個引數:事件物件,它負責保持與事件相關的資料,是一個簡單的普通類:

using System;namespace AbpDemo{    public class StockCountChangedEvent    {        public Guid ProductId { get; set; }                public int NewCount { get; set; }    }}

即使你不需要傳輸任何資料也需要建立一個類(在這種情況下為空類).

實體/聚合根類

實體不能透過依賴注入注入服務,但是在實體/聚合根類中釋出本地事件是非常常見的.

示例: 在聚合根方法內釋出本地事件

using System;using Volo.Abp.Domain.Entities;namespace AbpDemo{    public class Product : AggregateRoot<Guid>    {        public string Name { get; set; }                public int StockCount { get; private set; }        private Product() { }        public Product(Guid id, string name)            : base(id)        {            Name = name;        }        public void ChangeStockCount(int newCount)        {            StockCount = newCount;                        //ADD an EVENT TO BE PUBLISHED            AddLocalEvent(                new StockCountChangedEvent                {                    ProductId = Id,                    NewCount = newCount                }            );        }    }}

AggregateRoot 類定義了 AddLocalEvent 來新增一個新的本地事件,事件在聚合根物件儲存(建立,更新或刪除)到資料庫時釋出.

如果實體釋出這樣的事件,以可控的方式更改相關屬性是一個好的實踐,就像上面的示例一樣 - StockCount只能由保證釋出事件的 ChangeStockCount 方法來更改.

IGeneratesDomainEvents 介面

實際上新增本地事件並不是 AggregateRoot 類獨有的. 你可以為任何實體類實現 IGeneratesDomainEvents. 但是 AggregateRoot 預設實現了它以簡化你的工作.

不建議為不是聚合根的實體實現此介面,因為它可能不適用於此類實體的某些資料庫提供程式. 例如它適用於EF Core,但不適用於MongoDB.

它是如何實現的?

呼叫 AddLocalEvent 不會立即釋出事件. 當你將更改儲存到資料庫時釋出該事件;

對於 EF Core, 它在 DbContext.SaveChanges 中釋出.對於 MongoDB, 它在你呼叫倉儲的 InsertAsync, UpdateAsync 或 DeleteAsync 方法時發由 (因為MongoDB沒有更改跟蹤系統).訂閱事件

一個服務可以實現 ILocalEventHandler<TEvent> 來處理事件.

示例: 處理上面定義的StockCountChangedEvent

using System.Threading.Tasks;using Volo.Abp.DependencyInjection;using Volo.Abp.EventBus;namespace AbpDemo{    public class MyHandler       : ILocalEventHandler<StockCountChangedEvent>,         ITransientDependency    {        public async Task HandleEventAsync(StockCountChangedEvent eventData)        {            //TODO: your code that does somthing on the event        }    }}

MyHandler 由ABP框架自動發現,並在發生 StockCountChangedEvent 事件時呼叫 HandleEventAsync.

事件可以由0個或多個處理程式訂閱.一個事件處理程式可以訂閱多個事件,但是需要為每個事件實現 ILocalEventHandler<TEvent> 介面.

事件處理程式類必須註冊到依賴注入(DI),示例中使用了 ITransientDependency.

如果您執行資料庫操作並在事件處理程式中使用倉儲,那麼您可能需要建立一個工作單元,因為一些儲存庫方法需要在活動的工作單元中工作. 確保處理方法設定為 virtual,併為該方法新增一個 [UnitOfWork] attribute. 或者手動使用 IUnitOfWorkManager 建立一個工作單元範圍.

事務和異常行為

當一個事件釋出,訂閱的事件處理程式將立即執行.所以;

如果處理程式丟擲一個異常,它會影響釋出該事件的程式碼. 這意味著它在 PublishAsync 呼叫上獲得異常. 因此如果你想隱藏錯誤,在事件處理程式中使用try-catch.如果在一個工作單元範圍內執行的事件釋出的程式碼,該事件處理程式也由工作單元覆蓋. 這意味著,如果你的UOW是事務和處理程式丟擲一個異常,事務會回滾.預定義的事件

釋出實體建立,更新,刪除事件是常見的操作. ABP框架為所有的實體自動釋出這些事件. 你只需要訂閱相關的事件.

示例: 訂閱使用者建立事件

using System.Threading.Tasks;using Microsoft.AspNetCore.Identity;using Volo.Abp.DependencyInjection;using Volo.Abp.Domain.Entities.Events;using Volo.Abp.EventBus;namespace AbpDemo{    public class MyHandler        : ILocalEventHandler<EntityCreatedEventData<IdentityUser>>,          ITransientDependency    {        public async Task HandleEventAsync(EntityCreatedEventData<IdentityUser> eventData)        {            var userName = eventData.Entity.UserName;            var email = eventData.Entity.Email;            //...        }    }}

這個類訂閱 EntityCreatedEventData<IdentityUser>,它在使用者建立後釋出. 你可能需要向新使用者傳送一封"歡迎"電子郵件.

這些事件有兩種型別:過去時態的事件和進行時態的事件.

用於過去時態事件

當相關工作單元完成且實體更改成功儲存到資料庫時,將釋出帶有過去時態的事件. 如果在這些事件處理程式上丟擲異常,則無法回滾事務,因為事務已經提交.

事件型別;

EntityCreatedEventData<T> 當實體建立成功後釋出.EntityUpdatedEventData<T> 當實體更新成功後釋出.EntityDeletedEventData<T> 當實體刪除成功後釋出.EntityChangedEventData<T> 當實體建立,更新,刪除後釋出. 如果你需要監聽任何型別的更改,它是一種快捷方式 - 而不是訂閱單個事件.

用於進行時態事件

帶有進行時態的事件在完成事務之前釋出(如果資料庫事務由所使用的資料庫提供程式支援). 如果在這些事件處理程式上丟擲異常,它會回滾事務,因為事務還沒有完成,更改也沒有儲存到資料庫中.

事件型別;

EntityCreatingEventData<T> 當新實體儲存到資料庫前釋出.EntityUpdatingEventData<T> 當已存在實體更新到資料庫前釋出.EntityDeletingEventData<T> 刪除實體前釋出.EntityChangingEventData<T> 當實體建立,更新,刪除前釋出. 如果你需要監聽任何型別的更改,它是一種快捷方式 - 而不是訂閱單個事件.它是如何實現的?

在將更改儲存到資料庫時釋出預構建事件;

對於 EF Core, 他們在 DbContext.SaveChanges 釋出.對於 MongoDB, 在你呼叫倉儲的 InsertAsync, UpdateAsync 或 DeleteAsync 方法釋出(因為MongoDB沒有更改追蹤系統).

9
最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • 不要再用main方法測試程式碼效能了,用這款JDK自帶工具