(给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技能