# OF.JsonRpc **Repository Path**: fxh/OF.JsonRpc ## Basic Information - **Project Name**: OF.JsonRpc - **Description**: 本项目是依据 《JSON-RPC 2.0 Specification》 的 .NET 实现, 它是基于 HTTP (也能支持本地调用和TCP)方式实现的轻量级松耦合的远程调用服务框架,提供了高效可用、无侵入式的方式搭建自己的服务平台,可以快速开发、调试、发布、调用服务,保持轻量级及可定制性。可以基于它构建 .NET 平台的微服务或 API。 - **Primary Language**: C# - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 9 - **Created**: 2018-08-28 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # OF.JsonRpc 本项目是依据 [《JSON-RPC 2.0 Specification》](http://www.jsonrpc.org/specification) 的 .NET 实现, 它是基于 HTTP (也能支持本地调用和TCP)方式实现的轻量级松耦合的远程调用服务框架,提供了高效可用、无侵入式的方式搭建自己的服务平台,可以快速开发、调试、发布、调用服务,保持轻量级及可定制性。可以基于它构建 .NET 平台的微服务或 API。 ## 重要特性 * 支持目前支持 HTTP 和本地调用 * 强大的自动生成服务描述能力 * 支持 RSA 和自定义授权机制 * 支持自定义上下文 ## 如何开发实现服务 1.创建新的或使用原有的 Class Library 工程,如 OF.Microservices.DemoService,该工程并不强制要求引用外部依赖包 OF.JsonRpc.dll ,然后在项目属性中进行设置, build 属性页 > Output > 勾选中 Xml documentation file,以便能自动生成在线文档。 2.在刚才创建的 OF.JsonRpc 工程中,创建一个自己的的服务类,并实现 public 的方法,写方法对应的 XML 注释,如下: ```csharp namespace OF.Microservices.DemoService { /// /// 演示服务1 /// public class Demo1 { /// /// 输出两个参数的值 /// /// 参数1 /// 参数2 /// 返回参数1和参数2的信息 public string Method1(string param1, string param2) { return $"param1: {param1}, param2: {param2}"; } } } ``` 3.将本项目中的工程 OF.Microservices.Host 设为 IIS 的 Web 站点。并配置 jsonrpc.config 文件,在 serviceAssemblies 节点下配置需要暴露的服务实现 dll 程序集名称,jsonrpc.config 配置文件示例如下: ```xml ``` 4.然后用浏览器打开该网站的根地址,如:http://localhost:60282 即可查看服务的说明文档。 5.服务暴露的地址形如: http://localhost:60282/json.rpc ## 客户端 C# 的调用 详细请参见 OF.JsonRpc\OF.JsonRpc.ClientTest\CallDemoTest.cs 中的代码。需要在客户端引入 OF.JsonRpc.Client 程序集,并在 app.config/web.config 配置服务地址: ```xml ``` 调用的代码很简单,并不需要定义什么接口,完全松耦合的方式,Rpc.Call对应的参数为方法名及按顺序的参数即可。 示例如下: ```csharp // 调用服务,输入2个参数,返回一个字符串 var result1 = Rpc.Call( "Demo.Demo1.Method1", "Jack","John"); // 调用服务,无返回值 Rpc.Call("Demo.Demo1.Method2", "Jack"); // 调用服务,返回一个匿名 dynamic 对象 var result = Rpc.Call( "Demo.Demo1.Method3", //JSON-RPC方法名 new { Name = "Jack", Email = "Jack@gmail.com", MobilePhone = "12306" }); // JSON-RPC的参数, Console.WriteLine("result value, OrderNumber:" + result.OrderId); Console.WriteLine("Customer.UserName:" + result.Customer.Name); Console.WriteLine("Customer.Email:" + result.Customer.Email); Console.WriteLine("Customer.MobilePhone:" + result.Customer.MobilePhone); // 异常处理 try { var result1 = Rpc.Call( "Demo.Demo1.Method1", "Jack","John"); Console.WriteLine("result value:" + result1); } catch (JsonRpcException jsonRpcException) { if (jsonRpcException.code == 32000) Console.WriteLine("result business excetion:" + jsonRpcException.message); else Console.WriteLine("调用服务发生异常,{0}, {1}", jsonRpcException.message, jsonRpcException.data); } // 将参数为命名的对象属性进行调用 string result2 = Rpc.CallWithDeclaredParams( "Demo.Demo1.Method1", new { param2 = "John", param1 = "Jack" }); ``` ### 浏览 JSON-RPC Help 文档 打开浏览器地址: http://localhost:60282 后进行文档首页,可以过滤 ![help-index](https://gitee.com/OFProject/OF.JsonRpc/raw/master/doc/images/help-index.png) 进入方法的详细说明: ![help-method](https://gitee.com/OFProject/OF.JsonRpc/raw/master/doc/images/help-method.png) 进入参数或返回值的类型说明: ![help-type](https://gitee.com/OFProject/OF.JsonRpc/raw/master/doc/images/help-type.png) ### Java 调用 因为使用的统一的 JSON-RPC HTTP 协议,所以使用一些三方的库,推荐:https://github.com/briandilley/jsonrpc4j ```java JsonRpcHttpClient client = new JsonRpcHttpClient( new URL("http://example.com/UserService.json")); User user = client.invoke("createUser", new Object[] { "bob", "the builder" }, User.class); ``` ### Javascript 调用 可以直接使用第三方库,推荐:https://github.com/datagraph/jquery-jsonrpc 示例: ```javascript $.jsonRPC.request('method.name', { params: params, success: function(result) { // Do something with the result here // It comes back as an RPC 2.0 compatible response object }, error: function(result) { // Result is an RPC 2.0 compatible response object } }); ``` ### 网关与授权 这里的网关是微服务内部实现的一种预处理机制,并不存在单独的网关服务。比如,有个微服务方法叫:EC.Order.Create,那么在服务端接收到调用请求时,会调用网关层去做一些处理,可以是授权验证,也可以是记日志,或者是触发另一个服务等。 框架中目前内置两个授权验证的网关,分别是 1) 证书验签网关,由OF.JsonRpc.Gateway.SignatureAuthGateway类实现; 2) 最简单的用户名密码验证网关,可用于开发时测试或场景简单时,由OF.JsonRpc.Gateway.TestAuthGateway类实现。 可以根据需求选择一种授权网关或自定义自己的授权验证网关。 #### 证书验证网关的使用 * 步骤1:在服务端启用证书验证。 在`jsonrpc.config`的`jsonrpc`节点内添加以下配置: ```xml ``` * 步骤2:在服务端存放客户端的公钥。 在在服务Web根目录下创建keys目录,将客户端的公钥证书放在里面,但必须按照指定的命名规则即:`public_key_{auth_client_id}.pem`,将{auth_client_id}替换成客户端访问ID,客户端访问ID可以随便定义,只能由数字和字母构建,不能有空格等,如可以a001。 我们最终能看到:`keys\public_key_a001.pem`文件。 证书的生成可以参考网上的文章,从而生成RSA算法的base64文本证书格式,证书不要设密码,私钥+公钥。 方法很多,可以用openssl,也可以用java的keytool,用windows的证书管理工具也可以,较简单的方式是使用在线工具:http://travistidwell.com/jsencrypt/demo/ openssl使用方式如下: ``` openssl genrsa -out rsa_1024_priv.pem 1024 openssl rsa -pubout -in rsa_1024_priv.pem -out rsa_1024_pub.pem ``` * 步骤3:在客户端放私钥。 在程序根目录下(或Web根目录下)创建keys目录,将客户端的私钥证书放在里面,但必须按照指定的命名规则即:`private_key_{auth_client_id}.pem`,将{auth_client_id}替换成客户端访问ID。 我们最终能看到:`keys\private_key_a001.pem`文件。 * 步骤4:配置客户端的访问ID。:修改`app.config`(或者`web.config`)中的,在`appSettings`节点内添加以下节点: ```xml ``` 把{auth_client_id}替换成当前客户端访问ID。 #### 高级使用,如何自定义授权验证网关 可以自定义网关类,为了简化操作,可以直接继承`OF.JsonRpc.Gateway.BaseAuthGateway`,参考下例的实现 ```csharp public class TestAuthGateway : BaseAuthGateway { protected override void VerifyAuth(JsonRequest jsonRequest) { // 访问授权认证 if (!jsonRequest.Tags.ContainsKey("auth_client_id") || string.IsNullOrWhiteSpace(jsonRequest.Tags["auth_client_id"].ToString())) { throw new AuthenticationException("授权认证失败,缺少 auth_client_id 参数!"); } if (!jsonRequest.Tags.ContainsKey("auth_token") || string.IsNullOrWhiteSpace(jsonRequest.Tags["auth_token"].ToString())) { throw new AuthenticationException("授权认证失败,缺少 auth_token 参数!"); } if (!this.Attributes["clientId"].Equals(jsonRequest.Tags["auth_client_id"]) || !this.Attributes["token"].Equals(jsonRequest.Tags["auth_token"])) { throw new AuthenticationException("授权认证失败,密码错误!"); } } } ``` ## TODOLIST * 引入 Zookeeper 作为服务发现机制的选择之一 * 支持跨服务调用的分布式事务支持 * 加入 .NET Core 版本 * 可以不用 IIS 宿主