.net core使用RPC方式进行高效的HTTP服务访问
传统的HTTP接口调用是一件比较繁琐的事情,特别是在Post数据的时候;不仅要拼访问的URL还是把数据序列化成流的方式给Request进行提交,获取Respons后还要对流进行解码。在实际应用虽然可以对HttpClient
进行一个简单的封装,一旦到了上层大量的API调用还是不方便和不好维护。但如果在不改变HTTP接口服务的情况可以通过RPC的方式来调用HTTP服务那在使用和修改上都会变得更简单和便于维护了; 接下来讲解一下如何使用FastHttpApi
通过接口描述的方式来访问HTTP接口服务!
引用组件
在这里简单地介绍一下FastHttpApi
,它是一个轻量级高性的能的HTTP通讯组件,除了可以构建高性的HTTP服务外,还可以通过它来实现基于RPC的方式来访问第三方HTTP服务。可以到GitHub了解。如果需要通过接口的方式访问通第三方HTTP服务,首先要在项目用引用FastHttpApi
,可以在Nuget上找到它,命令安装如下 Install-Package BeetleX.FastHttpApi -Version 1.0.2.6
也可以直接在VS中添加Nuget引用。
使用组件
在定义接口前了解第三方的HTTP服务结构是必须的(当然如果选择FastHttpApi
构建webapi会得到一下更高效的性能支持),下面主要讲解通过组件定议接口来访问asp.net mvc api的接口服务,先看一下服务的代码
- public class HomeController : Controller
- {
- public DateTime GetTime()
- {
- return DateTime.Now;
- }
- public IActionResult Hello(string name)
- {
- return new JsonResult($"hello {name}");
- }
- public IEnumerable<Order> ListOrders(int employee, string customer)
- {
- Func<Order, bool> exp = o => (employee == || o.EmployeeID == employee)
- && (string.IsNullOrEmpty(customer) || o.CustomerID == customer);
- var result = DataHelper.Orders.Where(exp);
- return result;
- }
- public Employee GetEmployee(int id)
- {
- Employee result = DataHelper.Employees.Find(e => e.EmployeeID == id);
- return result;
- }
- [HttpPost]
- public int AddEmployee([FromBody] List<Employee> items)
- {
- if (items == null)
- return ;
- return items.Count;
- }
- [HttpPost]
- public Employee EditEmployee(int id, [FromBody]Employee employee)
- {
- employee.EmployeeID = id;
- return employee;
- }
- public bool Login(string name, string pwd)
- {
- if (name == "admin" && pwd == "")
- return true;
- return false;
- }
- }
以上是一个简单的asp.net mvc api的代码,接下来用接口来描述对应调用方法
- [JsonFormater]
- [Controller(BaseUrl = "Home")]
- public interface IDataService
- {
- [Get]
- DateTime GetTime();
- [Get]
- string Hello(string name);
- [Get]
- IList<Order> ListOrders();
- [Get]
- IList<Order> ListOrders(int employee, string customer);
- [Get]
- Employee GetEmployee(int id);
- [Post]
- Employee EditEmployee([CQuery]int id, Employee employee);
- [Get]
- bool Login(string name, string pwd);
- [Post]
- int AddEmployee(params Employee[] items);
- }
是不是非常简单,简单地通过接口方法就可以描述对应HTTP请求,为了达到更好的应用性还可以重载不同版本来访问同一服务接口,这样在使用的时候就变得更方便灵活。再往下看代码了解一下是如何使用这接口的。
- HttpApiClient client = new HttpApiClient(Host);
- IDataService service = client.CreateWebapi<IDataService>();
- DateTime dt = service.GetTime();
- Console.WriteLine($"get time:{dt}");
- string hello = service.Hello("henry");
- Console.WriteLine($"hello :{hello}");
- var orders = service.ListOrders(, null);
- if (orders != null)
- Console.WriteLine($"list orders: {orders.Count}");
- orders = service.ListOrders();
- if (orders != null)
- Console.WriteLine($"list orders: {orders.Count}");
- var emp = service.GetEmployee();
- Console.WriteLine($"get employee id 7:{emp?.FirstName} {emp?.LastName}");
- emp = service.EditEmployee(, new Employee { FirstName = "fan", LastName = "henry" });
- Console.WriteLine($"edit employee :{emp.EmployeeID} {emp?.FirstName} {emp?.LastName}");
- var count = service.AddEmployee(null);
- Console.WriteLine($"add employee :{count}");
- count = service.AddEmployee(new Employee { EmployeeID = }, new Employee { EmployeeID = });
- Console.WriteLine($"add employee :{count}");
- var login = service.Login("admin", "");
- Console.WriteLine($"login status:{login}");
首先是定义一个HttpApiClient
对象指向一个服务地址,在这个代码里的访问地址是http://localhost:8080
;接下来就可以通过HttpApiClient
创建指定接口的操作对象,创建对象后就可以进行方法调用。那在多线程下是怎样处理呢?其实HttpApiClient
是线程安全的,所以不用担心多线程下的操作,对于网络连接处理则内部通过连接池实现。
组件的优势和缺点
其实dotnet core已经存在这样一个功能的组件Refit
,它的功能比较完善支持的版本也比较多,而FastHttpApi
则只支持.net core.其实FastHttpApi
的定义是针对服务与服务之间的通讯,由于它是基于自有实现的一个轻量化'HttpClient'所以在性能上要出色于'Refit',还有内部集成了基于Host的连接池所以在处理性能和连接管理上相对有着自己的优势;而这些的特点更适合内部服务之间的通讯需求。以下是组件和Refit
的性能测试对比,由于网络间的延时会抵销具休处理的效率,所以测试是基于localhost进行,这样BenchmarkDotNet
的结果好反映实际代码情况,测试结果如下:
测试代码
- [Benchmark]
- public void RefitAddEmployee()
- {
- var gitHubApi = Refit.RestService.For<IRefitEmployeeApi>(Host);
- for (int i = ; i < Count; i++)
- {
- var octocat = gitHubApi.AddEmployee(Employee.GetEmployee());
- octocat.Wait();
- var id = octocat.Result.EmployeeID;
- }
- }
- [Benchmark]
- public void FastApiAddEmployee()
- {
- BeetleX.FastHttpApi.HttpApiClient client = new BeetleX.FastHttpApi.HttpApiClient(Host);
- var api = client.CreateWebapi<IFastHttpEmployeeApi>();
- for (int i = ; i < Count; i++)
- {
- var items = api.AddEmployee(Employee.GetEmployee());
- var id = items.EmployeeID;
- }
- }
- [Benchmark]
- public void RefitGetEmployees()
- {
- var gitHubApi = Refit.RestService.For<IRefitEmployeeApi>(Host);
- for (int i = ; i < Count; i++)
- {
- var octocat = gitHubApi.ListEmployees();
- octocat.Wait();
- var count = octocat.Result.Count;
- }
- }
- [Benchmark]
- public void FastApiGetEmployees()
- {
- BeetleX.FastHttpApi.HttpApiClient client = new BeetleX.FastHttpApi.HttpApiClient(Host);
- var api = client.CreateWebapi<IFastHttpEmployeeApi>();
- for (int i = ; i < Count; i++)
- {
- var items = api.ListEmployees();
- var count = items.Count;
- }
- client.Dispose();
- }
测试结果
虽然Refit
采用静态编译的方式来处理请求,最终测试下来的结构还是FastHttpApi
代理调用有着更出色的性能优势。
实际并发测试
由于对Refit
了解不深入所以并没有把它引入进来做多线程并发测试,接下来进行一个多线程的并发测试,测试的硬件是一台4核发的开发机作为测试服务器。服务测试代码如下:
- [BeetleX.FastHttpApi.Controller(BaseUrl = "Employee")]
- class Program
- {
- static HttpApiServer mApiServer;
- static void Main(string[] args)
- {
- mApiServer = new HttpApiServer();
- mApiServer.ServerConfig.WriteLog = true;
- mApiServer.ServerConfig.LogToConsole = true;
- mApiServer.ServerConfig.Port = ;
- mApiServer.ServerConfig.LogLevel = BeetleX.EventArgs.LogType.Warring;
- mApiServer.ServerConfig.UrlIgnoreCase = true;
- mApiServer.Register(typeof(Program).Assembly);
- mApiServer.Open();
- Console.Write(mApiServer.BaseServer);
- Console.WriteLine(Environment.ProcessorCount);
- Console.Read();
- }
- public object Get(int count)
- {
- return new JsonResult(Employee.GetEmployees(count));
- }
- [Post]
- public object Add(Employee item)
- {
- return new JsonResult(item);
- }
- public object GetTime()
- {
- return new JsonResult(DateTime.Now);
- }
- }
测试的服务并没有使用asp.net core作为服务,而是使用FastHttpApi
作为测试服务,主要原因是有着更轻量级的性能优势。接下是看一下测试结果:
- ***********************************************************************
- * https://github.com/IKende/ConcurrentTest.git
- * Copyright ? ikende.com email:henryfan@msn.com
- * ServerGC:True
- ***********************************************************************
- * AddEmployee test prepping completed
- -----------------------------------------------------------------------
- * [/]|threads:[]
- * Success:[ /s]|total:[ ][min:/s max:/s]
- * Error:[ /s]|total:[ ][min:/s max:/s]
- -----------------------------------------------------------------------
- * 0ms-.1ms:[ ] .1ms-.5ms:[ ,,]
- * .5ms-1ms:[ ,] 1ms-5ms:[ ,]
- * 5ms-10ms:[ ] 10ms-50ms:[ ]
- * 50ms-100ms:[ ] 100ms-1000ms:[ ]
- * 1000ms-5000ms:[ ] 5000ms-10000ms:[ ]
- ***********************************************************************
- ***********************************************************************
- * ListEmployees test prepping completed
- -----------------------------------------------------------------------
- * [/]|threads:[]
- * Success:[ /s]|total:[ ][min:/s max:/s]
- * Error:[ /s]|total:[ ][min:/s max:/s]
- -----------------------------------------------------------------------
- * 0ms-.1ms:[ ] .1ms-.5ms:[ ,,]
- * .5ms-1ms:[ ,] 1ms-5ms:[ ,]
- * 5ms-10ms:[ ] 10ms-50ms:[ ]
- * 50ms-100ms:[ ] 100ms-1000ms:[ ]
- * 1000ms-5000ms:[ ] 5000ms-10000ms:[ ]
- ***********************************************************************
- ***********************************************************************
- * GetTime test prepping completed
- -----------------------------------------------------------------------
- * [/]|threads:[]
- * Success:[ /s]|total:[ ][min:/s max:/s]
- * Error:[ /s]|total:[ ][min:/s max:/s]
- -----------------------------------------------------------------------
- * 0ms-.1ms:[ ,] .1ms-.5ms:[ ,,]
- * .5ms-1ms:[ ,] 1ms-5ms:[ ,]
- * 5ms-10ms:[ ] 10ms-50ms:[ ]
- * 50ms-100ms:[ ] 100ms-1000ms:[ ]
- * 1000ms-5000ms:[ ] 5000ms-10000ms:[ ]
- ***********************************************************************
客户端开启了20个线程同步调用服务,得到的结果峰值大概在8万每秒的http请求响应,这样的性能指标相信完全能满足普通业务的需求,毕竟这台测试服务用的只是一台5-6年前的4核PC机。
.net core使用RPC方式进行高效的HTTP服务访问的更多相关文章
- 采用RPC方式和document方式 开发Axis2的WebService客户端
import javax.xml.namespace.QName; import org.apache.axiom.om.OMAbstractFactory; import org.apache.ax ...
- asp.net core 自定义认证方式--请求头认证
asp.net core 自定义认证方式--请求头认证 Intro 最近开始真正的实践了一些网关的东西,最近写几篇文章分享一下我的实践以及遇到的问题. 本文主要介绍网关后面的服务如何进行认证. 解决思 ...
- ASP.NET Core默认注入方式下如何注入多个实现(多种方式) - sky 胡萝卜星星 - CSDN博客
原文:ASP.NET Core默认注入方式下如何注入多个实现(多种方式) - sky 胡萝卜星星 - CSDN博客 版权声明:本文为starfd原创文章,转载请标明出处. https://blog.c ...
- 使用.NET Core创建Windows服务 - 使用.NET Core工作器方式
原文:Creating Windows Services In .NET Core – Part 3 – The ".NET Core Worker" Way 作者:Dotnet ...
- 浅淡Webservice、WSDL三种服务访问的方式(附案例)
Webservice Webservice是使应用程序以与平台和编程语言无关的方式进行相互通信技术. eg:站点提供访问的数据接口:新浪微博.淘宝. 官方解释:它是一种构建应用程序的普遍模型,可以在任 ...
- C# 6 与 .NET Core 1.0 高级编程 - 39 章 Windows 服务(上)
译文,个人原创,转载请注明出处(C# 6 与 .NET Core 1.0 高级编程 - 39 章 Windows 服务(上)),不对的地方欢迎指出与交流. 章节出自<Professional C ...
- C# 6 与 .NET Core 1.0 高级编程 - 39 章 Windows 服务(下)
译文,个人原创,转载请注明出处(C# 6 与 .NET Core 1.0 高级编程 - 39 章 Windows 服务(下)),不对的地方欢迎指出与交流. 章节出自<Professional C ...
- ASP.NET Core 实战:基于 Dapper 扩展你的数据访问方法
一.前言 在非静态页面的项目开发中,必定会涉及到对于数据库的访问,最开始呢,我们使用 Ado.Net,通过编写 SQL 帮助类帮我们实现对于数据库的快速访问,后来,ORM(Object Relatio ...
- [ASP.NET Core 3框架揭秘] 依赖注入[8]:服务实例的生命周期
生命周期决定了IServiceProvider对象采用怎样的方式提供和释放服务实例.虽然不同版本的依赖注入框架针对服务实例的生命周期管理采用了不同的实现,但总的来说原理还是类似的.在我们提供的依赖注入 ...
随机推荐
- RSP小组——消消乐
RSP小组--消消乐 团队所有博客总结 1.团队第一周作业 2.团队第二周作业 3.RSP小组--团队冲刺博客一 4.RSP小组--团队冲刺博客二 5.RSP小组--团队冲刺博客三 6.RSP小组-- ...
- PC网站转换成手机版
博客地址:https://www.cnblogs.com/zxtceq/p/5714606.html 一天完成把PC网站改为自适应!原来这么简单! http://www.webkaka.com/blo ...
- KMP模板实现
看了出题知识点才发现自己连KMP都没有好好的理解,甚至一共就打过一次板子=-= 于是照着之前的课件学了一学...发现没怎么弄懂qwq 我太弱啦! 找了一篇自认为全网最好的介绍 觉得写得很棒 字符串匹配 ...
- Unity-NGUI UILabel换行
表里填写的是"\n",代码读出来会变成"\\n", 那就需要代码中将 "\\n" 重新变成 "\n" 才能够换行. st ...
- javascript是什么,可以做什么?
是一门脚本语言:不需要编译,直接运行 是一门解释型语言:遇到一行代码就解释一行代码 是一门动态类型的语言 是一门基于对象的语言 是一门弱类型的语言:声明变量的时候不用特别声明类型都使用var 不是一门 ...
- 动态规划-LIS1
https://vjudge.net/contest/297216?tdsourcetag=s_pctim_aiomsg#problem/J #include<bits/stdc++.h> ...
- git如何避免push/pull时输入密码
今天在搭建git服务器的时候,一切顺利,但是就是在git push的时候老是要输入密码,太烦了,然后百度搜索了一下,总结了主要有如下三种方法: 方法1 git config --global cred ...
- (BUG记录)使用迭代器安全的删除处于循环下集合中的元素
今日在写一个功能时,需要从MQ拿取数据集合调用对端系统进行批量处理,为了幂等支持,在循环内部如果不满足调用条件就直接从集合中移除. 以上是一个典型的循环集合内删除的场景任务,工作一年第一次遇到这个场景 ...
- Linux 搭建Nginx+uWSGI+Django环境
安装环境 sudo apt-get install nginx sudo apt install python3 sudo apt install python3-pip 使用 sudo pip3 i ...
- 如何理解opencv, python-opencv 和 libopencv?
转: OpenCV is a computer vision library written using highly optimized C/C++ code. It makes use of ...