(给DotNet加星标,提升.Net技能)
转自:smark
cnblogs.com/smark/p/9983181.html
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 == 0 || 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 0;
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 == "123456")
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(3, 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(7);
Console.WriteLine($"get employee id 7:{emp?.FirstName} {emp?.LastName}");
emp = service.EditEmployee(5, 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 = 3 }, new Employee { EmployeeID = 5 });
Console.WriteLine($"add employee :{count}");
var login = service.Login("admin", "123456");
Console.WriteLine($"login status:{login}");
首先是定义一个HttpApiClient对象指向一个服务地址,在这个代码里的访问地址是http://localhost:8080;接下来就可以通过HttpApiClient创建指定接口的操作对象,创建对象后就可以进行方法调用。
那在多线程下是怎样处理呢?其实HttpApiClient是线程安全的,所以不用担心多线程下的操作,对于网络连接处理则内部通过连接池实现。
[Benchmark]
public void RefitAddEmployee()
{
var gitHubApi = Refit.RestService.For<IRefitEmployeeApi>(Host);
for (int i = 0; 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 = 0; 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 = 0; i < Count; i++)
{
var octocat = gitHubApi.ListEmployees(5);
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 = 0; i < Count; i++)
{
var items = api.ListEmployees(5);
var count = items.Count;
}
client.Dispose();
}
测试结果
[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 = 8007;
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 2018 email:henryfan@msn.com
* ServerGC:True
***********************************************************************
* AddEmployee test prepping completed
-----------------------------------------------------------------------
* [10000000/10000000]|threads:[20]
* Success:[ 0/s]|total:[ 10000000][min:60087/s max:82394/s]
* Error:[ 0/s]|total:[ 0][min:0/s max:0/s]
-----------------------------------------------------------------------
* 0ms-0.1ms:[ 203] 0.1ms-0.5ms:[ 9,956,907]
* 0.5ms-1ms:[ 15,796] 1ms-5ms:[ 26,184]
* 5ms-10ms:[ 681] 10ms-50ms:[ 70]
* 50ms-100ms:[ 1] 100ms-1000ms:[ 158]
* 1000ms-5000ms:[ ] 5000ms-10000ms:[ ]
***********************************************************************
***********************************************************************
* ListEmployees test prepping completed
-----------------------------------------------------------------------
* [10000000/10000000]|threads:[20]
* Success:[ 0/s]|total:[ 10000000][min:57709/s max:83524/s]
* Error:[ 0/s]|total:[ 0][min:0/s max:0/s]
-----------------------------------------------------------------------
* 0ms-0.1ms:[ 504] 0.1ms-0.5ms:[ 9,978,394]
* 0.5ms-1ms:[ 4,114] 1ms-5ms:[ 16,732]
* 5ms-10ms:[ 98] 10ms-50ms:[ 3]
* 50ms-100ms:[ 20] 100ms-1000ms:[ 135]
* 1000ms-5000ms:[ ] 5000ms-10000ms:[ ]
***********************************************************************
***********************************************************************
* GetTime test prepping completed
-----------------------------------------------------------------------
* [10000000/10000000]|threads:[20]
* Success:[ 0/s]|total:[ 10000000][min:65740/s max:95669/s]
* Error:[ 0/s]|total:[ 0][min:0/s max:0/s]
-----------------------------------------------------------------------
* 0ms-0.1ms:[ 77,060] 0.1ms-0.5ms:[ 9,904,465]
* 0.5ms-1ms:[ 4,612] 1ms-5ms:[ 13,510]
* 5ms-10ms:[ 173] 10ms-50ms:[ 31]
* 50ms-100ms:[ ] 100ms-1000ms:[ 149]
* 1000ms-5000ms:[ ] 5000ms-10000ms:[ ]
***********************************************************************
客户端开启了20个线程同步调用服务,得到的结果峰值大概在8万每秒的http请求响应,这样的性能指标相信完全能满足普通业务的需求,毕竟这台测试服务用的只是一台5-6年前的4核PC机。
推荐阅读
(点击标题可跳转阅读)
看完本文有收获?请转发分享给更多人
关注「DotNet」加星标,提升.Net技能