ASP.NET Core Web API 实现异步通信

在构建现代Web应用程序时,异步通信是一个重要的概念,特别是在处理长时间运行的任务或分布式系统(如微服务架构)时。本文将介绍如何使用ASP.NET CoreWeb API实现异步通信,包括创建项目、配置服务、添加控制器、定义模型以及讨论异步通信的实现方式和使用场景。

创建项目和配置服务

首先,需要创建一个ASP.NET CoreWeb API项目。在项目中,需要配置服务和中间件以支持MVC。以下是配置服务和中间件的示例代码:

public class Startup { public void ConfigureServices(IServiceCollection services) { services.AddMvc(); } public void Configure(IApplicationBuilder app, IHostingEnvironment env) { app.UseMvcWithDefaultRoute(); } }

在这段代码中,通过调用services.AddMvc();来添加MVC服务,并通过app.UseMvcWithDefaultRoute();来配置默认路由。

添加控制器

接下来,需要添加一个控制器来处理异步请求。以下是控制器的示例代码:

[Route("api/rentals")] public class RentalsController : BaseController { [HttpPost("request-rental", Name = "RequestRental")] public IActionResult RequestRental([FromBody]RequestRentalInputModel inputModel) { return AcceptedAtRoute("CheckStatus", new { queueNo = "q-2" }); } [HttpGet("check-status/{queueNo}", Name = "CheckStatus")] public IActionResult CheckStatus(string queueNo) { if (queueNo == "q-2") return Ok(new CheckStatusOutputModel { Status = "Pending" }); else return SeeOther("GetRental", new { refNo = "r-1" }); } [HttpGet("get-rental/{refNo}", Name = "GetRental")] public IActionResult GetRental(string refNo) { if (refNo == "r-1") return Ok(new GetRentalOutputModel { DeliveryEstimate = DateTime.Now.AddDays(2) }); else return NotFound(); } }

在这个控制器中,定义了三个动作:RequestRental用于接收租赁请求,CheckStatus用于检查请求状态,GetRental用于获取租赁结果。

定义模型

为了通过API发送和接收数据,需要定义一些模型。以下是模型的示例代码:

public class RequestRentalInputModel { public string Customer { get; set; } public string Movie { get; set; } public int Days { get; set; } } public class CheckStatusOutputModel { public string Status { get; set; } } public class GetRentalOutputModel { public DateTime DeliveryEstimate { get; set; } }

这些模型分别用于表示租赁请求、状态检查和租赁结果。

异步通信的实现方式

异步通信可以通过同步(RPC)或异步(消息传递)的方式进行。对于异步通信,客户端将:

  • 发送请求
  • 检查其状态
  • 获取结果

在服务器端,API将有一个POST端点来接受请求。它通常会将请求消息存储在队列中以供后续处理。这个端点返回202(已接受)状态码以及用于检查请求状态的Location头:

[HttpPost("request-rental", Name = "RequestRental")] public IActionResult RequestRental([FromBody]RequestRentalInputModel inputModel) { return AcceptedAtRoute("CheckStatus", new { queueNo = "q-2" }); }

API将有一个GET端点来检查状态。这个端点将发送200(OK)状态码和状态详情,或者对于已完成的请求发送303(See Other)状态码:

[HttpGet("check-status/{queueNo}", Name = "CheckStatus")] public IActionResult CheckStatus(string queueNo) { if (queueNo == "q-2") return Ok(new CheckStatusOutputModel { Status = "Pending" }); else return SeeOther("GetRental", new { refNo = "r-1" }); }

注意,303(See Other)没有在基控制器中内置的方法,但是很容易创建自己的方法:

[NonAction] protected IActionResult SeeOther(string routeName, object values) { var location = Url.Link(routeName, values); HttpContext.Response.GetTypedHeaders().Location = new System.Uri(location); return StatusCode(StatusCodes.Status303SeeOther); }

API将有一个GET端点来获取结果。这个端点将发送200(OK)状态码,对于已完成的请求,或者404(未找到)状态码,对于未完成的请求:

[HttpGet("get-rental/{refNo}", Name = "GetRental")] public IActionResult GetRental(string refNo) { if (refNo == "r-1") return Ok(new GetRentalOutputModel { DeliveryEstimate = DateTime.Now.AddDays(2) }); else return NotFound(); }

使用场景

异步基于消息的通信非常适合长时间运行的过程和分布式系统(例如微服务)。客户端和服务器通常有以下责任:

  • 服务器:在接收到请求消息后,将消息存储在队列或数据库中以供后续处理。将有一个组件(例如Windows服务)在后台运行以处理队列中的消息。一旦处理完成,数据库中的记录(SQL或NoSQL)将更新以反映请求的状态。Check Status和Get Result的API端点将使用这个数据库来相应地响应客户端请求。
  • 客户端:在将请求发送到服务器API后,保留Location头的记录(在内存中或数据库中),其中包含用于检查请求状态的端点。将有一个组件(例如Windows服务)在后台运行以定期调用状态端点。一旦状态端点返回303(See Other),使用Location头访问处理结果。
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485