// 定义一个表示动物的类 public class Animal { // 动物的名称,必填 public required string Name { get; set; } // 动物的种类,必填 public required string Species { get; set; } // 动物的年龄,可选 public int? Age { get; set; } }然后,我们添加一个服务类:
// 定义一个提供动物信息的服务类 public class AnimalService : IAnimalService { // 定义一个异步方法,用于获取动物信息 public async Task<Animal> GetAnimalAsync(CancellationToken cancellationToken) { // 模拟一个耗时的操作,延迟两秒钟 await Task.Delay(2000, cancellationToken); // 返回一个动物对象 return new() { Name = "Tom", Species = "Cat", Age = 5 }; ; } }在这个类中,我们定义了一个异步方法,该方法使用Task.Delay方法模拟一个耗时的操作,然后返回一个动物对象。
// 创建一个 Web 应用程序的构建器 var builder = WebApplication.CreateBuilder(args); // 添加控制器服务 builder.Services.AddControllers(); // 添加请求超时中间件服务 builder.Services.AddRequestTimeouts(); // 堆代码 duidaima.com // 添加动物服务 builder.Services.AddTransient<IAnimalService, AnimalService>(); // 创建一个 Web 应用程序 var app = builder.Build(); // 使用请求超时中间件 app.UseRequestTimeouts(); // 映射控制器 app.MapControllers(); // 运行应用程序 app.Run();在Program.cs中,我们先调用AddRequestTimeouts方法,来添加请求超时中间件服务,再使用UseRequestTimeouts方法将中间件添加到管道中。
// 定义一个控制器类 [ApiController] [Route("[controller]")] public class AnimalController : ControllerBase { // 注入动物服务 private readonly IAnimalService _animalService; public AnimalController(IAnimalService animalService) { _animalService = animalService; } // 创建一个端点,用于获取动物信息 [HttpGet("GetAnimal")] // 使用属性设置请求超时为 1 秒 [RequestTimeout(milliseconds: 1000)] public async Task<Animal> GetAnimalAsync() // 调用服务的方法,并传递取消令牌 => await _animalService.GetAnimalAsync(HttpContext.RequestAborted); }上面的代码中,我们创建一个控制器并注入服务,然后创建一个端点 GetAnimalAsync用于调用服务的方法,并传递一个CancellationToken。对于GetAnimalAsync端点,我们使用RequestTimeout属性将超时设置为 1 秒。如果希望控制器内的所有端点都具有相同的请求超时,则我们可以使用RequestTimeout属性来装饰控制器本身。
// 定义一个控制器类,并使用属性设置请求超时为 1 秒 [ApiController] [Route("[controller]")] [RequestTimeout(milliseconds: 1000)] public class AnimalController : ControllerBase { // 注入动物服务 private readonly IAnimalService _animalService; public AnimalController(IAnimalService animalService) { _animalService = animalService; } // 创建一个端点,用于获取动物信息 [HttpGet("GetAnimal")] public async Task<Animal> GetAnimalAsync() // 调用服务的方法,并传递取消令牌 => await _animalService.GetAnimalAsync(HttpContext.RequestAborted); }
这样,就可以为控制器中的所有端点应用相同的超时策略,而无需为每个单独设置。
// 创建一个端点,用于获取动物信息 app.MapGet("/GetAnimal", // 使用属性设置请求超时为 1 秒 [RequestTimeout(milliseconds: 1000)] async (HttpContext context, IAnimalService animalService) => { // 调用服务的方法,并传递取消令牌 return await animalService.GetAnimalAsync(context.RequestAborted); });我们创建一个终结点,它接受一个HttpContext和一个IAnimalService。在端点内部,我们调用服务的方法,并传递一个CancellationToken。我们还使用RequestTimeout属性装饰端点,并将超时设置为 1 秒。
// 创建一个端点,用于获取动物信息 app.MapGet("/GetAnimal", async (HttpContext context, IAnimalService animalService) => { // 调用服务的方法,并传递取消令牌 return await animalService.GetAnimalAsync(context.RequestAborted); }) // 使用扩展方法设置请求超时为 1 秒 .WithRequestTimeout(TimeSpan.FromMilliseconds(1000));我们从端点中删除超时属性,在末尾添加WithRequestTimeout方法。并传递了一个TimeSpan,表示请求应超时的持续时间。
// 添加请求超时中间件服务 builder.Services.AddRequestTimeouts(options => { // 使用 AddPolicy 方法创建一个命名策略,名称为 OneSecondTimeout,超时为 1 秒 options.AddPolicy("OneSecondTimeout", TimeSpan.FromMilliseconds(1000)); });在AddRequestTimeouts方法中,可以使用AddPolicy方法来创建一个命名策略。设置策略名称和超时时间后。我们就可以通过将策略名称传递给RequestTimeout属性或WithRequestTimeout方法使用。
// 创建一个端点,用于获取动物信息 [HttpGet("GetAnimal")] // 使用属性设置请求超时为 OneSecondTimeout 策略 [RequestTimeout("OneSecondTimeout")] public async Task<Animal> GetAnimalAsync() // 调用服务的方法,并传递取消令牌 => await _animalService.GetAnimalAsync(HttpContext.RequestAborted); // 定义一个控制器类,并使用属性设置策略 [ApiController] [Route("[controller]")] // 使用属性设置请求超时为 OneSecondTimeout 策略 [RequestTimeout("OneSecondTimeout")] public class AnimalController : ControllerBase { }为最小 API 配置请求超时策略
// 创建一个端点,用于获取动物信息 app.MapGet("/GetAnimal", // 使用属性设置请求超时为 OneSecondTimeout 策略 [RequestTimeout("OneSecondTimeout")] async (HttpContext context, IAnimalService animalService) => { // 调用服务的方法,并传递取消令牌 return await animalService.GetAnimalAsync(context.RequestAborted); }); // 创建一个端点,用于获取动物信息 app.MapGet("/GetAnimal", async (HttpContext context, IAnimalService animalService) => { // 调用服务的方法,并传递取消令牌 return await animalService.GetAnimalAsync(context.RequestAborted); }) // 使用扩展方法设置请求超时为 OneSecondTimeout 策略 .WithRequestTimeout("OneSecondTimeout");设置全局默认请求超时策略
// 添加请求超时中间件服务 builder.Services.AddRequestTimeouts(options => { // 使用 DefaultPolicy 属性设置全局超时策略,超时为 1.5 秒 options.DefaultPolicy = new RequestTimeoutPolicy { Timeout = TimeSpan.FromMilliseconds(1500) }; // 使用 AddPolicy 方法创建一个命名策略,名称为 OneSecondTimeout,超时为 1 秒 options.AddPolicy("OneSecondTimeout", TimeSpan.FromMilliseconds(1000)); });可以使用下面的代码来测试它:
// 创建一个端点,用于获取动物信息 [HttpGet("GetAnimal")] // 使用属性设置请求超时为 OneSecondTimeout 策略 [RequestTimeout("OneSecondTimeout")] public async Task<Animal> GetAnimalAsync() // 调用服务的方法,并传递取消令牌 => await _animalService.GetAnimalAsync(HttpContext.RequestAborted); // 创建另一个端点,用于获取动物信息 [HttpGet("GetAnimalWithDefaultTimeout")] public async Task<Animal> GetAnimalWithDefaultTimeoutAsync() // 调用服务的方法,并传递取消令牌 => await _animalService.GetAnimalAsync(HttpContext.RequestAborted);我们在控制器中添加两个端点,由于已经配置了全局超时策略,因此第二个端点不做任何其他配置。对GetAnimal调用将在一秒后超时,对GetAnimalWithDefaultTimeout的调用将在 1.5 秒后因全局策略而超时。同样的策略也可以应用于最小的 API。
// 添加请求超时中间件服务 builder.Services.AddRequestTimeouts(options => { // 使用 DefaultPolicy 属性设置全局超时策略,超时为 1.5 秒 options.DefaultPolicy = new RequestTimeoutPolicy { Timeout = TimeSpan.FromMilliseconds(1500), // 使用 TimeoutStatusCode 属性设置超时时返回的状态码为 500(内部服务器错误) TimeoutStatusCode = (int)HttpStatusCode.InternalServerError }; // 使用 AddPolicy 方法创建一个命名策略,名称为 OneSecondTimeout,超时为 1 秒 options.AddPolicy("OneSecondTimeout", TimeSpan.FromMilliseconds(1000)); });
如上面所示,我们将RequestTimeoutPolicy实例的TimeoutStatusCode属性设置为HttpStatusCode.InternalServerError。通过执行此操作,每个超时的请求都将返回状态代码 500。
// 创建一个端点,用于获取动物信息 [HttpGet("GetAnimal")] // 使用属性禁用请求超时 [DisableRequestTimeout] public async Task<Animal> GetAnimalAsync() // 调用服务的方法,并传递取消令牌 => await _animalService.GetAnimalAsync(HttpContext.RequestAborted); 对于最小的 API,我们有两个选项来配置超时,可以使用DisableRequestTimeout属性或DisableRequestTimeout扩展方法来设置。 // 创建一个端点,用于获取动物信息 app.MapGet("/GetAnimal", // 使用属性禁用请求超时 [DisableRequestTimeout] async (HttpContext context, IAnimalService animalService) => { // 调用服务的方法,并传递取消令牌 return await animalService.GetAnimalAsync(context.RequestAborted); }) // 创建一个端点,用于获取动物信息 app.MapGet("/GetAnimal", async (HttpContext context, IAnimalService animalService) => { // 调用服务的方法,并传递取消令牌 return await animalService.GetAnimalAsync(context.RequestAborted); }) // 使用扩展方法禁用请求超时 .DisableRequestTimeout();请求超时中间件可以帮助我们的应用程序在处理时间不确定的情况下保持稳定和高效。它的配置非常简单,适用于任何 API 或控制器。灵活的设置选项,让我们可以通过自定义不同的策略组合来完全控制应用程序的请求超时行为。