大家好,我是失業在家,正在找工作的博主Jerry。作為一個.Net架構師,就要研究程式設計藝術,例如SOLID原則和各種設計模式。根據這些原則和實踐,實現了一個更簡潔更低耦合的RPC(Remote Procedure Calls)框架,名叫MediatRPC。
SOLID的總原則是開閉原則(Open Closed Principle): 一個軟體實體,如類、模組和函數應該對擴充套件開放,對修改關閉。其它原則和設計模式都是為了實現和體現這個總原則。例如我們熟悉的工廠模式就很好的實現了開閉原則(Open Closed Principle)。
但是我認為,MediatR對這個總原則的實現更完美。在MediatR中,任何新增功能都可以通過新增Resquest訊息和Handler處理器的方式實現,甚至可以在不改變原有Notification訊息的基礎上,新增Handler處理來實現功能擴充套件。新版本還增加了對StreamRequest的支援,使其可以通過相同的方式對請求資料流進行處理,實現和GRPC類似的流式資料處理。
MediatR對這個總原則的實現之所以更好,是因為它沒有讓程式設計師採用傳統的面向介面的程式設計方式來對功能進行抽象,也就是通過介面方法來代表功能。而是另闢蹊徑,採用訊息來代表功能,把功能抽象為對訊息的處理過程。很巧妙的避免了介面類粒度難以定義和介面方法簽名耦合的問題。 MediatR讓程式設計師從面向介面程式設計轉變為訊息導向程式設計。化繁為簡,我認為這是一個很大的程式設計思想的進步。
MediatR還提供各種自定義AOP功能和例外處理功能,是個很優秀的過程/功能呼叫(Procedure Calls)框架。從過程/功能呼叫的角度來講,它比GRPC更簡潔,更低耦合。因為GRPC本質上還是傳統的對伺服器端功能的介面抽象,也就是Proto檔案的作用。這導致了使用者端不但要知道伺服器端方法的介面引數,也要知道方法所在介面和方法名稱才能呼叫該功能。此外,如果使用者端只想呼叫伺服器端的一個方法,也必須要參照整個Proto檔案,或者對Proto檔案進行刪減(增加風險)。
而這些高耦合的問題在MediatR中都不存在,因為在MediatR中,訊息就代表功能,伺服器端只要接收到訊息就執行對應處理過程來實現功能。使用者端想呼叫那個功能只要傳送相應的訊息即可。除了MediatR不能遠端(Remote)以外。
那麼,我們就給MediatR加上遠端通訊的功能。這就涉及到遠端通訊的問題,目前最先進最時髦的遠端通訊協定莫過於QUIC了。它是HTTP3的通訊實現基礎,基於UDP協定,比TCP協定減少了握手次數,提高了傳輸效率,提高了傳輸安全性等,總之就是兩個字:先進。
而.Net 中的System.Net.Quic,是微軟實現的跨平臺QUIC的.Net封裝程式集。微軟其實是用C++實現的QUIC,據說其效能受到了業界好評。本文就使用System.Net.Quic為MediatR增加遠端傳送和接收訊息的功能。從而實現真正的RPC,起名叫MediatRPC。
我們先來看一下實現結果,首先啟動伺服器端:
使用者端遠端呼叫程式碼如下:
Console.WriteLine("MediatRPC Client Running..."); Console.WriteLine(); MediatRpcClient mediatRpcClient = await MediatRpcClient.Build(); var responseMessage1 = await mediatRpcClient.Send(new TestRequestMessage() { Message = "Hello MediatRPC 1" }); Console.WriteLine(JsonSerializer.Serialize(responseMessage1)); Console.WriteLine(); var responseMessage2 = await mediatRpcClient.Publish(new TestNotificationMessage() { Message = "Hello MediatRPC 2" }); Console.WriteLine(responseMessage2); Console.ReadKey();
MediatRpcClient是我實現的使用者端物件,它分別向伺服器端傳送了兩個訊息,一個是用Send傳送了IRequest訊息,並列印返回訊息。另一個是用Publish傳送了INotification訊息,列印是否執行成功。訊息傳送和接收方式和MediatR一摸一樣, 因為方法簽名直接抄襲了MediatR。宗旨就是,怎麼使用MediatR就怎麼使用MediatRPC。
伺服器端處理Request訊息的Handler程式碼如下:
public class TestRequestMessageHandler : IRequestHandler<TestRequestMessage, TestResponseMessage>
{
public TestRequestMessageHandler()
{
}
public async Task<TestResponseMessage> Handle(TestRequestMessage request, CancellationToken cancellationToken)
{
TestResponseMessage testResponseMessage = new TestResponseMessage();
testResponseMessage.Message = $"ACK:{request.Message},{DateTime.Now.ToString("HH:mm:ss")}";
return testResponseMessage;
}
}
啟動使用者端:
Request 和 Response Package是我封裝的訊息包,參考了Http包的實現,也分為Headers和Body。Request 包將原來Http包的請求路徑改為MediaRMethod,讓伺服器端知道如何處理這個訊息。呼叫紀錄檔每一步都列印的很清楚,不再贅述。
因篇幅關係,具體的伺服器端和使用者端通訊實現方式將在下一篇展開,明天就會發布,也會發布原始碼。
▪ 博主有15年以上的軟體技術實施經驗(Technical Leader),專注於微服務(Dapr)和雲原生(K8s)軟體架構設計、.Net Core、Java開發和Devops構建釋出。
▪ 博主10年以上的軟體交付管理經驗(Project Manager & Product Ower),致力於敏捷(Scrum)專案管理、軟體產品業務需求分析和原型設計。
▪ 博主熟練設定和使用 Microsoft Azure雲。
▪ 博主為人誠懇,積極樂觀,工作認真負責。
我家在廣州,也可以去深圳工作。做架構師、產品經理、專案經理都可以。有工作機會推薦的朋友可以加我微信 15920128707,微信名字叫Jerry。