ApiClient搭配ApiServer构成RPC框架。
Nuget包:NewLife.Remoting
源码地址:https://github.com/NewLifeX/NewLife.Remoting/blob/master/NewLife.Remoting/ApiClient.cs
建议提前阅读《RPC通信ApiServer》。
快速入门
新建控制台项目,写入以下代码:
using NewLife.Data;
using NewLife.Log;
using NewLife.Net;
using NewLife.Remoting;
using System;
using System.Linq;
using System.Net;
namespace NewLife.RPC
{
class Program
{
static void Main(string[] args)
{
XTrace.UseConsole();
var netUri = new NetUri(NetType.Tcp, IPAddress.Any, 5001);
using var server = new ApiServer(netUri)
{
Log = XTrace.Log,
EncoderLog = XTrace.Log,
ShowError = true
};
server.Register<BigController>();
server.Start();
ClientTest();
Console.ReadKey();
}
static void ClientTest()
{
var client = new MyClient("tcp://127.0.0.1:5001")
{
Log = XTrace.Log,
EncoderLog = XTrace.Log
};
client.Received += (s, e) =>
{
XTrace.WriteLine("通知:{0} 参数:{1}", e.ApiMessage.Action, e.ApiMessage.Data.ToStr());
};
var rs = client.Invoke<Int32>("Big/Sum", new { a = 123, b = 456 });
XTrace.WriteLine("{0}+{1}={2}", 123, 456, rs);
}
class MyClient : ApiClient
{
public MyClient(String urls) : base(urls) { }
}
class BigController : IApi
{
public IApiSession Session { get; set; }
public int Sum(int a, int b)
{
Task.Run(async () =>
{
await Task.Delay(1000);
Session.InvokeOneWay("test", new { name = "Stone", company = "NewLife" }, 3);
});
return a + b;
}
public string ToUpper(string str) => str.ToUpper();
public Packet Test(Packet pk)
{
var buf = pk.ReadBytes().Select(e => (Byte)(e ^ 'x')).ToArray();
return buf;
}
}
}
}
这里的重点是客户端调用:client.Invoke<Int32>("Big/Sum", new { a = 123, b = 456 })
新生命RPC框架的客户端调用,只有一个 Invoke (异步InvokeAsync),指定接口名并传入参数对象即可。这就是客户端的全部,没有描述文件生成代码,也不需要客户端服务端共用接口文件!
当然,只要你喜欢,可以搞一套接口,让客户端和服务端控制器都实现。这么做,比较麻烦的地方在于修改接口时需要同时改几个地方。客户端服务端还可以共享出入参模型类,这也是常见做法。由于默认采用Json序列化,因此两头可以使用各自的模型类,只要字段名对得上即可,完全避免了客户端服务端升级版本不匹配所带来的各种问题。
下行通知
修改前面的示例,加上服务端主动下发代码:
class BigController : IApi
{
public IApiSession Session { get; set; }
public int Sum(int a, int b)
{
Task.Run(async () =>
{
await Task.Delay(1000);
Session.InvokeOneWay("test", new { name = "Stone", company = "NewLife" }, 3);
});
return a + b;
}
}
在Sum接口内,调用了 Session.InvokeOneWay。客户端也需要修改一下:
static void ClientTest()
{
var client = new MyClient("tcp://127.0.0.1:5001")
{
Log = XTrace.Log,
EncoderLog = XTrace.Log
};
var rs = client.Invoke<Int32>("Big/Sum", new { a = 123, b = 456 });
XTrace.WriteLine("{0}+{1}={2}", 123, 456, rs);
}
class MyClient : ApiClient
{
public MyClient(String urls) : base(urls) { }
protected override void OnReceive(IMessage message)
{
if (Encoder.Decode(message, out var action, out _, out var args))
{
XTrace.WriteLine("通知:{0} 参数:{1}", action, args.ToStr());
}
}
}
MyClient类继承自ApiClient,重写了 OnReceive 方法,所有未经处理的消息,都将进入这里。使用编码器解码后即可得到想要的数据。