本篇內容屬於非實用性(拿來即用)介紹,如對框架設計沒興趣的朋友,請略過。
快一個月沒有寫博文了,最近忙着兩件事;
一:閱讀劉墉先生的《說話的魅力》,以一種微妙的,你我大家都會經常遇見的事物,來建議說話的“藝術和魅力”,對於我們從事軟件開發、不太善於溝通和表達的朋友來說,也算是一項軟技能了,推薦喜歡閱讀的朋友有時間閱讀,給你不一樣的閱讀體驗。

二:編寫基於Net Core的Rpc框架。之前有朋友說如何將Rpc等整個體系集成到dotnet框架中,我想這篇博文會給你一個答案。
哦,對了,我不建議直接將代碼直接復制下來然后去運行的朋友,因為這樣你達不到學習的目的,也違背了筆者的初衷。謝謝理解。
一:簡單回顧一下之前的介紹
繼續貼上之前的一張圖片
根據上面圖,服務化原理可以分為3步:
-
服務端啟動並且向注冊中心發送服務信息,注冊中心收到后會定時監控服務狀態(常見心跳檢測);
-
客戶端需要開始調用服務的時候,首先去注冊中心獲取服務信息;
-
客戶端創建遠程調用連接,連接后服務端返回處理信息;
第3步又可以細分,下面說說遠程過程調用的原理:
目標:客戶端怎么調用遠程機器上的公開方法
-
服務發現,向注冊中心獲取服務(這里需要做的有很多:拿到多個服務時需要做負載均衡,同機房過濾、版本過濾、服務路由過濾、統一網關等);
-
客戶端發起調用,將需要調用的服務、方法、參數進行組裝;
-
序列化編碼組裝的消息,這里可以使用json,也可以使用xml,也可以使用protobuf,也可以使用hessian,幾種方案的序列化速度還有序列化后占用字節大小都是選擇的重要指標,對內筆者建議使用高效的protobuf,它基於TCP/IP二進制進行序列化,體積小,速度快。
-
傳輸協議,可以使用傳統的IO阻塞傳輸,也可以使用高效的nio傳輸(Netty);
-
服務端收到后進行反序列化,然后進行相應的處理;
-
服務端序列化response信息並且返回;
-
客戶端收到response信息並且反序列化;
至於C類和S類之間的通信方式,是采用RPC還是采用RESTful,讀者可以參考之前的介紹,根據實際業務進行決定
https://www.cnblogs.com/SteveLee/p/service_discovery_and_service_governance.html
二:DotEasy.Rpc框架介紹
單論Rpc框架市場,且不論Java上的Spring Boot和Spring Cloud這樣大名鼎鼎的開源框架,目前Net上的Rpc整合性框架確實並不多,我們Net程序員也要混口飯吃,不能總被Java甩掉好幾條街吧。
言歸正傳,一個遠程過程調用,會涉及到如下幾個方面的技術點(功能):
-
路由轉發:當服務部署在多個節點上時,調用方需要知道自己的目標服務在什么地方。
-
通信協議:當管道存在,還需要在管道的兩端建立處理程序(宿主),以處理管道中的數據包。DotEasy.Rpc基於DotNetty進行通信處理和協議實現。
-
動態生成:我們知道,基於二進制的RPC傳輸,每當新增接口,或修改接口,都需要生成相關協議的protobuf文件(或 thrift 文件),本框架基於protobuf-net的傳輸框架和Rosyln的預生成,動態生成相關的CS文件。
-
運行時代理:本框架采用一次請求創建一個客戶端的模式,進行S端的服務請求,本框架基於Rosyln運行時創建客戶端代理。
-
接口掃描:需要實現多個接口的添加和注冊,本框架采用Attribute特性來掃描接口,並添加到相關的注冊中心,比如consul或etcd。
2.1 解決方案介紹:
整體解決方案不做過多介紹,相信單詞的詞義已經表達了這個項目的作用。
小插曲:筆者曾用Easy.Rpc做為項目的主庫名稱,但上傳到nuget后才發現,原來也有名為easy.rpc的包,不過筆者並沒找到這個開源作者的網站,無賴之下,想到“點”這個詞,也是dotnet的dot開頭部分,索性干脆也叫DotEasy了吧。
筆者的目的,是想通過這個框架(或類庫集),來簡化微服務的部署和開發,讓希望從事微服務NET開發的朋友不再找不到從何入手的窘境。
在Nuget.org上能直接下載編譯過的包,地址:
https://www.nuget.org/packages/DotEasy.Rpc/,推薦使用這種方式進行安裝。
如果喜歡研究源碼,筆者同樣也貼上地址:
https://github.com/steveleeCN87/doteasy.rpc,不過源碼不包含任何依賴,如果編譯中出現版本問題,可聯系筆者。目前Github和Nuget上就放上了DotEasy.Rpc核心庫和DotEasy.Rpc.Consul擴展包,etcd和entry還在測試階段,就不方便拿出來獻丑了。o(∩_∩)o 哈哈
當然,也歡迎廣大愛好開源的朋友加入,共同為NET開源項目做貢獻。
2.2 主項目介紹:
Attributes:用於標注該接口為某一特性的方法體,當系統通過Microsoft.Extensions.DependencyInjection自動構建成功后,框架將自動掃描接口上標注過[RpcTagBundle]的接口,形成目標接口列表,以供下面的方法調用。
Core:該核心分為Server和Client以及核心通用三個部分組成:
Client:主要用於通過Ip地址遠程調用的方法Invoke實現,以及遠程服務端的檢查檢查實現。
Communally:通用方法庫,包括唯一ID生成器(用於標識每次請求所產生的唯一客戶端)、通用對象轉換器(將復雜對象轉換為喜歡默認對象)、異常處理器、序列化生成器。
Server:提供服務宿主,服務執行者、服務入口處理、服務管理、服務定位、服務管理工廠的接口及默認實現。
Proxy:運行時預生成及客戶端動態代理模組的接口和方法實現。
Routing:提供地址定位、服務描述、服務路由的接口和方法實現。
Transport:基於protobuf-net和dotnettey構建的二進制序列化、和通信管道和宿主的接口和實現。
所有主要類均已接口的形式提供接口名稱,和已默認實現的具體方法體(虛方法),方便在這個基礎上進行擴展和重寫。
2.3 主項目接口
本節簡單介紹一下DotEasy.Rpc主框架的接口的作用。
Attribute: |---RpcTagBundleAttribute.cs Core: |---Client: |-------Address: |-----------IAddressResolver.cs |-------IRemoteInvokeService.cs |---Server: |-------IServiceEntryFactory.cs |-------IServiceEntryLocate.cs |-------IServiceEntryManager.cs |-------IServiceEntryProvider.cs |-------IServiceExecutor.cs |-------IServiceHost.cs Proxy: |---IServiceProxyFactory.cs |---IServiceProxyGenerater.cs Routing: |---IServiceRouteFactory.cs |---IServiceRouteManager.cs Transport: |-------Codec: |-----------ITransportMessageCodecFactory.cs |-----------ITransportMessageDecoder.cs |-----------ITransportMessageEncoder.cs |---IMessageListener.cs |---IMessageSender.cs
RpcTagBundleAttribute.cs:所有標記過[RpcTagBundle]特性的接口均會被掃描至doteasy.rpc框架中;
IAddressResolver.cs:地址解析器,提供IPv4地址解析作用,用於IServiceRouteFactory和IRemoteInvokeService定位操作;
IRemoteInvokeService.cs:遠程調用服務接口,提供遠程服務調用的關鍵接口,通過IServiceProxyFactory接口代理調用;
IServiceEntryFactory.cs:服務入口工廠接口,對全局服務入口的統一的工廠操作,例如添加,監聽,移除,修改服務入口等;
IServiceEntryLocate.cs:服務入口定位接口,通過IAddressResolver過濾和解析,實現服務入口的定位;
IServiceEntryManager.cs:服務入口管理全局管理接口,功能同IServiceEntryFactory相似,但提供更多的服務管理操作,比如負載均衡(采用輪詢實現);
IServiceEntryProvider.cs:服務入口提供者接口,一個簡單的服務入口提供者程序;
IServiceExecutor.cs:執行服務方法接口,執行遠程服務的IRemoteInvokeService;
IServiceHost.cs:服務宿主接口,DotNetty的服務宿主,類似own框架的自宿主程序,提供請求和響應操作;
IServiceProxyFactory.cs:服務代理工廠接口,客戶端代理(預編譯)的所有操作實現;
IServiceProxyGenerater.cs:服務代理生成接口,客戶端代理(預編譯)生成器;
IServiceRouteFactory.cs:服務路由工廠接口;
IServiceRouteManager.cs:服務路由全局管理接口;
ITransportMessageCodecFactory.cs:管道消息傳輸工廠接口;
ITransportMessageDecoder.cs:管道消息解碼器接口;
ITransportMessageEncoder.cs:管道消息編碼器接口;
IMessageListener.cs:管道消息監聽接口,可實現一個消息的接受者和處理程序;
IMessageSender.cs:管道消息發送接口,可實現一個消息的發送者;
通過上面的框架和㢟就能實現客戶端到服務端的RPC通信了嗎?當然不是,還需要服務注冊中心(例如Consul,etcd,zookeeper)來實現。上面只是提供了路由轉發,服務定位,客戶端預編譯的實現等等功能而已,而服務的注冊並沒提供,因為它不屬於基礎框架的范疇,筆者對zookeeper的笨重太反感(當然不是說它不好),而consul和etcd十分輕量級,特此又專門新增了兩個項目:DotEasy.Rpc.Consul和DotEasy.Rpc.Etcd,用於實現不同注冊中心的注冊(獲取)方法,和健康檢測機制。
當然,介紹Consul和Etcd如何實現不是本節的重點,DotEasy.Rpc這個框架的完全剖析也將在日后新開篇章中專門介紹如何去實現一個框架,想必大部分朋友關心的是這個框架能做什么,有什么樣的功能,那么,接下來開始吧。
三:如何使用
本系列一直重復的那張圖片,噼里啪啦噼里啪啦......此處省略三百字。繞來繞去,難以入手,正如上一篇有朋友推薦如何在Asp.net core中集成、等等。
功能和特性如下:
-
Apache許可證2協議開放源代碼;
-
統一組件裝配和構造;
-
基於protobuf-net實現字節流序列化;
-
基於Rosyln的運行時客戶端代理生成;
-
基於Rosyln的預生成的客戶端代理;
-
基於DotNetty的傳輸信道;
-
支持客戶端以輪詢的方式實現負載平衡;
-
Net Core結構及跨平台;
就這么點,不啰嗦,讓我們開始做DEMO。
3.1 建立服務接口和服務實現
既然是服務,那么肯定需要以接口interface的方式實現對外暴露,並且,
接口的實現不能和接口封裝在同一個DLL中,不然還叫什么遠程過程調用呢(RPC)呢,如果不了解什么叫接口,去翻一翻C#語言規范。
先定義一個接口,接口方法簽名如下:
namespace doteasy.rpc.interfaces { [RpcTagBundle] public interface IUserService { Task<string> GetUserName(int id); Task<bool> Exists(int id); Task<int> GetUserId(string userName); Task<DateTime> GetUserLastSignInTime(int id); Task<IDictionary<string, string>> GetDictionary(); Task TryThrowException(); } }
很簡單,不解釋。
其中接口上有個重要特性叫[RpcTagBundle],該特性只允許標記在interface接口上,用於啟動時方便框架掃描所有標有該特性的接口。
在看實現類
namespace doteasy.rpc.implement { public class UserService : IUserService { public Task<string> GetUserName(int id) { return Task.FromResult($"我傳了一個int數字{id}."); } public Task<bool> Exists(int id) { return Task.FromResult(true); } public Task<int> GetUserId(string userName) { return Task.FromResult(1); } public Task<DateTime> GetUserLastSignInTime(int id) { return Task.FromResult(DateTime.Now); } public Task<IDictionary<string, string>> GetDictionary() { return Task.FromResult<IDictionary<string, string>>(new Dictionary<string, string> { { "key", "value" } }); } public Task TryThrowException() { throw new Exception("嘗試拋出異常!"); } } }
再次重申:注意兩篇代碼中的命名空間,就是兩個不同的程序集(兩個項目),千萬不能以為筆者僅僅是為了區分而已。
3.2 建立asp.net core mvc應用程序
新建一個asp.net core mvc應用程序,模版默認webapi,添加一個控制器HeathController,當然,控制器名稱你也可以自由發揮,鍵入如下代碼:
namespace doteasy.rpc.webserver.Controllers { [Produces("application/json")] [Route("api/Health")] public class HealthController : Controller { [HttpGet] public IActionResult Get() => Ok("ok"); } }
也十分簡單,對外暴露一個路由地址為"api/Health"的API接口,提供GET方法,返回OK信息。
這個接口的作用是用於Consul對服務的健康狀態檢查回調地址,Consul可以基於HTTP做健康檢查,也可以通過gRPC驗證服務健康狀態。
至此,一個WebApi就建立完成,對外不在通過HTTP做任何接口暴露。
接下來我們添加一個IApplicationBuilder的擴展,用於啟動Rpc服務端,代碼如下:
using System; using doteasy.rpc.implement; using doteasy.rpc.interfaces; using DotEasy.Rpc.Entry; using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; namespace doteasy.rpc.webserver { public static class ConsulServerExtensions { public static IApplicationBuilder UseConsulServerExtensions(this IApplicationBuilder app, IConfiguration configuration) { if (app == null) throw new ArgumentNullException(nameof(app)); BaseServer baseServer = new BaseServer(configuration); //(1) baseServer.RegisterEvent += collection => collection.AddTransient<IUserService, UserService>(); //(2) baseServer.Start(); //(3) return app; } } }
(1):實例化一個BaseServer的服務類型,並使用
IConfiguration作為參數。該BaseServer類是封裝太DotEasy.Rpc.Entry中的一個實現,主要是簡化調用者的代碼構建能力,不然,截圖一個部分源碼瞧瞧
框架的目的是簡化編碼工作,構建RPC實例也不例外,100多行的構建代碼只用3行實現,偷懶者必備。
(2):調用一次
RegisterEvent委托事件,用於將接口和實現注冊到ServiceCollection容器中。
(3):啟動這個RPC服務,其實方法內還有構建ServiceCollection容器等等一大堆方法,你可以自己實現,也可以問筆者要源碼。
配置文件在哪兒,難道這樣就可以了?
當然不是,我們還需要一個appsettings.json的默認配置文件,代碼如下:
{ "Hosting.urls": "http://127.0.0.1:5000", "Hosting.And.Rpc.Health.Check": "http://127.0.0.1:5000/api/health", "Rpc": { "IP": "127.0.0.1", "Port": 9881 }, "ServiceDescriptor": { "Name": "LZZ.DEV.ServerService" }, "ConsulRegister": { "IP": "127.0.0.1", "Port": 8500, "Timeout": 5 } }
這篇配置文件很容易理解,這里不再重復啰嗦的解釋。
至此,一個寄宿於Asp.net core的rpc服務就這樣搭建完成,可以啟動隨Consul啟動看看。
友情提示:建議將Asp.net core的默認日志功能關閉,否則Consul會5秒發送一個健康檢查請求過來,日志會慢慢的變得十分臃腫,ConfigureLogging((context, logging) => { logging.ClearProviders(); })即可移除Logging日志功能。當然,你也可以做其他修改,畢竟日志在項目中非常重要。
3.3 測試啟動Consul和Asp.net core
consul如何啟動這個,筆者就不再復述了吧,想必看過之前的文章,應該都會啟動和使用consul了,截個圖,喜悅一下
3.1中的六個接口全被注冊到consul服務中,不信,我們訪問一個具體接口,看看meta信息。
路由和服務均通過這個信息進行定位,我們可以知道,在127.0.0.1的9881端口上,可以訪問名為“doteasy.rpc.interfaces.IUserService.Exists_id”的接口。當然,目前是沒有任何驗證機制的,下一篇會介紹RPC中的統一驗證機制。
3.4 建立一個客戶端
廢話不多說,直接上代碼:
using System; using System.Threading.Tasks; using doteasy.rpc.interfaces; using DotEasy.Rpc.Entry; namespace DotEasy.Client { class Program : BaseClient { static void Main() { new TestClient(); } } public class TestClient : BaseClient { public TestClient() { Task.Run(async () => { var userService = Proxy<IUserService>(); Console.WriteLine($"UserService.GetUserName:{await userService.GetUserName(1)}"); Console.WriteLine($"UserService.GetUserId:{await userService.GetUserId("rabbit")}"); Console.WriteLine($"UserService.GetUserLastSignInTime:{await userService.GetUserLastSignInTime(1)}"); Console.WriteLine($"UserService.Exists:{await userService.Exists(1)}"); Console.WriteLine($"UserService.GetDictionary:{(await userService.GetDictionary())["key"]}"); }).Wait(); } } }
如你所見,我們就像在調用接口一樣的去調用了RPC遠程服務,中間的所有操作都是透明的,不需要關心的,唯一多了一句是
Proxy<IUserService>();使用代理模式動態生成了RPC遠程客戶端,該操作又被筆者封裝在了BaseClient中,一切都為了使用者簡單。
3.5 跑跑客戶端看看結果
info: DotEasy.Rpc.Core.Communally.Convertibles.Impl.DefaultTypeConvertibleService[0] 發現了以下類型轉換提供程序:DotEasy.Rpc.Core.Communally.Convertibles.Impl.DefaultTypeConvertibleProvider info: DotEasy.Rpc.Core.Communally.IdGenerator.Impl.DefaultServiceIdGenerator[0] 方法:System.Threading.Tasks.Task`1[System.String] GetUserName(Int32) 生成服務Id:doteasy.rpc.interfaces.IUserService.GetUserName_id info: DotEasy.Rpc.Core.Communally.IdGenerator.Impl.DefaultServiceIdGenerator[0] 方法:System.Threading.Tasks.Task`1[System.Boolean] Exists(Int32) 生成服務Id:doteasy.rpc.interfaces.IUserService.Exists_id info: DotEasy.Rpc.Core.Communally.IdGenerator.Impl.DefaultServiceIdGenerator[0] 方法:System.Threading.Tasks.Task`1[System.Int32] GetUserId(System.String) 生成服務Id:doteasy.rpc.interfaces.IUserService.GetUserId_userName info: DotEasy.Rpc.Core.Communally.IdGenerator.Impl.DefaultServiceIdGenerator[0] 方法:System.Threading.Tasks.Task`1[System.DateTime] GetUserLastSignInTime(Int32) 生成服務Id:doteasy.rpc.interfaces.IUserService.GetUserLastSignInTime_id info: DotEasy.Rpc.Core.Communally.IdGenerator.Impl.DefaultServiceIdGenerator[0] 方法:System.Threading.Tasks.Task`1[System.Collections.Generic.IDictionary`2[System.String,System.String]] GetDictionary() 生成服務Id:doteasy.rpc.interfaces.IUserService.GetDictionary info: DotEasy.Rpc.Core.Communally.IdGenerator.Impl.DefaultServiceIdGenerator[0] 方法:System.Threading.Tasks.Task TryThrowException() 生成服務Id:doteasy.rpc.interfaces.IUserService.TryThrowException info: DotEasy.Rpc.Core.Client.Address.Resolvers.Implementation.DefaultAddressResolver[0] 准備為服務id:doteasy.rpc.interfaces.IUserService.GetUserName_id,解析可用地址 info: DotEasy.Rpc.Consul.ConsulServiceRouteManager[0] 准備獲取所有路由配置。 info: DotEasy.Rpc.Core.Client.Address.Resolvers.Implementation.DefaultAddressResolver[0] 根據服務id:doteasy.rpc.interfaces.IUserService.GetUserName_id,找到以下可用地址:127.0.0.1:9881 info: DotEasy.Rpc.Core.Client.Implementation.RemoteInvokeService[0] 使用地址:'127.0.0.1:9881'進行調用 info: DotEasy.Rpc.Transport.Impl.DefaultDotNettyTransportClientFactory[0] 准備為服務端地址:127.0.0.1:9881創建客戶端。 info: DotEasy.Rpc.Transport.Impl.DefaultDotNettyTransportClientFactory[0] 准備發送消息。 info: DotEasy.Rpc.Transport.Impl.DefaultDotNettyTransportClientFactory[0] 准備獲取Id為:0b720018feda4e4192937dfbb76eeb66的響應內容。 info: DotEasy.Rpc.Transport.Impl.DefaultDotNettyTransportClientFactory[0] 消息發送成功。 UserService.GetUserName:我傳了一個int數字1. info: DotEasy.Rpc.Core.Client.Address.Resolvers.Implementation.DefaultAddressResolver[0] 准備為服務id:doteasy.rpc.interfaces.IUserService.GetUserId_userName,解析可用地址 info: DotEasy.Rpc.Consul.ConsulServiceRouteManager[0] 准備獲取所有路由配置。 info: DotEasy.Rpc.Core.Client.Address.Resolvers.Implementation.DefaultAddressResolver[0] 根據服務id:doteasy.rpc.interfaces.IUserService.GetUserId_userName,找到以下可用地址:127.0.0.1:9881 info: DotEasy.Rpc.Core.Client.Implementation.RemoteInvokeService[0] 使用地址:'127.0.0.1:9881'進行調用 info: DotEasy.Rpc.Transport.Impl.DefaultDotNettyTransportClientFactory[0] 准備為服務端地址:127.0.0.1:9881創建客戶端。 info: DotEasy.Rpc.Transport.Impl.DefaultDotNettyTransportClientFactory[0] 准備發送消息。 info: DotEasy.Rpc.Transport.Impl.DefaultDotNettyTransportClientFactory[0] 准備獲取Id為:e14b7606b4d54a66af81bfe3c7df46d4的響應內容。 info: DotEasy.Rpc.Transport.Impl.DefaultDotNettyTransportClientFactory[0] 消息發送成功。 info: DotEasy.Rpc.Core.Communally.Convertibles.Impl.DefaultTypeConvertibleService[0] 准備將 System.Int64 轉換為:System.Int32 UserService.GetUserId:1 info: DotEasy.Rpc.Core.Client.Address.Resolvers.Implementation.DefaultAddressResolver[0] 准備為服務id:doteasy.rpc.interfaces.IUserService.GetUserLastSignInTime_id,解析可用地址 info: DotEasy.Rpc.Consul.ConsulServiceRouteManager[0] 准備獲取所有路由配置。 info: DotEasy.Rpc.Core.Client.Address.Resolvers.Implementation.DefaultAddressResolver[0] 根據服務id:doteasy.rpc.interfaces.IUserService.GetUserLastSignInTime_id,找到以下可用地址:127.0.0.1:9881 info: DotEasy.Rpc.Core.Client.Implementation.RemoteInvokeService[0] 使用地址:'127.0.0.1:9881'進行調用 info: DotEasy.Rpc.Transport.Impl.DefaultDotNettyTransportClientFactory[0] 准備為服務端地址:127.0.0.1:9881創建客戶端。 info: DotEasy.Rpc.Transport.Impl.DefaultDotNettyTransportClientFactory[0] 准備發送消息。 info: DotEasy.Rpc.Transport.Impl.DefaultDotNettyTransportClientFactory[0] 准備獲取Id為:d0452b16caeb48ba877da5f69a31b2f8的響應內容。 info: DotEasy.Rpc.Transport.Impl.DefaultDotNettyTransportClientFactory[0] 消息發送成功。 UserService.GetUserLastSignInTime:2018/12/11 22:31:41 info: DotEasy.Rpc.Core.Client.Address.Resolvers.Implementation.DefaultAddressResolver[0] 准備為服務id:doteasy.rpc.interfaces.IUserService.Exists_id,解析可用地址 info: DotEasy.Rpc.Consul.ConsulServiceRouteManager[0] 准備獲取所有路由配置。 info: DotEasy.Rpc.Core.Client.Address.Resolvers.Implementation.DefaultAddressResolver[0] 根據服務id:doteasy.rpc.interfaces.IUserService.Exists_id,找到以下可用地址:127.0.0.1:9881 info: DotEasy.Rpc.Core.Client.Implementation.RemoteInvokeService[0] 使用地址:'127.0.0.1:9881'進行調用 info: DotEasy.Rpc.Transport.Impl.DefaultDotNettyTransportClientFactory[0] 准備為服務端地址:127.0.0.1:9881創建客戶端。 info: DotEasy.Rpc.Transport.Impl.DefaultDotNettyTransportClientFactory[0] 准備發送消息。 info: DotEasy.Rpc.Transport.Impl.DefaultDotNettyTransportClientFactory[0] 准備獲取Id為:4e9a218c4abd4551845008d9bc23c31f的響應內容。 info: DotEasy.Rpc.Transport.Impl.DefaultDotNettyTransportClientFactory[0] 消息發送成功。 UserService.Exists:True info: DotEasy.Rpc.Core.Client.Address.Resolvers.Implementation.DefaultAddressResolver[0] 准備為服務id:doteasy.rpc.interfaces.IUserService.GetDictionary,解析可用地址 info: DotEasy.Rpc.Consul.ConsulServiceRouteManager[0] 准備獲取所有路由配置。 info: DotEasy.Rpc.Core.Client.Address.Resolvers.Implementation.DefaultAddressResolver[0] 根據服務id:doteasy.rpc.interfaces.IUserService.GetDictionary,找到以下可用地址:127.0.0.1:9881 info: DotEasy.Rpc.Core.Client.Implementation.RemoteInvokeService[0] 使用地址:'127.0.0.1:9881'進行調用 info: DotEasy.Rpc.Transport.Impl.DefaultDotNettyTransportClientFactory[0] 准備為服務端地址:127.0.0.1:9881創建客戶端。 info: DotEasy.Rpc.Transport.Impl.DefaultDotNettyTransportClientFactory[0] 准備發送消息。 info: DotEasy.Rpc.Transport.Impl.DefaultDotNettyTransportClientFactory[0] 准備獲取Id為:a625fd4a6bd24e6b82983272b8894562的響應內容。 info: DotEasy.Rpc.Transport.Impl.DefaultDotNettyTransportClientFactory[0] 消息發送成功。 info: DotEasy.Rpc.Core.Communally.Convertibles.Impl.DefaultTypeConvertibleService[0] 准備將 Newtonsoft.Json.Linq.JObject 轉換為:System.Collections.Generic.IDictionary`2[System.String,System.String] UserService.GetDictionary:value
注意加粗的文字,是否跟調用接口一樣的結果呢,其他的調試日志目前請忽略。
四:總結
這樣,通過asp.net core + consul + doteasy.rpc便實現了一個簡單的遠程服務調用,你可以嘗試部署到外網,看看是否是遠程調用,當然,目前並沒有任何的統一網關驗證,所以,任何人的機器都可以調用。
碼字不易,你的推薦是我最大的動力,謝謝。
感謝閱讀!