轉(zhuǎn)帖|行業(yè)資訊|編輯:龔雪|2024-04-12 10:39:45.217|閱讀 109 次
概述:本文主要介紹在Winform系統(tǒng)開發(fā)中,如何使用MediatR來實現(xiàn)類似事件總線的消息處理,希望能幫助到大家~
# 界面/圖表報表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
相關(guān)鏈接:
MediatR是一款進程內(nèi)的消息訂閱、發(fā)布框架,可實現(xiàn)請求/響應(yīng)、命令、查詢、通知和事件的消息傳遞,解耦了消息處理器和消息之間耦合。提供了Send方法用于發(fā)布到單個處理程序、Publish方法發(fā)布到多個處理程序,使用起來非常方便。目前支持 .NET Framework 、.NET Stardand、.NETCore等版本,可跨平臺使用。本文介紹在Winform系統(tǒng)開發(fā)中,使用MediatR來實現(xiàn)類似事件總線的消息處理。
PS:給大家推薦一個C#開發(fā)可以用到的界面組件——DevExpress WinForms,它能完美構(gòu)建流暢、美觀且易于使用的應(yīng)用程序,無論是Office風格的界面,還是分析處理大批量的業(yè)務(wù)數(shù)據(jù),它都能輕松勝任!
DevExpress技術(shù)交流群9:909157416 歡迎一起進群討論
MediatR的GitHub項目地址:
MediatR的各種場景使用代碼:
如果我們在VS開發(fā)項目,我們在Nugget上找到對應(yīng)模塊,直接添加到項目引用即可,如下所示。
MediatR使用 Microsoft.Extensions.DependencyInjection.Abstractions 來 注入服務(wù)處理,我們使用MediatR的時候,首先需要構(gòu)造ServiceCollection,然后添加配置到其中。
// IServiceCollection負責注冊 IServiceCollection services = new ServiceCollection(); //注冊MediatR服務(wù),用于測試MediatR的服務(wù) services.AddMediatR(cfg => { cfg.RegisterServicesFromAssembly(typeof(Portal).Assembly); });
使用注入服務(wù)的時候,我們需要獲得其中的ServiceProvider,如下通過BuildServiceProvider 獲得該對象。
IServiceProvider provider = services.BuildServiceProvider();
然后我們創(chuàng)建一個靜態(tài)類來存儲這個對象。
//存儲全局IServiceProvider的接口實例, 便于后續(xù)獲得接口實例 ServiceLocator.ConfigService(provider);
其中靜態(tài)類 ServiceLocator 的代碼如下所示。
/// <summary> /// 全局存儲IServiceProvider /// </summary> public class ServiceLocator { /// <summary> /// IOC中的IServiceProvider對象接口 /// </summary> public static IServiceProvider SerivcePovider { get; private set; } /// <summary> /// 賦值IServiceProvider到靜態(tài)變量中 /// </summary> /// <param name="provider">IServiceProvider對象接口</param> public static void ConfigService(IServiceProvider provider) { SerivcePovider = provider; } /// <summary> /// 獲取指定服務(wù)接口實例 /// </summary> /// <returns></returns> public static T GetService<T>() { return SerivcePovider.GetService<T>(); } }
后面我們就可以通過該靜態(tài)類的 GetService<T>() 方法獲取對應(yīng)的注入接口IMediator,需要利用該接口來發(fā)送Send請求/應(yīng)答命令或者發(fā)布Publish消息的處理。例如我們在窗體對象中定義該接口,用于實際的相關(guān)命令、消息的處理。
public partial class TestMediatR : BaseForm { private readonly IMediator _mediator; public TestMediatR() { InitializeComponent(); _mediator = ServiceLocator.GetService<IMediator>(); }
MediatR是一個跨平臺通過一種進程內(nèi)消息傳遞機制,進行請求/響應(yīng)、命令、查詢、通知和事件的消息傳遞,并通過C#泛型來支持消息的智能調(diào)度,其目的是消息發(fā)送和消息處理的解耦。它支持以單播和多播形式使用同步或異步的模式來發(fā)布消息,創(chuàng)建和偵聽事件。它主要的幾個對象:
Request/Response模式對象定義
/// <summary> /// 請求類 /// </summary> public class RetrieveInfoCommandRequest : IRequest<RetrieveInfoCommandResponse> { public string Text { get; set; } } /// <summary> /// 回應(yīng)消息 /// </summary> public class RetrieveInfoCommandResponse { public string OutputMessage { get; set; } } /// <summary> /// 請求應(yīng)答處理類 /// </summary> public class RetrieveInfoCommandHandler : IRequestHandler<RetrieveInfoCommandRequest, RetrieveInfoCommandResponse> { public async Task<RetrieveInfoCommandResponse> Handle(RetrieveInfoCommandRequest request, CancellationToken cancellationToken) { var response = new RetrieveInfoCommandResponse(); response.OutputMessage = $"This is an example of MediatR using {request.Text}"; return response; } }
例如我們根據(jù)這個請求、應(yīng)答的消息協(xié)議,以及定義的處理Handler類(唯一一個),可以設(shè)計一個Winform界面來測試消息的處理。
界面的代碼如下所示。
/// <summary> /// 測試MediatR的窗體例子 /// </summary> public partial class TestMediatR : BaseForm { private readonly IMediator _mediator; public TestMediatR() { InitializeComponent(); _mediator = ServiceLocator.GetService<IMediator>(); } /// <summary> /// 使用請求、應(yīng)答的消息進行測試,獲得返回結(jié)果后輸出顯示 /// </summary> private async void btnSend_Click(object sender, EventArgs e) { //應(yīng)答處理 var outputMessage = await _mediator.Send(new RetrieveInfoCommandRequest { Text = this.txtSend.Text }); Console.WriteLine(outputMessage.OutputMessage); this.txtReceived.AppendText(outputMessage.OutputMessage + Environment.NewLine); }
上面的命令消息方式,有返回值,如果不需要返回值,也可以采用這種一一應(yīng)答的方式,那么定義的時候,繼承IRequest接口即可。
public class OneWay : IRequest { } public class OneWayHandler : IRequestHandler<OneWay> { public Task Handle(OneWay request, CancellationToken cancellationToken) { // do work return Task.CompletedTask; } }
如果我們需要類似事件多播的處理,也就是常規(guī)的消息通知處理,采用INotification方式。
Notification模式將消息發(fā)布給多個處理程序,消息的處理沒有返回值。
/// <summary> /// 通知類 /// </summary> public class MyNotification : INotification { public string Message { get; } public MyNotification(string message) { Message = message; } } /// <summary> /// Notification處理程序-模塊1 /// </summary> public class MyNotifyHandler : INotificationHandler<MyNotification> { public Task Handle(MyNotification notification, CancellationToken cancellationToken) { var message = "模塊1-收到消息:" + notification.Message; //MessageDxUtil.ShowTips(message); //提示消息 var alert = new AlertControl(); alert.FormLocation = AlertFormLocation.TopRight; alert.AutoFormDelay = 3000; alert.Show(Portal.gc.MainDialog, message, message); // 處理通知 Console.WriteLine($"Notification處理程序-模塊1-收到消息: {notification.Message}"); return Task.CompletedTask; } } /// <summary> /// Notification處理程序-模塊2 /// </summary> public class MySecondNotifyHandler : INotificationHandler<MyNotification> { public Task Handle(MyNotification notification, CancellationToken cancellationToken) { var message = "模塊2-收到消息:" + notification.Message; //MessageDxUtil.ShowTips(message); //提示消息 var alert = new AlertControl(); alert.FormLocation = AlertFormLocation.TopRight; alert.AutoFormDelay = 3000; alert.Show(Portal.gc.MainDialog, message, message); // 處理通知 Console.WriteLine($"Notification處理程序-模塊2-收到消息: {notification.Message}"); return Task.CompletedTask; } }
我們在界面上發(fā)布消息的代碼如下所示。
private async void btnNotify_Click(object sender, EventArgs e) { //發(fā)布消息 await _mediator.Publish(new MyNotification(this.txtSend.Text)); }
可以看到在控制臺和UI上我們的都有測試消息的輸出。
默認情況下,MediatR的消息發(fā)布是一個一個執(zhí)行的,即便是返回Task的情況,也是使用await等待上一個執(zhí)行完成后才進行下一個的調(diào)用。如果需要使用并行的方法進行調(diào)用,可以進行定制,具體可參考官方示例:。
對于MediatR來說,無論是發(fā)送IRequest類型消息,還是發(fā)布INotification類型消息,都是異步的。這里需要特別留意,即使你使用的是同步的消息處理程序,對于消息發(fā)布來說,都是異步的,與你的處理程序是同步或異步無關(guān)。
詳細的介紹,可以參考官方的案例介紹:。
對于WPF,其實也是類似采用該組件實現(xiàn)事件、消息的處理的,不過如果我們采用MVVM的框架設(shè)計模式,可以采用MVVM(微軟的 CommunityToolkit.Mvvm的組件包)的內(nèi)置的消息處理模式。
CommunityToolkit.Mvvm (又名 MVVM 工具包,以前名為 Microsoft.Toolkit.Mvvm) 是一個現(xiàn)代、快速且模塊化的 MVVM 庫。官網(wǎng)介紹地址://learn.microsoft.com/zh-cn/dotnet/communitytoolkit/mvvm/
利用MVVM推送一條消息,如下代碼所示。
//發(fā)送MVVM消息信息通知方式(一) WeakReferenceMessenger.Default.Send(new ClickEventMessage(eventData));
而其中 ClickEventMessage 是我們根據(jù)要求定義的一個消息對象類,如下代碼所示。
完整的Command命令如下所示。
/// <summary> /// 雙擊觸發(fā)MVVM消息通知 /// </summary> /// <param name="typeName">處理類型:Number、Animal、WuHan</param> /// <returns></returns> [RelayCommand] private async Task DoubleClick(string typeName) { var clickType = ClickEventType.Number; var clickValue = this.Number; ..............//處理不同typeName值邏輯//事件數(shù)據(jù) var eventData = new ClickEventData(clickType, clickValue); //發(fā)送MVVM消息信息通知方式(一) WeakReferenceMessenger.Default.Send(new ClickEventMessage(eventData)); }
通過這樣的消息發(fā)送,就需要有個地方來接收這個信息的,我們在需要處理事件的父窗口中攔截處理消息即可。
//處理MVVM的消息通知 WeakReferenceMessenger.Default.Register<ClickEventMessage>(this, (r, m) => { var data = m.Value; var list = ControlHelper.FindVisualChildren<LotteryItemControl>(this.listControl); foreach (var lottery in list) { lottery.SetSelected(data); } });
從而實現(xiàn)了WPF消息的發(fā)送和應(yīng)答處理。
本文轉(zhuǎn)載自:
本站文章除注明轉(zhuǎn)載外,均為本站原創(chuàng)或翻譯。歡迎任何形式的轉(zhuǎn)載,但請務(wù)必注明出處、不得修改原文相關(guān)鏈接,如果存在內(nèi)容上的異議請郵件反饋至chenjj@fc6vip.cn
文章轉(zhuǎn)載自: