您好,登錄后才能下訂單哦!
使用ASP.NET Core怎么實現單體程序的事件發布?針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。
public void SubmitShoppingCart(string shoppingCartId) { var shoppingCart = _unitOfWork.ShoppingCartRepository .GetShoppingCart(shoppingCartId); _unitOfWork.ShoppingCartRepository .SubmitShoppingCart(shoppingCartId); _unitOfWork.OrderRepository .CreatOrder(new CreateOrderDTO { Items = shoppingCart.Items .Select(p => new NewOrderItemDTO { ItemId = p.ItemId, Name = p.Name, Price = p.Price }).ToList() }); //這里為了簡化代碼,我用命令行表示發送郵件的邏輯 Console.WriteLine("Confirm Email Sent."); _unitOfWork.Save(); }
根據SOLID設計原則中的單一責任原則,如果一個類承擔的職責過多,就等于把這些職責耦合在一起了。這里生成訂單和發送郵件都不應該是當前SubmitShoppingCart需要負責的,所以我們需要它們從這個方法中移出去,使用的方法就是事件訂閱/發布。
新的架構圖
以下是使用事件發布/訂閱之后的系統架構圖。
這里我們會創建一個購物車提交事件ShoppingCartSubmittedEvent。
當站點啟動的時候,我們會在一個名為EventHandlerContainer的類中注冊訂閱ShoppingCartSubmittedEvent事件的2個處理類CreateOrderHandler和ConfirmEmailSentHandler。
在SubmitShoppingCart方法中,我們會做2件事情:
更改當前購物車的狀態。
發布ShoppingCartSubmittedEvent事件。
CreateOrderHandler事件處理器會調用OrderManager類中的創建訂單方法。
ConfirmEmailSentHandler事件處理器會負責發送郵件。
好的,下面讓我們來一步一步實現以上描述的代碼。
添加事件基類
這里我們首先定義一個事件基類,其中暫時只添加了一個屬性OccuredOn,它表示了當前事件的觸發時間。
public class EventBase { public EventBase() { OccuredOn = DateTime.Now; } protected DateTime OccuredOn { get; set; } }
定義購物車提交事件
接下來我們就需要創建購物車提交事件類ShoppingCartSubmittedEvent, 它繼承自EventBase, 并提供了一個購物項集合
public class ShoppingCartSubmittedEvent : EventBase { public ShoppingCartSubmittedEvent() { Items = new List<ShoppingCartSubmittedItem>(); } public List<ShoppingCartSubmittedItem> Items { get; set; } } public class ShoppingCartSubmittedItem { public string ItemId { get; set; } public string Name { get; set; } public decimal Price { get; set; } }
定義事件處理器接口
為了添加事件處理器,我們首先需要定義一個泛型接口類IEventHandler
public interface IEventHandler<T> where T : EventBase { void Run(T obj); Task RunAsync(T obj); }
這個泛型接口類的是泛型類型必須繼承自EventBase類。接口提供了2個方法Run和RunAsync。 它們定義了該接口的實現類必須實現同一個處理邏輯的同步和異步方法。
為購物車提交事件編寫事件處理器
有了事件處理器接口,接下來我們就可以開始為購物車提交事件添加事件處理器了。這里我們為了實現前面定義的邏輯,我們需要創建2個處理器CreateOrderHandler和ConfirmEmailSentHandler
CreateOrderHandler.cs
public class CreateOrderHandler : IEventHandler<ShoppingCartSubmittedEvent> { private IOrderManager _orderManager = null; public CreateOrderHandler(IOrderManager orderManager) { _orderManager = orderManager; } public void Run(ShoppingCartSubmittedEvent obj) { _orderManager.CreateNewOrder(new Models.DTOs.CreateOrderDTO { Items = obj.Items.Select(p => new Models.DTOs.NewOrderItemDTO { ItemId = p.ItemId, Name = p.Name, Price = p.Price }).ToList() }); } public Task RunAsync(ShoppingCartSubmittedEvent obj) { return Task.Run(() => { Run(obj); }); } }
代碼解釋:
在CreateOrderHandler的構造函數中,我們注入了IOrderManager接口對象,CreateNewOrder負責最終創建訂單的工作
這里為了簡化代碼,我直接使用了Task.Run,并在其中調用了同步方法實現
ConfirmEmailSentHandler.cs
public class ConfirmEmailSentHandler : IEventHandler<ShoppingCartSubmittedEvent> { public void Run(ShoppingCartSubmittedEvent obj) { Console.WriteLine("Confirm Email Sent."); } public Task RunAsync(ShoppingCartSubmittedEvent obj) { return Task.Run(() => { Console.WriteLine("Confirm Email Sent."); }); } }
代碼解釋:
這個處理類非常簡單,為了簡化代碼,我僅輸出了一行文本來表示實際需要運行的代碼。
為OrderManager類添加創建訂單方法
IOrderManager.cs
public interface IOrderManager { string CreateNewOrder(CreateOrderDTO dto); }
OrderManager.cs
public class OrderManager : IOrderManager { private IOrderRepository _orderRepository; public OrderManager(IOrderRepository orderRepository) { _orderRepository = orderRepository; } public string CreateNewOrder(CreateOrderDTO dto) { var orderId = _orderRepository.CreatOrder(dto); Console.WriteLine($"One order created: {JsonConvert.SerializeObject(dto)}"); return orderId; } }
創建EventHandlerContainer
下面我們來編寫最核心的事件處理器容器。在這里我們的事件處理器容器完成了3個功能
訂閱事件(Subscribe Event)
取消訂閱事件(Unsubscribe Event)
發布事件(Publish Event)
public class EventHandlerContainer { private IServiceProvider _serviceProvider = null; private static Dictionary<string, List<Type>> _mappings = new Dictionary<string, List<Type>>(); public EventHandlerContainer(IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; } public static void Subscribe<T, THandler>() where T : EventBase where THandler : IEventHandler<T> { var name = typeof(T).Name; if (!_mappings.ContainsKey(name)) { _mappings.Add(name, new List<Type> { }); } _mappings[name].Add(typeof(THandler)); } public static void Unsubscribe<T, THandler>() where T : EventBase where THandler : IEventHandler<T> { var name = typeof(T).Name; _mappings[name].Remove(typeof(THandler)); if (_mappings[name].Count == 0) { _mappings.Remove(name); } } public void Publish<T>(T o) where T : EventBase { var name = typeof(T).Name; if (_mappings.ContainsKey(name)) { foreach (var handler in _mappings[name]) { var service = (IEventHandler<T>)_serviceProvider.GetService(handler); service.Run(o); } } } public async Task PublishAsync<T>(T o) where T : EventBase { var name = typeof(T).Name; if (_mappings.ContainsKey(name)) { foreach (var handler in _mappings[name]) { var service = (IEventHandler<T>)_serviceProvider.GetService(handler); await service.RunAsync(o); } } } }
代碼解釋:
這里我沒有直接訂閱事件處理器的實例,而且訂閱了事件處理器的類型
多個事件處理器可以訂閱同一個事件
EventHandlerContainer的構造函數中,我們注入了一個IServiceProvider,我們可以使用它來獲得對應事件處理器的實例。
在程序啟動時,注冊事件訂閱
現在我們來Startup.cs的ConfigureServices方法,這里我們需要進行服務注冊,并完成事件訂閱。
public void ConfigureServices(IServiceCollection services) { services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); services.AddScoped<IOrderManager, OrderManager>(); services.AddScoped<IShoppingCartManager, ShoppingCartManager>(); services.AddScoped<IShoppingCartRepository, ShoppingCartRepository>(); services.AddScoped<IOrderRepository, OrderRepository>(); services.AddScoped<IUnitOfWork, UnitOfWork>(); services.AddScoped<CreateOrderHandler>(); services.AddScoped<ConfirmEmailSentHandler>(); services.AddScoped<EventHandlerContainer>(); EventHandlerContainer.Subscribe<ShoppingCartSubmittedEvent, CreateOrderHandler>(); EventHandlerContainer.Subscribe<ShoppingCartSubmittedEvent, ConfirmEmailSentHandler>(); }
注意:這里保證一個Api請求中的所有數據庫操作在一個事務里,這里我們使用Scoped作用域。這樣我們就可以在調用工作單元IUnitOfWork接口的Save代碼中啟用事務。
修改ShoppingCartManager
最后我們來修改ShoppingCartManager, 改用發布事件的方式來完成后續創建訂單和發送郵件的功能。
public void SubmitShoppingCart(string shoppingCartId) { var shoppingCart = _unitOfWork.ShoppingCartRepository .GetShoppingCart(shoppingCartId); _unitOfWork.ShoppingCartRepository .SubmitShoppingCart(shoppingCartId); _container.Publish(new ShoppingCartSubmittedEvent() { Items = shoppingCart .Items .Select(p => new ShoppingCartSubmittedItem { ItemId = p.ItemId, Name = p.Name, Price = p.Price }) .ToList() }); _unitOfWork.Save(); }
這樣ShoppingCartManager就只需要關注購物車狀態的變更,而不需要關注發送確認郵件和創建訂單了。
最終效果
現在讓我們啟動項目,
首先我們使用[POST] /api/shoppingCarts來添加一個新的購物車, 這個API會返回當前購物車的Id
然后我們使用[PUT] /api/shoppingCarts/ShoppingCart_636872897140555966來模擬提交購物車,程序返回操作成功
最后我們查看一下控制臺的輸出日志
關于使用ASP.NET Core怎么實現單體程序的事件發布問題的解答就分享到這里了,希望以上內容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關注億速云行業資訊頻道了解更多相關知識。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。