在我们的项目中,我们有一个由前同事编写的测试,该测试正在向端点发出请求,该端点应该并且确实在抛出异常后返回 500 - InternalServerError (使用 Shouldly 检查这一点)。
为了演示目的,简化了以下代码。
端点:
[HttpGet]
[Route("machines/{idMachine:guid}/admin")]
[Authorize(Policy = Policies.RequireMachineCustomerCheck)]
public IActionResult MachineEditor(Guid idMachine)
{
// Lookup machine...
if (machine == null)
{
throw new Exception("Exception");
}
}
测试:
[Fact]
public async Task MachineNotFoundShouldThrowException()
{
var idMachine = Guid.NewGuid();
var uri = new Uri($"/machines/{idMachine}/admin", UriKind.Relative);
var httpClient = new HttpClient();
var response = await httpClient.GetAsync(uri);
response.StatusCode.ShouldBe(HttpStatusCode.InternalServerError);
}
但是,自从从 .NET Core 3.1 更新到 .NET 6 后,我们的 Azure DevOps YAML 部署管道在运行测试时报告异常。然而,它是从不同的代码路径抛出的,在我们端点的授权策略中:
执行请求时发生未处理的异常。 System.Exception:在服务器的内存缓存中找不到机器 ID 为 7f6825f9-3e4c-4d32-aace-ec9128394e0c。要么缓存已过时 或者ID不正确。 在Proseal.Portal.Services.Utilities.CacheHelper.GetProVisionMachine(Guid idMachine)中 D:\ s \ Proseal \ Portal.Services \ Utilities \ CacheHelper.cs:第72行 在Proseal.Portal.Server.Common.Authorization.MachineCustomerCheckHandler.HandleRequirementAsync(AuthorizationHandlerContext 上下文,MachineCustomerCheck 要求)中 D:\ s \ Proseal \ Portal.Server \ Common \ Authorization \ MachineCustomerCheck.cs:行 83 在 Microsoft.AspNetCore.Authorization.AuthorizationHandler
1 要求) 在 Microsoft.AspNetCore.Authorization.Policy.PolicyEvaluator.AuthorizeAsync(AuthorizationPolicy 策略、AuthenticateResult 身份验证结果、HttpContext 上下文、 对象资源) 在 Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext 语境) 在Proseal.Portal.Server.Common.Middleware.AuthenticationForStaticFilesMiddleware.InvokeAsync(HttpContext 上下文,RequestDelegate 接下来)中 D:\s\Proseal\Portal.Server\Common\Middleware\AuthenticationForStaticFilesMiddleware.cs:行 43 在 Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.<>c__DisplayClass6_1.1.HandleAsync(AuthorizationHandlerContext context) at Microsoft.AspNetCore.Authorization.DefaultAuthorizationService.AuthorizeAsync(ClaimsPrincipal user, Object resource, IEnumerable
d.MoveNext()
授权策略注册:
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthorization(options =>
{
options.AddPolicy(Policies.RequireMachineCustomerCheck, policy => policy.Requirements.Add(new MachineCustomerCheck()));
}
}
}
验证处理程序:
public class MachineCustomerCheckHandler : AuthorizationHandler<MachineCustomerCheck>
{
protected override Task HandleRequirementAsync()
{
// Lookup machine
if (machine == null)
{
throw new Exception("Exception");
}
}
在 Visual Studio 2022 的测试资源管理器中本地运行测试不会引发异常或失败,但对其进行调试可确认引发异常。由于返回了 500,测试仍然通过。不知道为什么部署管道的行为与 VS 不同。
将测试包装在 try-catch 中是我的第一个想法,但异常没有被捕获。
try
{
var response = await httpClient.GetAsync(uri);
response.StatusCode.ShouldBe(HttpStatusCode.InternalServerError);
}
catch (Exception exception)
{
exception.Message.ShouldBe("Exception");
}
经过一番谷歌搜索后,我改变了这一点,但得到了相同的行为。
try
{
await Task.Run(async () => await httpClient.GetAsync(uri));
}
catch (Exception exception)
{
exception.Message.ShouldBe("Exception");
}
我也尝试过使用 Shouldly 的 ShouldThrowAsync 方法:https://docs.shouldly.org/documentation/exceptions/throw#shouldthrowasync,但这也无法捕获异常。
Func<Task> func = async () => await httpClient.GetAsync(uri);
await Should.ThrowAsync<Exception>(func);
担心异步代码(因此异常)包含在单独的线程中可能存在另一个问题,但我的异步知识不是最好的,所以我缺乏其他可以尝试的东西。
例如,如果您使用 XUnit,您可能会遇到如下异常:
await Assert.ThrowsAsync<ExceptionType>(() => testContext.httpClient.GetAsync(uri));
如果您继续遇到不属于此类别的异常,请检查您的 DI。过去曾遇到过未正确捕获/抛出 DI 错误的情况。