XRPC是基于BeetleX扩展一个远程接口调用组件,它提供基于接口的方式来实现远程服务调用,在应用上非常简便。组件提供.NETCore2.1.NETStandard2.0的client版本,因此即使在winfromwpf也可以使用该组件进行服务调用处理。接下来详细讲解一下XRPC使用,从简单的hello到桌面wpf调用服务、ssl通讯安全和对象注入等功能。

引用组件

组件提供了两个版本BeetleX.XRPC对应.NETCore2.1它同时提供服务和客户端调用功能,BeetleX.XRPC.Clients是对应Standard2.0客户端版本,专门针对桌面应用调用而开发。除了这两个组件外还提供了BeetleX.XRPC.Hosting,这个组件专门为XRPC服务提供以Hosting方式运行的支持,如果你想使用DI那也可以通过这个组件实现。

Hello

很多程序的开始都是以Hello来展示使用,接下来就使用组件构建一个Hello的通讯服务。组件的所有服务都需要通过接口来描述,所以在制定服务前需要用接口来描述一下服务需求:

    public interface IHello
{
Task<string> Hello(string name);
}

以上是一个Hello服务接口的定义(接口定义要求是所有方法都必须以Task<T>Task作为返回值)。服务实现

    [Service(typeof(IHello))]
public class HelloImpl : IHello
{
public Task<string> Hello(string name)
{
return $"hello {name} {DateTime.Now}".ToTask();
}
}

以上是实现服务细节,接下来通过以下代码启动服务:

        static void Main(string[] args)
{
var builder = new HostBuilder()
.ConfigureServices((hostContext, services) =>
{
services.UseXRPC(s =>
{
s.ServerOptions.LogLevel = BeetleX.EventArgs.LogType.Trace;
s.ServerOptions.DefaultListen.Port = ;
s.RPCOptions.ParameterFormater = new JsonPacket();//default messagepack
},
typeof(Program).Assembly);
});
builder.Build().Run();
}

以上是在所有IP.Any上的9090端口提供服务。接下来的工作就是如何调用它,XRPC在使用上设计非常方便,所以在调用上会变得非常简单.

            client = new XRPCClient("localhost", );
client.Options.ParameterFormater = new JsonPacket();//default messagepack
hello = client.Create<IHello>();
while (true)
{
Console.Write("Enter you name:");
var name = Console.ReadLine();
var result = await hello.Hello(name);
Console.WriteLine(result);
}

只需要指定XRPCClient对应的服务地址和端口,并创建接口即可调用。XRPCClient和它创建的接口都是线程安全的,因此只需要定义一个即可在并发中使用。

参数编码

组件提供jsonmessagepack作为参数传递的编码,messagepack是默认编码使这种编码序列化对象可以达到非常好的效率,但这种编码需要对类的属性进行标记使用也相对麻烦;如果对效率要求不高不想对类进行属性标记可以设置成Json.如果想实现自己的编码方式可以通过实现以下接口:

    public interface IParameterFormater
{
void Encode(Options rpcOption, object data, PipeStream stream); object Decode(Options rpcOption, Type type, ArraySegment<byte> data);
}

创建Actor模式对象

Actor是一种非常高效的业务处理模型,每个实例有着独立线程资源,其行所有为是串行操作,所以它这种线程独立性和无锁机制非常适合高并发业务处理;XPRC支持远程Actor创建,并在服务端维持其独立性,在多客户端同时调用同一Actor行为时服务端会保证其自有的特性运行。

    public interface IAmount
{
Task Income(int value);
Task Pay(int value);
Task<int> GetValue();
}

以上是一个简单的数量增加接口,实现的服务如下:

    [Service(typeof(IAmount))]
public class AmountImpl : IAmount
{ private int mAmount; public Task<int> GetValue()
{
return mAmount.ToTask();
} public Task Income(int value)
{
mAmount -= value;
return Task.CompletedTask;
} public Task Pay(int value)
{
mAmount += value;
return Task.CompletedTask;
}
}

组件在actor应用并没有特殊的要求,主要是客户端在创建的时候告诉服务端需要创建一个指标识的actor实例即可,代码如下:

            client = new XRPCClient("localhost", );
client.Options.ParameterFormater = new JsonPacket();//default messagepack
henry = client.Create<IAmount>("henry");
ken = client.Create<IAmount>("ken");

以上是针对IAmount创建两个实例,分别是:henryken.服务端会根据请求的标识在服务端维护各自的actor实例。多客户端同时创建相同名称的actor实例怎办?即是多客户端同时创建同一名称的actor和并发调用,服务端都可保证actor实例的唯一性(实际应用需要涉及到actor的状态,信息持久化等,这些就不在这里讨论;XRPC的这一功能则由https://github.com/IKende/EventNext 提供)。

在WPF中调用

有时候需要在winfromwpf中调用服务,这个时候就需要通过BeetleX.XRPC.Clients来实现调用;它所提供的功能和BeetleX.XRPC内置的客户端功能是一样的。接下来做一个简单的数据查询,不过这个示例为了符合客户端的需求还针对方法添加了JWT验证的功能。

    public interface IDataService
{
Task<string> Login(string name, string pwd); Task<List<Employee>> List();
}

以上是一个简单的数据查询接口,里面添加了一个登陆方法.

    [Service(typeof(IDataService))]
[TokenFilter]
public class DataServiceImpl : IDataService
{
public Task<List<Employee>> List()
{
return DataHelper.Defalut.Employees.ToTask();
} [SkipActionFilter(typeof(TokenFilter))]
public Task<string> Login(string name, string pwd)
{
string token = null;
if (name == "admin" && pwd == "")
token = JWTHelper.Default.CreateToken(name, "admin");
return token.ToTask(); }
}

以上是对应的服务实现,但这个服务多了个TokenFilter属性;这个属性是一个过虑器用于验证请求的,Login方法就移走了这个验证过虑器。接下来看来下这个属性的代码:

    public class TokenFilter : ActionFilterAttribute
{
public override bool Executing(EventCenter center, EventActionHandler handler, IEventInput input, IEventOutput output)
{
string token = null;
input.Properties?.TryGetValue("token", out token);
var user = JWTHelper.Default.GetUserInfo(token);
if (user!=null)
{
return base.Executing(center, handler, input, output);
}
else
{
output.EventError = EventError.InnerError;
output.Data = new object[] { "操作错误,无权操作相关资源!" };
return false;
}
}
}

过虑器逻辑比较简单就是获取请求头的token属性是否有效,如果有则通过请求没有则拒绝请求。接下来看一下WPF的使用代码:

        private IDataService dataService;

        private XRPCClient XRPCClient;

        private void Window_Loaded(object sender, RoutedEventArgs e)
{
XRPCClient = new XRPCClient("localhost", );
XRPCClient.Options.ParameterFormater = new JsonPacket();
dataService = XRPCClient.Create<IDataService>();
} private async void CmdSearch_Click(object sender, RoutedEventArgs e)
{
try
{
var data = await dataService.List();
lstEmployees.ItemsSource = data;
}
catch (Exception e_)
{
MessageBox.Show(e_.Message);
}
} private async void CmdLogin_Click(object sender, RoutedEventArgs e)
{
try
{
var token = await dataService.Login(txtName.Text, txtPwd.Text);
txtToken.Content = token;
((IHeader)dataService).Header["token"] = token;
}
catch(Exception e_)
{
MessageBox.Show(e_.Message);
}
}

代码其实很简单,在窗体构建的时候创建一个XRPCClient并创建对应的接口实例;在这里这里主要是关心token的传递,因为接口上并没有方法可以这样做;其实所有代理接口都实现了一个IHeader接口,只需要做一个显式的转换并在Header上设置对应名称的值即可.

ssl的支持

安全的通讯在服务交互中是必不可少的,XRPC通过支持ssl来解决这一问题;由于这功能是BeetleX的基础核心,所以组件不需要太过于关注只需要简单配置一下证书即可:

     static void Main(string[] args)
{
var builder = new HostBuilder()
.ConfigureServices((hostContext, services) =>
{
services.UseXRPC(s =>
{
JWTHelper.Init();
s.ServerOptions.LogLevel = BeetleX.EventArgs.LogType.Trace;
s.ServerOptions.DefaultListen.Port = ;
s.ServerOptions.DefaultListen.SSL = true;
s.ServerOptions.DefaultListen.CertificateFile = "test.pfx";
s.ServerOptions.DefaultListen.CertificatePassword = "";
s.RPCOptions.ParameterFormater = new JsonPacket();//default messagepack
},
typeof(Program).Assembly);
});
builder.Build().Run();
}

只要在服务中配置好证书和对应的密码即可,服务在启动的时候会看到具体的情况:

服务启用ssl后,客户端在创建XRPCClient指定sslServiceName即可,代码如下:

            XRPCClient = new XRPCClient("localhost", , "test");
XRPCClient.CertificateValidationCallback = (s, certificate, chain, sslPolicyErrors) => true;
XRPCClient.Options.ParameterFormater = new JsonPacket();
dataService = XRPCClient.Create<IDataService>();

当无法确定sslServiceName的时候需要添加CertificateValidationCallback委托自己定义验证返回的结果。

对象注入

由于服务对象的创建是由组件托管的,所以很多时候需要对接口服务添加不同的参数和属性方便功能集成。用户可以通过以下事件来服务类创建:

        XRPCServer.EventCenter.ServiceInstance

其实组件提供了BeetleX.XRPC.Hosting扩展来成这功能,通过这个扩展在服务启动时进行注册,代码如下:

            var builder = new HostBuilder()
.ConfigureServices((hostContext, services) =>
{
services.AddSingleton(new User { Name = "BeetleX" });
services.UseXRPC(s =>
{
//...
},
typeof(Program).Assembly);
});
builder.Build().Run();

通过services可以给DI容器添注入需要的对象,当容器注册后就可以在服务类的构建函数中定义需要的参数:

    [Service(typeof(IHello))]
public class HelloImpl : IHello
{
public HelloImpl(BeetleX.XRPC.XRPCServer server, User user)
{
mServer = server;
mUser = user;
}
}

以上讲述了XRPC的使用情况,详细代码可以访问 https://github.com/IKende/BeetleX-Samples

BeetleX之XRPC使用详解的更多相关文章

  1. BeetleX之HttpClusterApi应用详解

    之前的文章已经介绍过如何使用HttpClusterApi进行去中心化的HTTP集群服务访问,这一章主要详细讲述如何使用HttpClusterApi,主要包括如何定义节点,创建服务接口和使用接口描述不同 ...

  2. Linq之旅:Linq入门详解(Linq to Objects)

    示例代码下载:Linq之旅:Linq入门详解(Linq to Objects) 本博文详细介绍 .NET 3.5 中引入的重要功能:Language Integrated Query(LINQ,语言集 ...

  3. 架构设计:远程调用服务架构设计及zookeeper技术详解(下篇)

    一.下篇开头的废话 终于开写下篇了,这也是我写远程调用框架的第三篇文章,前两篇都被博客园作为[编辑推荐]的文章,很兴奋哦,嘿嘿~~~~,本人是个很臭美的人,一定得要截图为证: 今天是2014年的第一天 ...

  4. EntityFramework Core 1.1 Add、Attach、Update、Remove方法如何高效使用详解

    前言 我比较喜欢安静,大概和我喜欢研究和琢磨技术原因相关吧,刚好到了元旦节,这几天可以好好学习下EF Core,同时在项目当中用到EF Core,借此机会给予比较深入的理解,这里我们只讲解和EF 6. ...

  5. Java 字符串格式化详解

    Java 字符串格式化详解 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 文中如有纰漏,欢迎大家留言指出. 在 Java 的 String 类中,可以使用 format() 方法 ...

  6. Android Notification 详解(一)——基本操作

    Android Notification 详解(一)--基本操作 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 源码:AndroidDemo/Notification 文中如有纰 ...

  7. Android Notification 详解——基本操作

    Android Notification 详解 版权声明:本文为博主原创文章,未经博主允许不得转载. 前几天项目中有用到 Android 通知相关的内容,索性把 Android Notificatio ...

  8. Git初探--笔记整理和Git命令详解

    几个重要的概念 首先先明确几个概念: WorkPlace : 工作区 Index: 暂存区 Repository: 本地仓库/版本库 Remote: 远程仓库 当在Remote(如Github)上面c ...

  9. Drawable实战解析:Android XML shape 标签使用详解(apk瘦身,减少内存好帮手)

    Android XML shape 标签使用详解   一个android开发者肯定懂得使用 xml 定义一个 Drawable,比如定义一个 rect 或者 circle 作为一个 View 的背景. ...

随机推荐

  1. Google 各国地址

    google各国域名大全 香港www.google.com.hk 台湾www.google.com.tw 日本www.google.co.jp 中国www.google.cn 韩国www.google ...

  2. @bzoj - 5219@ [Lydsy2017省队十连测]最长路径

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 在Byteland一共有n个城市,编号依次为1到n,形成一个n个 ...

  3. 如何使用jmeter调用soap协议

  4. 二叉堆&&左偏堆 代码实现

    今天打算学习左偏堆,可是想起来自己二叉堆都没有看懂,于是就跑去回顾二叉堆了.发现以前看不懂的二叉堆,今天看起来特简单,随手就写好了一个堆了. 简单的说一下我对二叉堆操作的理解.我不从底层函数说上去,相 ...

  5. redux【react】

    首先介绍一下redux就是Flux的一种进阶实现.它是一个应用数据流框架,主要作用应用状态的管理 一.设计思想: (1).web应用就是一个状态机,视图和状态一一对应 (2).所有的状态保存在一个对象 ...

  6. Python数据可视化matplotlib和seaborn

    Python在数据科学中的地位,不仅仅是因为numpy, scipy, pandas, scikit-learn这些高效易用.接口统一的科学计算包,其强大的数据可视化工具也是重要组成部分.在Pytho ...

  7. 怎样判断一个jquery对象是否为空jquery对象

    if ( $('#myDiv').length ){} http://stackoverflow.com/questions/47... 也可以直接判断$('#myDiv')[0]===undefin ...

  8. H3C 单区域OSPF配置示例一

  9. P1091 剧院广场

    题目描述 柏林首都的剧院广场呈长方形,面积为 \(n \times m\) 平方米.在这座城市的周年纪念日之际,人们决定用方形花岗岩石板铺设广场.每块石板的大小都是 \(a \times a\) . ...

  10. P1000 A+B Problem

    题目描述 给定两个整数\(a,b\),输出它们的和. 输入格式 输入两个整数,表示\(a,b(1 \le a,b \le 10^9)\). 输出格式 输出一个整数,表示答案. 样例输入 20 30 样 ...