1. 程式人生 > >基於動態代理的WebAPI/RPC/webSocket框架,一套介面定義,多個通訊方式

基於動態代理的WebAPI/RPC/webSocket框架,一套介面定義,多個通訊方式

API/RPC/webSocket三個看起來好像沒啥相同的地方,在開發時,服務端,客戶端實現程式碼也大不一樣

最近整理了一下,通過動態代理的形式,整合了這些開發,都通過統一的介面約束,服務端實現和客戶端呼叫

基於這樣的形式,WebAPI/RPC/webSocket只需要定義一套介面,就能達到通用的效果

 

 示例介面約束

    public class TestObj
    {
        public string Name { get; set; }
    }
    public interface ITestService
    {
        void Login();
        bool Test1(int a,int? b,out string error);
        TestObj Test2(TestObj obj);
    }
    public class TestService : AbsService, ITestService
    {
        [LoginPoint]
        public void Login()
        {
            SaveSession("hubro", "7777777777", "test");
        }

        public bool Test1(int a, int? b, out string error)
        {
            var user = CurrentUserName;
            var tag = CurrentUserTag;

            error = "out error";
            Console.WriteLine(a);
            Console.WriteLine(b);
            return true;
        }

        public TestObj Test2(TestObj obj)
        {
            Console.WriteLine(obj.ToJson());
            return obj;
        }
    }

上面是一個標準介面和介面實現,並繼承了AbsService,

Login方法標註了LoginPoint特性,表示登入切入點,呼叫此介面時首先得呼叫此方法,方法內SaveSession儲存登入狀態

Test1方法內使用了CurrentUserName,以獲取登入方法儲存的Session

特點:

  • 通過介面約束服務端和客戶端呼叫,引數定義透明化,out也支援
  • 真正的方法遠端呼叫,任意引數型別,個數
  • 整合登入認證邏輯,自定義登入認證過程,也可以自定義Session實現
  • 整合簡單資料簽名,不用費心資料安全問題

技術實現:

  • Dynamitey實現介面型別代理
  • DotNetty實現TCP通訊
  • 物件二進位制序列化

RPC呼叫

服務端

var server = new ServerCreater().CreatetRPC(805);
            server.CheckSign();
            server.SetSessionManage(new SessionManage());
            server.Register<ITestService, TestService>();
            server.Start();

CreateRPC是一個擴充套件方法,引用CRL.RPC獲取

SetSessionManage,自定義Session儲存,預設是記憶體裡

CheckSign 處理請求時,進行引數簽名驗證

客戶端介面呼叫

var clientConnect = new RPCClientConnect("127.0.0.1", 805);
            clientConnect.UseSign();
            var service = clientConnect.GetClient<ITestService>();
        label1:
            service.Login();
            Console.WriteLine("loginOk");
            int? a = 1;
            string error;
            service.Test1(1, a, out error);
            Console.WriteLine("error:" + error);
            var obj2 = service.Test2(new TestObj() { Name = "test" });
            Console.WriteLine("obj2:" + obj2.ToJson());
            Console.ReadLine();
            goto label1;

  

客戶端先呼叫login方法進行登入,並記錄服務端返回的token

Test1方法將token回傳給伺服器以驗證登入狀態,並進行遠端呼叫

當呼叫了UseSign方法,就會對提交的引數進行簽名,簽名KEY為登入後服務端返回的TOKEN,服務端同樣按此對簽名進行比較 

 

動態webApi

同樣基於上文結構,介面定義就不貼上了

服務端定義

var server = new ServerCreater().CreatetApi();
            server.CheckSign();
            server.SetSessionManage(new SessionManage());
            server.Register<ITestService, TestService>();
            var listener = new ServerListener();
            //listener.Start("http://localhost:809/");//自定義監聽

 

如果宿主是.NET網站 在web.config增加處理module

<system.webServer>
    <modules>
      <add name="DynamicModule" type="CRL.DynamicWebApi.DynamicModule" />
    </modules>
  </system.webServer>

  

如果是單獨程式,啟動ServerListener即可

客戶端呼叫

var clientConnect = new CRL.DynamicWebApi.ApiClientConnect("http://localhost:53065");
            //var clientConnect = new CRL.DynamicWebApi.ApiClientConnect("http://localhost:8022");
            clientConnect.UseSign();
            var service = clientConnect.GetClient<ITestService>();
        
        label1:
            service.Login();
            Console.WriteLine("loginOk");
            int? a = 1;
            string error;
            service.Test1(1, a, out error);
            Console.WriteLine("error:" + error);
            var obj2 = service.Test2(new TestObj() { Name = "test" });
            Console.WriteLine("obj2:" + obj2.ToJson());
            Console.ReadLine();
            goto label1;

 

WebSocket

WebSocket是一個比較特殊的方式,常用來做雙工通訊的方式,客戶端能往服務端傳送數,服務端也能往客戶端傳送據

除去服務端往客戶端發資料,也可以採用介面呼叫的形式實現,在這裡,服務端往客戶端傳送資料,客戶端採用了訂閱的方式

服務端實現

var server = new ServerCreater().CreatetWebSocket(8015);
            server.CheckSign();
            server.SetSessionManage(new SessionManage());
            server.Register<ITestService, TestService>();
            server.Start();
            new CRL.Core.ThreadWork().Start("send", () =>
            {
                var socket = server.GetServer() as CRL.WebSocket.WebSocketServer;
                socket.SendMessage("hubro", new socketMsg() { name = DateTime.Now.ToString() }, out string error);
                Console.WriteLine("send msg");
                return true;
            }, 10);

  

上面演示程式碼,服務端開啟了一個執行緒,定時往客戶端"hubro"傳送資料 socket.SendMessage

客戶端實現

var clientConnect = new CRL.WebSocket.WebSocketClientConnect("127.0.0.1", 8015);
            clientConnect.UseSign();
            clientConnect.SubscribeMessage<socketMsg>((obj) =>
            {
                Console.WriteLine("OnMessage:" + obj.ToJson());
            });
            clientConnect.StartPing();
            var service = clientConnect.GetClient<ITestService>();
        label1:

            service.Login();
            Console.WriteLine("loginOk");
            int? a = 1;
            string error;
            service.Test1(1, a, out error);
            Console.WriteLine("error:" + error);
            var obj2 = service.Test2(new TestObj() { Name = "test" });
            Console.WriteLine("obj2:" + obj2.ToJson());
            Console.ReadLine();
            goto label1;

clientConnect.SubscribeMessage就是訂閱訊息了,通過訂閱的方式,處理服務端傳送的資料

 

可以看到以上各種形式,服務端實現和客戶端呼叫基本相同,定義的介面能重複使用,做介面通訊效果槓槓的

具體實現方式和細節功能參見原始碼和demo,已經開源,請自行下載

原始碼地址:

CRL:

https://github.com/hubro-xx/CRL5

RCP:

https://github.com/hubro-xx/CRL5/tree/master/RPC

WebAPI:

https://github.com/hubro-xx/CRL5/tree/master/DynamicWebApi

WebSocket:

https://github.com/hubro-xx/CRL5/tree/master/WebSo