NET Core微服务之路:自己动手实现Rpc服务框架,基于DotEasy.Rpc服务框架的介绍和集成...
本篇內(nèi)容屬于非實(shí)用性(拿來即用)介紹,如對框架設(shè)計(jì)沒興趣的朋友,請略過。
?
快一個(gè)月沒有寫博文了,最近忙著兩件事; ?? 一:閱讀劉墉先生的《說話的魅力》,以一種微妙的,你我大家都會經(jīng)常遇見的事物,來建議說話的“藝術(shù)和魅力”,對于我們從事軟件開發(fā)、不太善于溝通和表達(dá)的朋友來說,也算是一項(xiàng)軟技能了,推薦喜歡閱讀的朋友有時(shí)間閱讀,給你不一樣的閱讀體驗(yàn)。 二:編寫基于Net?Core的Rpc框架。之前有朋友說如何將Rpc等整個(gè)體系集成到dotnet框架中,我想這篇博文會給你一個(gè)答案。 哦,對了,我不建議直接將代碼直接復(fù)制下來然后去運(yùn)行的朋友,因?yàn)檫@樣你達(dá)不到學(xué)習(xí)的目的,也違背了筆者的初衷。謝謝理解。?
一:簡單回顧一下之前的介紹
繼續(xù)貼上之前的一張圖片
?
?
根據(jù)上面圖,服務(wù)化原理可以分為3步:二:DotEasy.Rpc框架介紹
單論Rpc框架市場,且不論Java上的Spring?Boot和Spring?Cloud這樣大名鼎鼎的開源框架,目前Net上的Rpc整合性框架確實(shí)并不多,我們Net程序員也要混口飯吃,不能總被Java甩掉好幾條街吧。 言歸正傳,一個(gè)遠(yuǎn)程過程調(diào)用,會涉及到如下幾個(gè)方面的技術(shù)點(diǎn)(功能):?
2.1 解決方案介紹:
整體解決方案不做過多介紹,相信單詞的詞義已經(jīng)表達(dá)了這個(gè)項(xiàng)目的作用。 小插曲:筆者曾用Easy.Rpc做為項(xiàng)目的主庫名稱,但上傳到nuget后才發(fā)現(xiàn),原來也有名為easy.rpc的包,不過筆者并沒找到這個(gè)開源作者的網(wǎng)站,無賴之下,想到“點(diǎn)”這個(gè)詞,也是dotnet的dot開頭部分,索性干脆也叫DotEasy了吧。 筆者的目的,是想通過這個(gè)框架(或類庫集),來簡化微服務(wù)的部署和開發(fā),讓希望從事微服務(wù)NET開發(fā)的朋友不再找不到從何入手的窘境。 在Nuget.org上能直接下載編譯過的包,地址:https://www.nuget.org/packages/DotEasy.Rpc/,推薦使用這種方式進(jìn)行安裝。 如果喜歡研究源碼,筆者同樣也貼上地址:https://github.com/steveleeCN87/doteasy.rpc,不過源碼不包含任何依賴,如果編譯中出現(xiàn)版本問題,可聯(lián)系筆者。目前Github和Nuget上就放上了DotEasy.Rpc核心庫和DotEasy.Rpc.Consul擴(kuò)展包,etcd和entry還在測試階段,就不方便拿出來獻(xiàn)丑了。o(∩_∩)o 哈哈 當(dāng)然,也歡迎廣大愛好開源的朋友加入,共同為NET開源項(xiàng)目做貢獻(xiàn)。?
2.2 主項(xiàng)目介紹:
Attributes:用于標(biāo)注該接口為某一特性的方法體,當(dāng)系統(tǒng)通過Microsoft.Extensions.DependencyInjection自動構(gòu)建成功后,框架將自動掃描接口上標(biāo)注過[RpcTagBundle]的接口,形成目標(biāo)接口列表,以供下面的方法調(diào)用。
Core:該核心分為Server和Client以及核心通用三個(gè)部分組成:
? Client:主要用于通過Ip地址遠(yuǎn)程調(diào)用的方法Invoke實(shí)現(xiàn),以及遠(yuǎn)程服務(wù)端的檢查檢查實(shí)現(xiàn)。
? Communally:通用方法庫,包括唯一ID生成器(用于標(biāo)識每次請求所產(chǎn)生的唯一客戶端)、通用對象轉(zhuǎn)換器(將復(fù)雜對象轉(zhuǎn)換為喜歡默認(rèn)對象)、異常處理器、序列化生成器。
? Server:提供服務(wù)宿主,服務(wù)執(zhí)行者、服務(wù)入口處理、服務(wù)管理、服務(wù)定位、服務(wù)管理工廠的接口及默認(rèn)實(shí)現(xiàn)。
Proxy:運(yùn)行時(shí)預(yù)生成及客戶端動態(tài)代理模組的接口和方法實(shí)現(xiàn)。
Routing:提供地址定位、服務(wù)描述、服務(wù)路由的接口和方法實(shí)現(xiàn)。
Transport:基于protobuf-net和dotnettey構(gòu)建的二進(jìn)制序列化、和通信管道和宿主的接口和實(shí)現(xiàn)。
所有主要類均已接口的形式提供接口名稱,和已默認(rèn)實(shí)現(xiàn)的具體方法體(虛方法),方便在這個(gè)基礎(chǔ)上進(jìn)行擴(kuò)展和重寫。
?
2.3 主項(xiàng)目接口
本節(jié)簡單介紹一下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:所有標(biāo)記過[RpcTagBundle]特性的接口均會被掃描至doteasy.rpc框架中; IAddressResolver.cs:地址解析器,提供IPv4地址解析作用,用于IServiceRouteFactory和IRemoteInvokeService定位操作; IRemoteInvokeService.cs:遠(yuǎn)程調(diào)用服務(wù)接口,提供遠(yuǎn)程服務(wù)調(diào)用的關(guān)鍵接口,通過IServiceProxyFactory接口代理調(diào)用; IServiceEntryFactory.cs:服務(wù)入口工廠接口,對全局服務(wù)入口的統(tǒng)一的工廠操作,例如添加,監(jiān)聽,移除,修改服務(wù)入口等; IServiceEntryLocate.cs:服務(wù)入口定位接口,通過IAddressResolver過濾和解析,實(shí)現(xiàn)服務(wù)入口的定位; IServiceEntryManager.cs:服務(wù)入口管理全局管理接口,功能同IServiceEntryFactory相似,但提供更多的服務(wù)管理操作,比如負(fù)載均衡(采用輪詢實(shí)現(xiàn)); IServiceEntryProvider.cs:服務(wù)入口提供者接口,一個(gè)簡單的服務(wù)入口提供者程序; IServiceExecutor.cs:執(zhí)行服務(wù)方法接口,執(zhí)行遠(yuǎn)程服務(wù)的IRemoteInvokeService; IServiceHost.cs:服務(wù)宿主接口,DotNetty的服務(wù)宿主,類似own框架的自宿主程序,提供請求和響應(yīng)操作; IServiceProxyFactory.cs:服務(wù)代理工廠接口,客戶端代理(預(yù)編譯)的所有操作實(shí)現(xiàn); IServiceProxyGenerater.cs:服務(wù)代理生成接口,客戶端代理(預(yù)編譯)生成器; IServiceRouteFactory.cs:服務(wù)路由工廠接口; IServiceRouteManager.cs:服務(wù)路由全局管理接口; ITransportMessageCodecFactory.cs:管道消息傳輸工廠接口; ITransportMessageDecoder.cs:管道消息解碼器接口; ITransportMessageEncoder.cs:管道消息編碼器接口; IMessageListener.cs:管道消息監(jiān)聽接口,可實(shí)現(xiàn)一個(gè)消息的接受者和處理程序; IMessageSender.cs:管道消息發(fā)送接口,可實(shí)現(xiàn)一個(gè)消息的發(fā)送者; 通過上面的框架和?就能實(shí)現(xiàn)客戶端到服務(wù)端的RPC通信了嗎?當(dāng)然不是,還需要服務(wù)注冊中心(例如Consul,etcd,zookeeper)來實(shí)現(xiàn)。上面只是提供了路由轉(zhuǎn)發(fā),服務(wù)定位,客戶端預(yù)編譯的實(shí)現(xiàn)等等功能而已,而服務(wù)的注冊并沒提供,因?yàn)樗粚儆诨A(chǔ)框架的范疇,筆者對zookeeper的笨重太反感(當(dāng)然不是說它不好),而consul和etcd十分輕量級,特此又專門新增了兩個(gè)項(xiàng)目:DotEasy.Rpc.Consul和DotEasy.Rpc.Etcd,用于實(shí)現(xiàn)不同注冊中心的注冊(獲取)方法,和健康檢測機(jī)制。 當(dāng)然,介紹Consul和Etcd如何實(shí)現(xiàn)不是本節(jié)的重點(diǎn),DotEasy.Rpc這個(gè)框架的完全剖析也將在日后新開篇章中專門介紹如何去實(shí)現(xiàn)一個(gè)框架,想必大部分朋友關(guān)心的是這個(gè)框架能做什么,有什么樣的功能,那么,接下來開始吧。?
三:如何使用
本系列一直重復(fù)的那張圖片,噼里啪啦噼里啪啦......此處省略三百字。繞來繞去,難以入手,正如上一篇有朋友推薦如何在Asp.net core中集成、等等。 功能和特性如下:3.1?建立服務(wù)接口和服務(wù)實(shí)現(xiàn)
既然是服務(wù),那么肯定需要以接口interface的方式實(shí)現(xiàn)對外暴露,并且,接口的實(shí)現(xiàn)不能和接口封裝在同一個(gè)DLL中,不然還叫什么遠(yuǎn)程過程調(diào)用呢(RPC)呢,如果不了解什么叫接口,去翻一翻C#語言規(guī)范。 先定義一個(gè)接口,接口方法簽名如下: 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();} }?
很簡單,不解釋。 其中接口上有個(gè)重要特性叫[RpcTagBundle],該特性只允許標(biāo)記在interface接口上,用于啟動時(shí)方便框架掃描所有標(biāo)有該特性的接口。 在看實(shí)現(xiàn)類 namespace doteasy.rpc.implement {public class UserService : IUserService{public Task<string> GetUserName(int id){return Task.FromResult($"我傳了一個(gè)int數(shù)字{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("嘗試拋出異常!");}} }?
再次重申:注意兩篇代碼中的命名空間,就是兩個(gè)不同的程序集(兩個(gè)項(xiàng)目),千萬不能以為筆者僅僅是為了區(qū)分而已。3.2?建立asp.net core?mvc應(yīng)用程序
新建一個(gè)asp.net core mvc應(yīng)用程序,模版默認(rèn)webapi,添加一個(gè)控制器HeathController,當(dāng)然,控制器名稱你也可以自由發(fā)揮,鍵入如下代碼: namespace doteasy.rpc.webserver.Controllers {[Produces("application/json")][Route("api/Health")]public class HealthController : Controller{[HttpGet]public IActionResult Get() => Ok("ok");} }?
也十分簡單,對外暴露一個(gè)路由地址為"api/Health"的API接口,提供GET方法,返回OK信息。 這個(gè)接口的作用是用于Consul對服務(wù)的健康狀態(tài)檢查回調(diào)地址,Consul可以基于HTTP做健康檢查,也可以通過gRPC驗(yàn)證服務(wù)健康狀態(tài)。 至此,一個(gè)WebApi就建立完成,對外不在通過HTTP做任何接口暴露。 接下來我們添加一個(gè)IApplicationBuilder的擴(kuò)展,用于啟動Rpc服務(wù)端,代碼如下: 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):實(shí)例化一個(gè)BaseServer的服務(wù)類型,并使用IConfiguration作為參數(shù)。該BaseServer類是封裝太DotEasy.Rpc.Entry中的一個(gè)實(shí)現(xiàn),主要是簡化調(diào)用者的代碼構(gòu)建能力,不然,截圖一個(gè)部分源碼瞧瞧 框架的目的是簡化編碼工作,構(gòu)建RPC實(shí)例也不例外,100多行的構(gòu)建代碼只用3行實(shí)現(xiàn),偷懶者必備。 (2):調(diào)用一次RegisterEvent委托事件,用于將接口和實(shí)現(xiàn)注冊到ServiceCollection容器中。 (3):啟動這個(gè)RPC服務(wù),其實(shí)方法內(nèi)還有構(gòu)建ServiceCollection容器等等一大堆方法,你可以自己實(shí)現(xiàn),也可以問筆者要源碼。 配置文件在哪兒,難道這樣就可以了? 當(dāng)然不是,我們還需要一個(gè)appsettings.json的默認(rèn)配置文件,代碼如下: {"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} } 這篇配置文件很容易理解,這里不再重復(fù)啰嗦的解釋。 至此,一個(gè)寄宿于Asp.net core的rpc服務(wù)就這樣搭建完成,可以啟動隨Consul啟動看看。 友情提示:建議將Asp.net core的默認(rèn)日志功能關(guān)閉,否則Consul會5秒發(fā)送一個(gè)健康檢查請求過來,日志會慢慢的變得十分臃腫,ConfigureLogging((context, logging) => { logging.ClearProviders(); })即可移除Logging日志功能。當(dāng)然,你也可以做其他修改,畢竟日志在項(xiàng)目中非常重要。3.3?測試啟動Consul和Asp.net core
consul如何啟動這個(gè),筆者就不再復(fù)述了吧,想必看過之前的文章,應(yīng)該都會啟動和使用consul了,截個(gè)圖,喜悅一下 3.1中的六個(gè)接口全被注冊到consul服務(wù)中,不信,我們訪問一個(gè)具體接口,看看meta信息。 路由和服務(wù)均通過這個(gè)信息進(jìn)行定位,我們可以知道,在127.0.0.1的9881端口上,可以訪問名為“doteasy.rpc.interfaces.IUserService.Exists_id”的接口。當(dāng)然,目前是沒有任何驗(yàn)證機(jī)制的,下一篇會介紹RPC中的統(tǒng)一驗(yàn)證機(jī)制。3.4?建立一個(gè)客戶端
廢話不多說,直接上代碼: 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();}} }?
如你所見,我們就像在調(diào)用接口一樣的去調(diào)用了RPC遠(yuǎn)程服務(wù),中間的所有操作都是透明的,不需要關(guān)心的,唯一多了一句是Proxy<IUserService>();使用代理模式動態(tài)生成了RPC遠(yuǎn)程客戶端,該操作又被筆者封裝在了BaseClient中,一切都為了使用者簡單。3.5?跑跑客戶端看看結(jié)果
info: DotEasy.Rpc.Core.Communally.Convertibles.Impl.DefaultTypeConvertibleService[0]發(fā)現(xiàn)了以下類型轉(zhuǎn)換提供程序: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) 生成服務(wù)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) 生成服務(wù)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) 生成服務(wù)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) 生成服務(wù)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() 生成服務(wù)Id:doteasy.rpc.interfaces.IUserService.GetDictionary info: DotEasy.Rpc.Core.Communally.IdGenerator.Impl.DefaultServiceIdGenerator[0]方法:System.Threading.Tasks.Task TryThrowException() 生成服務(wù)Id:doteasy.rpc.interfaces.IUserService.TryThrowException info: DotEasy.Rpc.Core.Client.Address.Resolvers.Implementation.DefaultAddressResolver[0]準(zhǔn)備為服務(wù)id:doteasy.rpc.interfaces.IUserService.GetUserName_id,解析可用地址 info: DotEasy.Rpc.Consul.ConsulServiceRouteManager[0]準(zhǔn)備獲取所有路由配置。 info: DotEasy.Rpc.Core.Client.Address.Resolvers.Implementation.DefaultAddressResolver[0]根據(jù)服務(wù)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'進(jìn)行調(diào)用 info: DotEasy.Rpc.Transport.Impl.DefaultDotNettyTransportClientFactory[0]準(zhǔn)備為服務(wù)端地址:127.0.0.1:9881創(chuàng)建客戶端。 info: DotEasy.Rpc.Transport.Impl.DefaultDotNettyTransportClientFactory[0]準(zhǔn)備發(fā)送消息。 info: DotEasy.Rpc.Transport.Impl.DefaultDotNettyTransportClientFactory[0]準(zhǔn)備獲取Id為:0b720018feda4e4192937dfbb76eeb66的響應(yīng)內(nèi)容。 info: DotEasy.Rpc.Transport.Impl.DefaultDotNettyTransportClientFactory[0]消息發(fā)送成功。 UserService.GetUserName:我傳了一個(gè)int數(shù)字1. info: DotEasy.Rpc.Core.Client.Address.Resolvers.Implementation.DefaultAddressResolver[0]準(zhǔn)備為服務(wù)id:doteasy.rpc.interfaces.IUserService.GetUserId_userName,解析可用地址 info: DotEasy.Rpc.Consul.ConsulServiceRouteManager[0]準(zhǔn)備獲取所有路由配置。 info: DotEasy.Rpc.Core.Client.Address.Resolvers.Implementation.DefaultAddressResolver[0]根據(jù)服務(wù)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'進(jìn)行調(diào)用 info: DotEasy.Rpc.Transport.Impl.DefaultDotNettyTransportClientFactory[0]準(zhǔn)備為服務(wù)端地址:127.0.0.1:9881創(chuàng)建客戶端。 info: DotEasy.Rpc.Transport.Impl.DefaultDotNettyTransportClientFactory[0]準(zhǔn)備發(fā)送消息。 info: DotEasy.Rpc.Transport.Impl.DefaultDotNettyTransportClientFactory[0]準(zhǔn)備獲取Id為:e14b7606b4d54a66af81bfe3c7df46d4的響應(yīng)內(nèi)容。 info: DotEasy.Rpc.Transport.Impl.DefaultDotNettyTransportClientFactory[0]消息發(fā)送成功。 info: DotEasy.Rpc.Core.Communally.Convertibles.Impl.DefaultTypeConvertibleService[0]準(zhǔn)備將 System.Int64 轉(zhuǎn)換為:System.Int32 UserService.GetUserId:1 info: DotEasy.Rpc.Core.Client.Address.Resolvers.Implementation.DefaultAddressResolver[0]準(zhǔn)備為服務(wù)id:doteasy.rpc.interfaces.IUserService.GetUserLastSignInTime_id,解析可用地址 info: DotEasy.Rpc.Consul.ConsulServiceRouteManager[0]準(zhǔn)備獲取所有路由配置。 info: DotEasy.Rpc.Core.Client.Address.Resolvers.Implementation.DefaultAddressResolver[0]根據(jù)服務(wù)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'進(jìn)行調(diào)用 info: DotEasy.Rpc.Transport.Impl.DefaultDotNettyTransportClientFactory[0]準(zhǔn)備為服務(wù)端地址:127.0.0.1:9881創(chuàng)建客戶端。 info: DotEasy.Rpc.Transport.Impl.DefaultDotNettyTransportClientFactory[0]準(zhǔn)備發(fā)送消息。 info: DotEasy.Rpc.Transport.Impl.DefaultDotNettyTransportClientFactory[0]準(zhǔn)備獲取Id為:d0452b16caeb48ba877da5f69a31b2f8的響應(yīng)內(nèi)容。 info: DotEasy.Rpc.Transport.Impl.DefaultDotNettyTransportClientFactory[0]消息發(fā)送成功。 UserService.GetUserLastSignInTime:2018/12/11 22:31:41 info: DotEasy.Rpc.Core.Client.Address.Resolvers.Implementation.DefaultAddressResolver[0]準(zhǔn)備為服務(wù)id:doteasy.rpc.interfaces.IUserService.Exists_id,解析可用地址 info: DotEasy.Rpc.Consul.ConsulServiceRouteManager[0]準(zhǔn)備獲取所有路由配置。 info: DotEasy.Rpc.Core.Client.Address.Resolvers.Implementation.DefaultAddressResolver[0]根據(jù)服務(wù)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'進(jìn)行調(diào)用 info: DotEasy.Rpc.Transport.Impl.DefaultDotNettyTransportClientFactory[0]準(zhǔn)備為服務(wù)端地址:127.0.0.1:9881創(chuàng)建客戶端。 info: DotEasy.Rpc.Transport.Impl.DefaultDotNettyTransportClientFactory[0]準(zhǔn)備發(fā)送消息。 info: DotEasy.Rpc.Transport.Impl.DefaultDotNettyTransportClientFactory[0]準(zhǔn)備獲取Id為:4e9a218c4abd4551845008d9bc23c31f的響應(yīng)內(nèi)容。 info: DotEasy.Rpc.Transport.Impl.DefaultDotNettyTransportClientFactory[0]消息發(fā)送成功。 UserService.Exists:True info: DotEasy.Rpc.Core.Client.Address.Resolvers.Implementation.DefaultAddressResolver[0]準(zhǔn)備為服務(wù)id:doteasy.rpc.interfaces.IUserService.GetDictionary,解析可用地址 info: DotEasy.Rpc.Consul.ConsulServiceRouteManager[0]準(zhǔn)備獲取所有路由配置。 info: DotEasy.Rpc.Core.Client.Address.Resolvers.Implementation.DefaultAddressResolver[0]根據(jù)服務(wù)id:doteasy.rpc.interfaces.IUserService.GetDictionary,找到以下可用地址:127.0.0.1:9881 info: DotEasy.Rpc.Core.Client.Implementation.RemoteInvokeService[0]使用地址:'127.0.0.1:9881'進(jìn)行調(diào)用 info: DotEasy.Rpc.Transport.Impl.DefaultDotNettyTransportClientFactory[0]準(zhǔn)備為服務(wù)端地址:127.0.0.1:9881創(chuàng)建客戶端。 info: DotEasy.Rpc.Transport.Impl.DefaultDotNettyTransportClientFactory[0]準(zhǔn)備發(fā)送消息。 info: DotEasy.Rpc.Transport.Impl.DefaultDotNettyTransportClientFactory[0]準(zhǔn)備獲取Id為:a625fd4a6bd24e6b82983272b8894562的響應(yīng)內(nèi)容。 info: DotEasy.Rpc.Transport.Impl.DefaultDotNettyTransportClientFactory[0]消息發(fā)送成功。 info: DotEasy.Rpc.Core.Communally.Convertibles.Impl.DefaultTypeConvertibleService[0]準(zhǔn)備將 Newtonsoft.Json.Linq.JObject 轉(zhuǎn)換為:System.Collections.Generic.IDictionary`2[System.String,System.String] UserService.GetDictionary:value?
注意加粗的文字,是否跟調(diào)用接口一樣的結(jié)果呢,其他的調(diào)試日志目前請忽略。四:總結(jié)
這樣,通過asp.net core + consul +?doteasy.rpc便實(shí)現(xiàn)了一個(gè)簡單的遠(yuǎn)程服務(wù)調(diào)用,你可以嘗試部署到外網(wǎng),看看是否是遠(yuǎn)程調(diào)用,當(dāng)然,目前并沒有任何的統(tǒng)一網(wǎng)關(guān)驗(yàn)證,所以,任何人的機(jī)器都可以調(diào)用。 碼字不易,你的推薦是我最大的動力,謝謝。 感謝閱讀!總結(jié)
以上是生活随笔為你收集整理的NET Core微服务之路:自己动手实现Rpc服务框架,基于DotEasy.Rpc服务框架的介绍和集成...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Error APICloud iOS n
- 下一篇: 【Apache】Apache的安装和配置