BeetleX之XRPC使用详解
XRPC
是基于BeetleX
扩展一个远程接口调用组件,它提供基于接口的方式来实现远程服务调用,在应用上非常简便。组件提供.NETCore2.1
和.NETStandard2.0
的client版本,因此即使在winfrom
和wpf
也可以使用该组件进行服务调用处理。接下来详细讲解一下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
和它创建的接口都是线程安全的,因此只需要定义一个即可在并发中使用。
参数编码
组件提供json
和messagepack
作为参数传递的编码,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
创建两个实例,分别是:henry
和ken
.服务端会根据请求的标识在服务端维护各自的actor
实例。多客户端同时创建相同名称的actor
实例怎办?即是多客户端同时创建同一名称的actor
和并发调用,服务端都可保证actor
实例的唯一性(实际应用需要涉及到actor
的状态,信息持久化等,这些就不在这里讨论;XRPC
的这一功能则由https://github.com/IKende/EventNext 提供)。
在WPF中调用
有时候需要在winfrom
或wpf
中调用服务,这个时候就需要通过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使用详解的更多相关文章
- BeetleX之HttpClusterApi应用详解
之前的文章已经介绍过如何使用HttpClusterApi进行去中心化的HTTP集群服务访问,这一章主要详细讲述如何使用HttpClusterApi,主要包括如何定义节点,创建服务接口和使用接口描述不同 ...
- Linq之旅:Linq入门详解(Linq to Objects)
示例代码下载:Linq之旅:Linq入门详解(Linq to Objects) 本博文详细介绍 .NET 3.5 中引入的重要功能:Language Integrated Query(LINQ,语言集 ...
- 架构设计:远程调用服务架构设计及zookeeper技术详解(下篇)
一.下篇开头的废话 终于开写下篇了,这也是我写远程调用框架的第三篇文章,前两篇都被博客园作为[编辑推荐]的文章,很兴奋哦,嘿嘿~~~~,本人是个很臭美的人,一定得要截图为证: 今天是2014年的第一天 ...
- EntityFramework Core 1.1 Add、Attach、Update、Remove方法如何高效使用详解
前言 我比较喜欢安静,大概和我喜欢研究和琢磨技术原因相关吧,刚好到了元旦节,这几天可以好好学习下EF Core,同时在项目当中用到EF Core,借此机会给予比较深入的理解,这里我们只讲解和EF 6. ...
- Java 字符串格式化详解
Java 字符串格式化详解 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 文中如有纰漏,欢迎大家留言指出. 在 Java 的 String 类中,可以使用 format() 方法 ...
- Android Notification 详解(一)——基本操作
Android Notification 详解(一)--基本操作 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 源码:AndroidDemo/Notification 文中如有纰 ...
- Android Notification 详解——基本操作
Android Notification 详解 版权声明:本文为博主原创文章,未经博主允许不得转载. 前几天项目中有用到 Android 通知相关的内容,索性把 Android Notificatio ...
- Git初探--笔记整理和Git命令详解
几个重要的概念 首先先明确几个概念: WorkPlace : 工作区 Index: 暂存区 Repository: 本地仓库/版本库 Remote: 远程仓库 当在Remote(如Github)上面c ...
- Drawable实战解析:Android XML shape 标签使用详解(apk瘦身,减少内存好帮手)
Android XML shape 标签使用详解 一个android开发者肯定懂得使用 xml 定义一个 Drawable,比如定义一个 rect 或者 circle 作为一个 View 的背景. ...
随机推荐
- Session机制在页面间保持Cookie——大街网
解决Cookie有效期,页面间Cookie传递 解決大规模,长期有效采集. 之前做一个项目,要采集招聘网站的职位信息,智联,拉钩,中华英才,BOOS,大街网,写完了前4个,大街网数据加载方式是AJAX ...
- 洛谷P3366 【模板】最小生成树(kuskal)
#include<bits/stdc++.h> using namespace std; ; ; struct node{ int cnt,fa; }f[maxn]; inline voi ...
- Python 进阶02 文本文件的输入输出
Python 具有基本的文本文件读写功能,Python的标准库提供有更丰富的读写功能. 文本文件的读写主要通过open()所构建的文件对象来实现 创建文件对象 我们打开一个文件,并适用一个对象来表示该 ...
- shell去掉最后一个字符
实测过第一种写法,可正常删除 sed 's/.$//' awk '{sub(/.$/,"")}1' awk '{printf $0"\b \n"}' ufile ...
- Android教程 -04 启动其它Activity,静态工厂设计模式传递数据
视频建议采用超清模式观看, 欢迎点击订阅我的优酷 意图 Intent 一个应用程序肯定不只有一个界面,如何切换到其它界面,只时候就需要启动其它的Activity.启动Activity有多种方式.我在这 ...
- Jquery FormData文件异步上传 快速指南
网站中文件的异步上传是个比较麻烦的问题,不过现在通过jquery 可以很容易的解决这个问题: 使用jquery2.1版本,较老版本不支持异步文件上传功能: 表单代码: <form id=&quo ...
- 一个div居于另一个div底部
一个div如何与另一个div底部对齐,方法有很多,比如使用绝对定位 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional/ ...
- css模仿ipad的日历
https://www.cnblogs.com/sandraryan/ 题外话之:最近的练习用js之类的写起来会简单点,但是为了巩固基础,只好html和css硬怼页面X﹏X 这是一个日历的代码 注释有 ...
- python基础十一之装饰器进阶
函数的双下划线方法 def hahahha(): """测试函数""" print('zxc') print(hahahha.__name_ ...
- SourceYard 制作源代码包
本文带大家走进SourceYard开发之旅 在项目开发中,将一个大的项目拆为多个小项目解耦,减少模块之间的耦合.因为如果将代码放在一起,即使有团队的约束,但只要能写出的代码就会有小伙伴写出,很快就发现 ...