6.2 ASP.NET Core Web API 控制器


文档摘要

6.2 ASP.NET Core Web API 控制器 6.2 ASP.NET Core Web API 控制器 在ASP.NET Core Web API开发中,控制器扮演着至关重要的角色。它们接收来自客户端的HTTP请求,处理请求逻辑,并返回适当的HTTP响应。控制器是Web API的核心组件,负责将业务逻辑暴露为可访问的API端点。本章节将深入探讨ASP.NET Core Web API控制器的各个方面,包括其结构、特性、常用方法和最佳实践。 6.2.1 控制器的基本结构 ASP.NET Core Web API控制器通常是一个继承自 或 类的C#类。

6.2 ASP.NET Core Web API 控制器

6.2 ASP.NET Core Web API 控制器

在ASP.NET Core Web API开发中,控制器扮演着至关重要的角色。它们接收来自客户端的HTTP请求,处理请求逻辑,并返回适当的HTTP响应。控制器是Web API的核心组件,负责将业务逻辑暴露为可访问的API端点。本章节将深入探讨ASP.NET Core Web API控制器的各个方面,包括其结构、特性、常用方法和最佳实践。

6.2.1 控制器的基本结构

ASP.NET Core Web API控制器通常是一个继承自ControllerBaseController类的C#类。ControllerBase类提供了Web API开发所需的基本功能,而Controller类则在ControllerBase的基础上增加了对视图的支持,因此更适合于MVC应用程序,而Web API通常使用ControllerBase

一个典型的控制器类结构如下:

using Microsoft.AspNetCore.Mvc; using System.Collections.Generic; namespace MyWebApi.Controllers { [ApiController] [Route("api/[controller]")] public class ItemsController : ControllerBase { // 依赖注入的属性或字段 public ItemsController() { // 构造函数,用于依赖注入 } // HTTP Action Methods (GET, POST, PUT, DELETE等) } }

代码解释:

  • using Microsoft.AspNetCore.Mvc;: 导入Microsoft.AspNetCore.Mvc命名空间,该命名空间包含了创建Web API控制器所需的类和接口。

  • namespace MyWebApi.Controllers: 定义控制器所在的命名空间,通常建议将控制器放置在Controllers命名空间下。

  • [ApiController]: 这是一个特性,用于标记该类是一个API控制器。它提供了一些默认行为,例如自动模型验证、参数绑定和返回ProblemDetails类型的错误响应。

  • [Route("api/[controller]")]: 这是一个路由特性,定义了API端点的URL。"api/[controller]"表示URL以api/开头,后面跟着控制器的名称(不包含"Controller"后缀)。例如,对于ItemsController,默认路由将是api/items

  • public class ItemsController : ControllerBase: 声明一个名为ItemsController的类,它继承自ControllerBase类。

  • 构造函数: 用于依赖注入,将服务注入到控制器中。

  • HTTP Action Methods: 这些方法对应于不同的HTTP请求方法(GET, POST, PUT, DELETE等),并处理相应的业务逻辑。

6.2.2 路由配置

路由是将HTTP请求映射到控制器操作的过程。ASP.NET Core提供了多种方式来配置路由:

  • 属性路由 (Attribute Routing):在控制器和Action方法上使用特性来定义路由。这是推荐的方式,因为它将路由配置与代码紧密结合。

  • 约定路由 (Conventional Routing):在Startup.cs文件中定义路由模板。这种方式适用于简单的API,但对于复杂的API,属性路由更灵活。

属性路由示例:

[ApiController] [Route("api/[controller]")] public class ItemsController : ControllerBase { [HttpGet] public ActionResult<IEnumerable<string>> Get() { return new string[] { "value1", "value2" }; } [HttpGet("{id}")] public ActionResult<string> Get(int id) { return "value"; } [HttpPost] public void Post([FromBody] string value) { // 处理POST请求 } }

代码解释:

  • [HttpGet]: 将Get()方法映射到HTTP GET请求。没有指定路由模板,因此它将使用控制器的默认路由(api/items)。

  • [HttpGet("{id}")]: 将Get(int id)方法映射到HTTP GET请求,并带有一个名为id的参数。路由模板"{id}"表示URL中api/items之后的部分将被绑定到id参数。例如,api/items/123将调用此方法,并将id设置为123。

  • [HttpPost]: 将Post(string value)方法映射到HTTP POST请求。

  • [FromBody] string value: 指示value参数的值应该从HTTP请求的主体中获取。

约定路由示例 (Startup.cs):

app.UseEndpoints(endpoints => { endpoints.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); });

代码解释:

  • pattern: "{controller=Home}/{action=Index}/{id?}"定义了路由模板。

    • {controller=Home}: 指定控制器名称,默认值为Home

    • {action=Index}: 指定Action方法名称,默认值为Index

    • {id?}: 指定一个可选的id参数。

6.2.3 HTTP Action Methods

Action方法是控制器中处理HTTP请求的方法。它们接收来自客户端的输入,执行业务逻辑,并返回HTTP响应。常见的HTTP Action方法包括:

  • HttpGet: 用于检索数据。

  • HttpPost: 用于创建新数据。

  • HttpPut: 用于更新现有数据。

  • HttpDelete: 用于删除数据。

  • HttpPatch: 用于部分更新现有数据。

Action方法返回值:

Action方法可以返回多种类型的值,包括:

  • ActionResult<T>: 推荐使用的方式,它允许返回特定类型的数据或标准的HTTP状态码。

  • IActionResult: 一个接口,表示Action方法的结果。

  • 具体类型 (如string, int, object): ASP.NET Core会自动将这些类型序列化为JSON并返回。

  • void: 不返回任何内容,通常用于执行某些操作但不返回数据。

示例:

[HttpGet] public ActionResult<IEnumerable<Item>> GetItems() { // 从数据库或缓存中检索所有items var items = new List<Item> { new Item { Id = 1, Name = "Item 1" }, new Item { Id = 2, Name = "Item 2" } }; if (items == null || items.Count == 0) { return NotFound(); // 返回404 Not Found } return Ok(items); // 返回200 OK,并包含items数据 } [HttpGet("{id}")] public ActionResult<Item> GetItem(int id) { // 从数据库或缓存中检索指定id的item var item = new Item { Id = id, Name = $"Item {id}" }; // 模拟数据 if (item == null) { return NotFound(); // 返回404 Not Found } return Ok(item); // 返回200 OK,并包含item数据 } [HttpPost] public ActionResult<Item> CreateItem([FromBody] Item newItem) { // 将newItem保存到数据库或缓存中 newItem.Id = 3; // 模拟生成Id // 返回201 Created,并包含新创建的item数据和Location header return CreatedAtAction(nameof(GetItem), new { id = newItem.Id }, newItem); } [HttpPut("{id}")] public IActionResult UpdateItem(int id, [FromBody] Item updatedItem) { // 检查id和updatedItem.Id是否一致 if (id != updatedItem.Id) { return BadRequest(); // 返回400 Bad Request } // 更新数据库或缓存中指定id的item // ... return NoContent(); // 返回204 No Content } [HttpDelete("{id}")] public IActionResult DeleteItem(int id) { // 从数据库或缓存中删除指定id的item // ... return NoContent(); // 返回204 No Content } public class Item { public int Id { get; set; } public string Name { get; set; } }

代码解释:

  • Ok(object value): 返回一个OkResult对象,表示HTTP 200 OK状态码,并包含value作为响应体。

  • NotFound(): 返回一个NotFoundResult对象,表示HTTP 404 Not Found状态码。

  • CreatedAtAction(string actionName, object routeValues, object value): 返回一个CreatedAtActionResult对象,表示HTTP 201 Created状态码,并包含新创建的value作为响应体,以及一个Location header,指向可以通过actionNamerouteValues检索新创建资源的URL。

  • BadRequest(): 返回一个BadRequestResult对象,表示HTTP 400 Bad Request状态码。

  • NoContent(): 返回一个NoContentResult对象,表示HTTP 204 No Content状态码。

6.2.4 模型绑定和验证

ASP.NET Core会自动将HTTP请求中的数据绑定到Action方法的参数上。这称为模型绑定。ASP.NET Core还提供了模型验证功能,可以自动验证绑定后的数据是否有效。

模型绑定:

ASP.NET Core使用不同的绑定源来绑定参数:

  • [FromBody]: 从HTTP请求的主体中绑定数据(通常是JSON)。

  • [FromQuery]: 从查询字符串中绑定数据。

  • [FromRoute]: 从路由参数中绑定数据。

  • [FromHeader]: 从HTTP Header中绑定数据。

  • [FromForm]: 从表单数据中绑定数据。

如果没有指定绑定源,ASP.NET Core会根据参数类型和请求类型自动选择绑定源。

模型验证:

可以使用System.ComponentModel.DataAnnotations命名空间中的特性来定义模型验证规则。常见的验证特性包括:

  • [Required]: 指示属性是必需的。

  • [StringLength]: 指定字符串的最大和最小长度。

  • [Range]: 指定数值的范围。

  • [EmailAddress]: 验证属性是否是有效的电子邮件地址。

  • [RegularExpression]: 使用正则表达式验证属性。

示例:

public class Item { public int Id { get; set; } [Required(ErrorMessage = "Name is required.")] [StringLength(100, MinimumLength = 3, ErrorMessage = "Name must be between 3 and 100 characters.")] public string Name { get; set; } [Range(0, 1000, ErrorMessage = "Price must be between 0 and 1000.")] public decimal Price { get; set; } } [HttpPost] public ActionResult<Item> CreateItem([FromBody] Item newItem) { if (!ModelState.IsValid) { return BadRequest(ModelState); // 返回400 Bad Request,并包含验证错误信息 } // 将newItem保存到数据库或缓存中 newItem.Id = 3; // 模拟生成Id // 返回201 Created,并包含新创建的item数据和Location header return CreatedAtAction(nameof(GetItem), new { id = newItem.Id }, newItem); }

代码解释:

  • ModelState.IsValid: 检查模型是否通过了验证。如果模型无效,ModelState将包含验证错误信息。

  • BadRequest(ModelState): 返回一个BadRequestObjectResult对象,表示HTTP 400 Bad Request状态码,并包含ModelState中的验证错误信息。

6.2.5 依赖注入

ASP.NET Core内置了依赖注入 (DI) 容器,可以方便地将服务注入到控制器中。依赖注入可以提高代码的可测试性、可维护性和可重用性。

示例:

public interface IItemRepository { IEnumerable<Item> GetItems(); Item GetItem(int id); void AddItem(Item item); void UpdateItem(Item item); void DeleteItem(int id); } public class ItemRepository : IItemRepository { // 实现接口方法 private static List<Item> _items = new List<Item>() { new Item { Id = 1, Name = "Item 1" }, new Item { Id = 2, Name = "Item 2" } }; public IEnumerable<Item> GetItems() { return _items; } public Item GetItem(int id) { return _items.FirstOrDefault(i => i.Id == id); } public void AddItem(Item item) { item.Id = _items.Count + 1; _items.Add(item); } public void UpdateItem(Item item) { var existingItem = _items.FirstOrDefault(i => i.Id == item.Id); if (existingItem != null) { existingItem.Name = item.Name; } } public void DeleteItem(int id) { var itemToRemove = _items.FirstOrDefault(i => i.Id == id); if (itemToRemove != null) { _items.Remove(itemToRemove); } } } // 在 Startup.cs 中注册服务 public void ConfigureServices(IServiceCollection services) { services.AddControllers(); services.AddScoped<IItemRepository, ItemRepository>(); } [ApiController] [Route("api/[controller]")] public class ItemsController : ControllerBase { private readonly IItemRepository _itemRepository; public ItemsController(IItemRepository itemRepository) { _itemRepository = itemRepository; } [HttpGet] public ActionResult<IEnumerable<Item>> GetItems() { return Ok(_itemRepository.GetItems()); } [HttpGet("{id}")] public ActionResult<Item> GetItem(int id) { var item = _itemRepository.GetItem(id); if (item == null) { return NotFound(); } return Ok(item); } [HttpPost] public ActionResult<Item> CreateItem([FromBody] Item newItem) { if (!ModelState.IsValid) { return BadRequest(ModelState); } _itemRepository.AddItem(newItem); return CreatedAtAction(nameof(GetItem), new { id = newItem.Id }, newItem); } [HttpPut("{id}")] public IActionResult UpdateItem(int id, [FromBody] Item updatedItem) { if (id != updatedItem.Id) { return BadRequest(); } _itemRepository.UpdateItem(updatedItem); return NoContent(); } [HttpDelete("{id}")] public IActionResult DeleteItem(int id) { _itemRepository.DeleteItem(id); return NoContent(); } }

代码解释:

  • IItemRepository: 定义一个接口,表示Item数据访问层。

  • ItemRepository: 实现IItemRepository接口,提供Item数据的CRUD操作。

  • services.AddScoped<IItemRepository, ItemRepository>(): 在Startup.cs中注册IItemRepository服务,使用ItemRepository类作为实现。AddScoped表示在每个HTTP请求中创建一个ItemRepository实例。

  • ItemsController(IItemRepository itemRepository): 在ItemsController的构造函数中,通过依赖注入获取IItemRepository实例。

6.2.6 异步操作

为了提高Web API的性能和响应速度,建议使用异步操作。ASP.NET Core提供了asyncawait关键字,可以方便地编写异步代码。

示例:

[HttpGet] public async Task<ActionResult<IEnumerable<Item>>> GetItemsAsync() { // 异步从数据库或缓存中检索所有items var items = await Task.Run(() => new List<Item> { new Item { Id = 1, Name = "Item 1" }, new Item { Id = 2, Name = "Item 2" } }); if (items == null || items.Count == 0) { return NotFound(); // 返回404 Not Found } return Ok(items); // 返回200 OK,并包含items数据 }

代码解释:

  • async Task<ActionResult<IEnumerable<Item>>>: 声明一个异步Action方法,返回Task<ActionResult<IEnumerable<Item>>>

  • await Task.Run(() => ...): 使用await关键字等待异步操作完成。Task.Run()用于将同步代码放到后台线程中执行,模拟异步操作。

6.2.7 API 版本控制

当API不断发展演进时,版本控制变得至关重要。它可以确保客户端应用程序在API更新后仍然能够正常工作。ASP.NET Core提供了多种API版本控制的方法:

  • 基于URI的版本控制: 在URL中包含版本号,例如api/v1/items

  • 基于查询字符串的版本控制: 在查询字符串中包含版本号,例如api/items?api-version=1

  • 基于Header的版本控制: 在HTTP Header中包含版本号,例如Accept: application/json; version=1.0

基于URI的版本控制示例:

[ApiController] [Route("api/v{version:apiVersion}/[controller]")] [ApiVersion("1.0")] [ApiVersion("2.0")] public class ItemsController : ControllerBase { [HttpGet] public ActionResult<string> Get() { return $"Items Controller - Version {HttpContext.GetRequestedApiVersion()}"; } }

代码解释:

  • [Route("api/v{version:apiVersion}/[controller]")]: 定义路由模板,其中{version:apiVersion}表示版本号,apiVersion是一个约束,确保version参数是有效的API版本。

  • [ApiVersion("1.0")]: 指定该控制器支持的版本号为1.0。

  • [ApiVersion("2.0")]: 指定该控制器支持的版本号为2.0。

  • HttpContext.GetRequestedApiVersion(): 获取请求的API版本号。

需要在Startup.cs中配置API版本控制服务:

public void ConfigureServices(IServiceCollection services) { services.AddControllers(); services.AddApiVersioning(options => { options.AssumeDefaultVersionWhenUnspecified = true; options.DefaultApiVersion = new ApiVersion(1, 0); options.ReportApiVersions = true; }); services.AddVersionedApiExplorer(options => { options.GroupNameFormat = "'v'VVV"; options.SubstituteApiVersionInUrl = true; }); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IApiVersionDescriptionProvider provider) { // ... app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); // ... }

6.2.8 错误处理

在Web API开发中,错误处理是一个重要的方面。ASP.NET Core提供了多种方式来处理错误:

  • 全局异常处理: 使用中间件捕获未处理的异常,并返回统一的错误响应。

  • Action方法中的异常处理: 使用try-catch块捕获Action方法中的异常,并返回特定的错误响应。

  • 使用ProblemDetails: ProblemDetails是一个标准的错误响应格式,可以提供更详细的错误信息。

全局异常处理示例:

创建一个全局异常处理中间件:

public class GlobalExceptionHandlingMiddleware { private readonly RequestDelegate _next; private readonly ILogger<GlobalExceptionHandlingMiddleware> _logger; public GlobalExceptionHandlingMiddleware(RequestDelegate next, ILogger<GlobalExceptionHandlingMiddleware> logger) { _next = next; _logger = logger; } public async Task InvokeAsync(HttpContext context) { try { await _next(context); } catch (Exception ex) { _logger.LogError(ex, "An unhandled exception occurred."); context.Response.StatusCode = 500; context.Response.ContentType = "application/json"; var problemDetails = new ProblemDetails { Status = 500, Title = "Internal Server Error", Detail = "An unexpected error occurred. Please try again later.", Instance = context.Request.Path }; await context.Response.WriteAsync(JsonSerializer.Serialize(problemDetails)); } } } public static class GlobalExceptionHandlingMiddlewareExtensions { public static IApplicationBuilder UseGlobalExceptionHandling(this IApplicationBuilder builder) { return builder.UseMiddleware<GlobalExceptionHandlingMiddleware>(); } }

Startup.cs中注册中间件:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { // ... app.UseGlobalExceptionHandling(); // ... }

6.2.9 Graph TD 图示

以下是一个简单的Graph TD图示,展示了ASP.NET Core Web API控制器的请求处理流程:

graph TD A[Client Request] --> B(Routing); B --> C{Controller Action}; C --> D[Business Logic]; D --> E((Response Data)); E --> F(Response Formatting); F --> G[Client Response];

图示解释:

  • Client Request: 客户端发送的HTTP请求。

  • Routing: ASP.NET Core路由引擎根据请求的URL将请求映射到相应的控制器Action方法。

  • Controller Action: 控制器Action方法接收请求,并调用业务逻辑层处理请求。

  • Business Logic: 业务逻辑层执行实际的业务操作,例如从数据库中检索数据或更新数据。

  • Response Data: 业务逻辑层返回的数据。

  • Response Formatting: ASP.NET Core将响应数据格式化为JSON或其他格式。

  • Client Response: ASP.NET Core将格式化后的响应数据发送回客户端。

6.2.10 总结

ASP.NET Core Web API控制器是构建RESTful API的关键组件。通过理解控制器的结构、路由配置、HTTP Action方法、模型绑定和验证、依赖注入、异步操作、API版本控制和错误处理,可以构建出高效、可维护和可扩展的Web API。希望本章节能够帮助你更好地理解和使用ASP.NET Core Web API控制器。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U