传统的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服务访问的更多相关文章

  1. 采用RPC方式和document方式 开发Axis2的WebService客户端

    import javax.xml.namespace.QName; import org.apache.axiom.om.OMAbstractFactory; import org.apache.ax ...

  2. asp.net core 自定义认证方式--请求头认证

    asp.net core 自定义认证方式--请求头认证 Intro 最近开始真正的实践了一些网关的东西,最近写几篇文章分享一下我的实践以及遇到的问题. 本文主要介绍网关后面的服务如何进行认证. 解决思 ...

  3. ASP.NET Core默认注入方式下如何注入多个实现(多种方式) - sky 胡萝卜星星 - CSDN博客

    原文:ASP.NET Core默认注入方式下如何注入多个实现(多种方式) - sky 胡萝卜星星 - CSDN博客 版权声明:本文为starfd原创文章,转载请标明出处. https://blog.c ...

  4. 使用.NET Core创建Windows服务 - 使用.NET Core工作器方式

    原文:Creating Windows Services In .NET Core – Part 3 – The ".NET Core Worker" Way 作者:Dotnet ...

  5. 浅淡Webservice、WSDL三种服务访问的方式(附案例)

    Webservice Webservice是使应用程序以与平台和编程语言无关的方式进行相互通信技术. eg:站点提供访问的数据接口:新浪微博.淘宝. 官方解释:它是一种构建应用程序的普遍模型,可以在任 ...

  6. C# 6 与 .NET Core 1.0 高级编程 - 39 章 Windows 服务(上)

    译文,个人原创,转载请注明出处(C# 6 与 .NET Core 1.0 高级编程 - 39 章 Windows 服务(上)),不对的地方欢迎指出与交流. 章节出自<Professional C ...

  7. C# 6 与 .NET Core 1.0 高级编程 - 39 章 Windows 服务(下)

    译文,个人原创,转载请注明出处(C# 6 与 .NET Core 1.0 高级编程 - 39 章 Windows 服务(下)),不对的地方欢迎指出与交流. 章节出自<Professional C ...

  8. ASP.NET Core 实战:基于 Dapper 扩展你的数据访问方法

    一.前言 在非静态页面的项目开发中,必定会涉及到对于数据库的访问,最开始呢,我们使用 Ado.Net,通过编写 SQL 帮助类帮我们实现对于数据库的快速访问,后来,ORM(Object Relatio ...

  9. [ASP.NET Core 3框架揭秘] 依赖注入[8]:服务实例的生命周期

    生命周期决定了IServiceProvider对象采用怎样的方式提供和释放服务实例.虽然不同版本的依赖注入框架针对服务实例的生命周期管理采用了不同的实现,但总的来说原理还是类似的.在我们提供的依赖注入 ...

随机推荐

  1. 音频相关基本概念,音频处理及编解码基本框架和原理以及音、重采样、3A等音频处理(了解概念为主)

    视频笔记:音频专业级分析软件(Cooledit) 音质定义以语音带宽来区分,采样率越高,带宽越大,则保真度越高,音质越好.窄带(8khz采样),宽带(16khz采样),CD音质(44.1khz采样) ...

  2. Spring常用注解总结

    转载自:https://www.cnblogs.com/xiaoxi/p/5935009.html 传统的Spring做法是使用.xml文件来对bean进行注入或者是配置aop.事物,这么做有两个缺点 ...

  3. GitHub的简单使用记录

    记录于:2013/4/24 GitHub(网址 https://github.com/)是一个面向开源及私有软件项目的托管平台,因为只支持Git作为唯一的版本库格式进行托管,故名GitHub.   G ...

  4. golang struct 和 byte互转

    相比于encoding, 使用unsafe性能更高 type MyStruct struct { A int B int } var sizeOfMyStruct = int(unsafe.Sizeo ...

  5. WWH——学习方法理解与分析

    WWH是"What+Why+How"的简称,是对学习方法最完美的概括."如果不按照WWH这种模式来教学,90%的结果是老师没教好,学生学不好." 1.What( ...

  6. BZOJ5304 : [Haoi2018]字串覆盖

    离线处理所有询问. 对于$r-l\leq 50$的情况: 按照串长从$1$到$51$分别把所有子串按照第一位字符为第一关键字,上一次排序结果为第二关键字进行$O(n)$基数排序. 同理也可以用上一次比 ...

  7. React事件绑定几种方法测试

    前提 es6写法的类方法默认没有绑定this,不手动绑定this值为undefined. 因此讨论以下几种绑定方式. 一.构造函数constructor中用bind绑定 class App exten ...

  8. HDP Hive StorageHandler 下推优化的坑

    关键词:hdp , hive , StorageHandler 了解Hive StorageHandler的同学都知道,StorageHandler作为Hive适配不同存储的拓展类,同时肩负着Hive ...

  9. Vue 过滤器的使用

    Vue官方文档是这样说的:Vue过滤器用于格式化一些常见的文本. 在实际项目中的使用: 定义过滤器 在src定义一个filter.js文件,里面定义过滤器函数,在最后要使用 exprot defaul ...

  10. maven的安装及配置

    学习的目标 1.能够掌握Maven的安装 2.能够配置Maven仓库 3.理解Maven的依赖传递 4.能够掌握Maven工程的创建 准备工作 1.需要的资料(apache-maven-3.5.2,本 ...