.net core下使用事件匯流排

来源:https://www.cnblogs.com/MrHanBlog/archive/2020/06/09/13031671.html
-Advertisement-
Play Games

隨著微服務的火熱,DDD(領域驅動設計模式)思想風起雲涌,衝擊著整個軟體生態系統。其中,事件匯流排那是必須知道的了,於是我便抱著一個學習DDD的心態搭建了一個博客網站,目前該網站正在建設階段,後續會不斷完善,這裡我只是講一下我裡面所用到的事件匯流排。 事件匯流排,我的理解就是發佈訂閱模式,這裡有一篇文章寫 ...


        隨著微服務的火熱,DDD(領域驅動設計模式)思想風起雲涌,衝擊著整個軟體生態系統。其中,事件匯流排那是必須知道的了,於是我便抱著一個學習DDD的心態搭建了一個博客網站,目前該網站正在建設階段,後續會不斷完善,這裡我只是講一下我裡面所用到的事件匯流排。

      事件匯流排,我的理解就是發佈訂閱模式,這裡有一篇文章寫的比較好,我就是按著這個文章來完成的事件匯流排:事件匯流排知多少。我之前按照他的文章結合自己寫的,但是今天又看了下自己寫的,發現好多都生疏了,所以覺得有必要來回憶下,這裡只是我個人的理解,如有不對請指出。

     事件匯流排就肯定要有事件源,這裡我定義一個Command事件源:   
    /// <summary>
    /// 領域命令基類(此處文章里我稱之為事件源)
    /// </summary>
    public  class Command
    {
        
    }

 然後我根據事件源來定義一個事件源處理的介面和它的實現類:

    /// <summary>
    /// 創建用戶領域命令(創建事件源)
    /// </summary>
    public class CreateUserCommand: Command
    {
        public CreateUserCommand(User user)
        {
            User = user;
        }
        public User User { get; private set; }

    }
    /// <summary>
    /// 用戶命令處理程式(處理事件源)
    /// </summary>
    public class UserCommandHandler : ICommandHandler<CreateUserCommand>, 
    {
        private readonly IUserRepository _userRepository;
        private readonly IEventBus _eventBus;
        public UserCommandHandler(IUserRepository userRepository, IEventBus eventBus)
        {
            _userRepository = userRepository;
            _eventBus = eventBus;
        }

        public void Handler(CreateUserCommand command)
        {
            int count = _userRepository.SelectCountByAccount(command.User.Account);
            if (count > 0)
            {
                _eventBus.RaiseEvent(new NotifyValidation("該賬號已存在"));
                return;
            }
            _userRepository.Insert(command.User);
        }
    }

     此處我覺得已經完成了關於事件源的功能,那麼我們就來思考根據這個事件源來處理髮布訂閱的關係。

     就那註冊用戶功能來說,前面已經將註冊用戶的事件源已經寫好了,那麼發佈訂閱怎麼處理呢?首先,我們應該清楚一個邏輯,那就是頁面生成用戶信息,後端獲取信息生成UserModel,然後我們根據UserModel轉為我們需要的CreateUserCommand,然後我們ICommandHandler根據CreateUserCommand來調用Handler,這是一個簡單的調用邏輯。那麼IcommandHnadler怎麼知道調用哪一個Handler呢?那就是我將事件源和事件源處理類存入集合裡面,這樣我以後就會根據Command來獲取到我的ICommandHandler了,又因為.net core遵循依賴註入原則,所以我需要往容器了註入ICommander和他的實現類,就是UserCommandhandler,這個時候可以說是已經將事件源都註冊到了記憶體里了,以下是我的相關代碼:

 
        /// <summary>
        /// 臨時存儲類型數組
        /// </summary>
        private static Type[] serviceTypes = Assembly.Load("Blog.Domain").GetTypes();
 
        private static ConcurrentDictionary<Type, IList<Type>> handlerMapping = new ConcurrentDictionary<Type, IList<Type>>();

        public static IList<Type> GetOrAddHandlerMapping(this Type eventType)
        {
           return handlerMapping.GetOrAdd(eventType,(Type type)=>new List<Type>());
        }

        /// <summary>
        /// 註冊事件匯流排(事件源)
        /// </summary>
        /// <typeparam name="TImplementation">ICommandler<CreateUserCommand></typeparam>
        /// <typeparam name="TService">CreateUserCommand</typeparam>
        /// <param name="serviceDescriptors"></param>
        public static void AddEventBus<TImplementation, TService>(this IServiceCollection serviceDescriptors)
        {
            Type handler = typeof(TImplementation);
            Type serviceType = serviceTypes.FirstOrDefault(s => handler.IsAssignableFrom(s));//獲得介面的實現類
            if (serviceType == null)
                throw new ArgumentNullException(string.Format("類型{0}未找到實現類", handler.FullName));
            serviceDescriptors.AddTransient(handler, serviceType);//.net core自帶的IOC容器
            GetOrAddHandlerMapping(typeof(TService)).Add(handler);//將事件源和事件源處理程式註冊到記憶體里,可以說生成了一個訂閱列表
        }

    接下來我們再看發佈與訂閱,我要先定義一個發佈訂閱的中間件,

    /// <summary>
    /// 中間件
    /// </summary>
   public  interface  IEventBus
    {
        /// <summary>
        /// 發佈
        /// </summary>
        /// <typeparam name="TEventData"></typeparam>
        /// <param name="eventData"></param>
        void Publish<TCommand>(TCommand command) where TCommand : Command;
     }

  然後還有它的實現類,處理邏輯就是根據UserCommandHandler去ConcurrentDictionary里找到它的對應的ICommandHandler,然後在從IOC容器找到ICommandHandler的實現類,然後執行裡面的方法,如下:

    public sealed class EventBus : IEventBus
    {
        private IServiceProvider _serviceProvider;
        public EventBus(IServiceProvider serviceProvider)
        {
            _serviceProvider = serviceProvider;
        }
        /// <summary>
        /// 發佈事件
        /// </summary>
        /// <typeparam name="TEventData"></typeparam>
        /// <param name="eventData"></param>
        public void Publish<TCommand>(TCommand command) where TCommand : Command
        {
            IList<Type> types=typeof(TCommand).GetOrAddHandlerMapping();
            if (types == null || types.Count == 0)
                throw new ServiceException("事件匯流排未註冊:" + typeof(TCommand).Name);
            foreach (var type in types)//從訂閱列表裡尋找
            {
                object obj = _serviceProvider.GetService(type);
                if(type.IsAssignableFrom(obj.GetType()))
                {
                    ICommandHandler<TCommand> handler = obj as ICommandHandler<TCommand>;
                    if (handler != null)
                        handler.Handler(command);//
                }
            }
        }
  }

  這個時候可以說已經完成了發佈訂閱,程式生成CreateUserCommand,這裡我的理解為就是發佈,調用Publish方法,這裡我覺得就是訂閱,然後最後執行Handler完成業務邏輯:

  public class UserService : IUserService
    {
        private readonly IUserRepository _userRepository;
        private readonly IEventBus _eventBus;
        /// <summary>
        /// 根據UserModel轉實體
        /// </summary>
        /// <param name="userModel"></param>
        /// <returns></returns>
        private User TransferModel(UserModel userModel)
        {
            return user;
        }
        public UserService(IUserRepository userRepository, IEventBus eventBus)
        {
            _userRepository = userRepository;
            _eventBus = eventBus;
        }
        public void Insert(UserModel userModel)
        {
            userModel.Password = EncrypUtil.MD5Encry(userModel.Password);
            var command = new CreateUserCommand(TransferModel(userModel));//創建事件源
            _eventBus.Publish(command);//發佈命令
        }
}

        還有就是最後的IServiceCollection註入了:

        /// <summary>
        /// 服務集合
        /// </summary>
        /// <param name="services"></param>
        public static void AddServices(this IServiceCollection services)
        {
            services.AddTransient<IUserRepository, UserRepository>();
            services.AddTransient<IUserService, UserService>();
            services.AddEventBus<ICommandHandler<CreateUserCommand>, CreateUserCommand>();
services.AddTransient<IEventBus,EventBus>() services.DisposeServiceTypes(); }

  以上就是我對事件匯流排的具體應用,希望有大佬能指出我這菜鳥的不足指出!

        好記性不如爛筆頭,所以我把這個玩意用到了我的網站裡面,我的個人站點的地址是:www.ttblog.site,源代碼的地址是:https://github.com/Hansdas/BlogH.git,個人站點處於建設階段,很多功能不完善,由於時間原因,所以進度比較慢,但是我也是每天回到家後都會去完善,自己做的飯再難吃也要吃完自己做的網站,不好看也要用心呵護。 

      

     

      


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 前言 本文的文字及圖片來源於網路,僅供學習、交流使用,不具有任何商業用途,版權歸原作者所有,如有問題請及時聯繫我們以作處理。 作者:CDA數據分析師 地攤經濟火了!微博微熱點數據 我們先看到微博微熱點的數據:全網熱度指數趨勢 從全網熱度指數的變化趨勢來看,地攤經濟的熱度在6月3日起逐步升溫,6月4日 ...
  • QT讀JSON文件步驟,這裡把過程記錄一下,網上大多都是怎麼寫json的,對於讀的,記錄的不多 首先JSON文件格式必須為UTF-8(非UTF-8 with BOM),UTF-8 with BOM 即為UTF-8 前加了BOM標識,會導致解析失敗,報錯內容非法,這時候就將文件保存為UTF-8就好了。 ...
  • 使用vs2019創建ASP.Net Core Web應用程式: 右側高級選項中有一項啟用Docker支持,勾選後vs會自動幫我們創建Dockerfile: 看一下Dockerfile的內容: #See https://aka.ms/containerfastmode to understand ho ...
  • SunnyUI為了避免視覺傳達差異,使用一套特定的調色板來規定顏色,為你所搭建的產品提供一致的外觀視覺感受。 主色 SunnyUI主要品牌顏色是鮮艷、友好的藍色。 ...
  • 0. 前言 通過前兩篇,我們創建了一個項目,並規定了一個基本的數據層訪問介面。這一篇,我們將以EF Core為例演示一下數據層訪問介面如何實現,以及實現中需要註意的地方。 1. 添加EF Core 先在數據層實現層引入 EF Core: cd Domain.Implements dotnet add ...
  • vs版本 2019,鏈接資料庫使用Navicat,資料庫MySql abp的官網:https://aspnetboilerplate.com/,我們去Download這裡下載一個模板,需要選好Target Version、輸入項目名字,我這裡使用abp的mvc版本、項目名為AbpLearn下載一份 ...
  • LiveCharts 提示框(DataTooltip)百分比一直為0.00%解決辦法 問題描述:在使用LiveCharts 開源圖標庫的時候,使用CartesianChart類圖表,當Series為LineSeries(多個對象)類型時,DataTooltip數據提示框會提示每個點對應的百分比,但一 ...
  • 後臺修改前臺不刷新可能的原因: 1.前臺頁面沒有寫Binding 2.後臺數據定義的欄位沒有get和set 3.數據容器沒有使用ObservableCollection 4.欄位內容修改時沒有重置數據源 首先簡單舉例界面代碼如下: <DataGrid Name="DG" ItemsSource="{ ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...