来源: 基于动态代理的WebAPI/RPC/webSocket框架,一套接口定义,多个通讯方式 – hubro – 博客园
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 处理请求时,进行参数签名验证
客户端接口调用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
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
同样基于上文结构,接口定义就不粘贴了
服务端定义
1
2
3
4
5
6
|
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
1
2
3
4
5
|
<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是一个比较特殊的方式,常用来做双工通讯的方式,客户端能往服务端发送数,服务端也能往客户端发送据
除去服务端往客户端发数据,也可以采用接口调用的形式实现,在这里,服务端往客户端发送数据,客户端采用了订阅的方式
服务端实现
1
2
3
4
5
6
7
8
9
10
11
12
|
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/WebSocket