NET Core微服務之路:本身動手實現Rpc服務框架,基於DotEasy.Rpc服務框架的介紹和集成

原文: NET Core微服務之路:本身動手實現Rpc服務框架,基於DotEasy.Rpc服務框架的介紹和集成

本篇內容屬於非實用性(拿來即用)介紹,如對框架設計沒興趣的朋友,請略過。 html

 

快一個月沒有寫博文了,最近忙着兩件事;
   一:閱讀劉墉先生的《說話的魅力》,以一種微妙的,你我你們都會常常碰見的事物,來建議說話的「藝術和魅力」,對於咱們從事軟件開發、不太善於溝通和表達的朋友來講,也算是一項軟技能了,推薦喜歡閱讀的朋友有時間閱讀,給你不同的閱讀體驗。
二:編寫基於Net Core的Rpc框架。以前有朋友說如何將Rpc等整個體系集成到dotnet框架中,我想這篇博文會給你一個答案。
哦,對了,我不建議直接將代碼直接複製下來而後去運行的朋友,由於這樣你達不到學習的目的,也違背了筆者的初衷。謝謝理解。

 

一:簡單回顧一下以前的介紹

繼續貼上以前的一張圖片 git

 

 

根據上面圖,服務化原理能夠分爲3步:
  1. 服務端啓動而且向註冊中心發送服務信息,註冊中心收到後會定時監控服務狀態(常見心跳檢測);
  2. 客戶端須要開始調用服務的時候,首先去註冊中心獲取服務信息;
  3. 客戶端建立遠程調用鏈接,鏈接後服務端返回處理信息;
 
  第3步又能夠細分,下面說說遠程過程調用的原理:
目標:客戶端怎麼調用遠程機器上的公開方法
  1. 服務發現,向註冊中心獲取服務(這裏須要作的有不少:拿到多個服務時須要作負載均衡,同機房過濾、版本過濾、服務路由過濾、統一網關等);
  2. 客戶端發起調用,將須要調用的服務、方法、參數進行組裝;
  3. 序列化編碼組裝的消息,這裏可使用json,也可使用xml,也可使用protobuf,也可使用hessian,幾種方案的序列化速度還有序列化後佔用字節大小都是選擇的重要指標,對內筆者建議使用高效的protobuf,它基於TCP/IP二進制進行序列化,體積小,速度快。
  4. 傳輸協議,可使用傳統的IO阻塞傳輸,也可使用高效的nio傳輸(Netty);
  5. 服務端收到後進行反序列化,而後進行相應的處理;
  6. 服務端序列化response信息而且返回;
  7. 客戶端收到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甩掉好幾條街吧。
  言歸正傳,一個遠程過程調用,會涉及到以下幾個方面的技術點(功能):
  1. 路由轉發:當服務部署在多個節點上時,調用方須要知道本身的目標服務在什麼地方。
  2. 通訊協議:當管道存在,還須要在管道的兩端創建處理程序(宿主),以處理管道中的數據包。DotEasy.Rpc基於DotNetty進行通訊處理和協議實現。
  3. 動態生成:咱們知道,基於二進制的RPC傳輸,每當新增接口,或修改接口,都須要生成相關協議的protobuf文件(或 thrift 文件),本框架基於protobuf-net的傳輸框架和Rosyln的預生成,動態生成相關的CS文件。
  4. 運行時代理:本框架採用一次請求建立一個客戶端的模式,進行S端的服務請求,本框架基於Rosyln運行時建立客戶端代理。
  5. 接口掃描:須要實現多個接口的添加和註冊,本框架採用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以及核心通用三個部分組成:github

  Client:主要用於經過Ip地址遠程調用的方法Invoke實現,以及遠程服務端的檢查檢查實現。web

  Communally:通用方法庫,包括惟一ID生成器(用於標識每次請求所產生的惟一客戶端)、通用對象轉換器(將複雜對象轉換爲喜歡默認對象)、異常處理器、序列化生成器。json

  Server:提供服務宿主,服務執行者、服務入口處理、服務管理、服務定位、服務管理工廠的接口及默認實現。api

Proxy:運行時預生成及客戶端動態代理模組的接口和方法實現。mvc

Routing:提供地址定位、服務描述、服務路由的接口和方法實現。app

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中集成、等等。
功能和特性以下:
  1. Apache許可證2協議開放源代碼;
  2. 統一組件裝配和構造;
  3. 基於protobuf-net實現字節流序列化;
  4. 基於Rosyln的運行時客戶端代理生成;
  5. 基於Rosyln的預生成的客戶端代理;
  6. 基於DotNetty的傳輸信道;
  7. 支持客戶端以輪詢的方式實現負載平衡;
  8. 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便實現了一個簡單的遠程服務調用,你能夠嘗試部署到外網,看看是不是遠程調用,固然,目前並無任何的統一網關驗證,因此,任何人的機器均可以調用。
 
碼字不易,你的推薦是我最大的動力,謝謝。
感謝閱讀!
相關文章
相關標籤/搜索