Я пытаюсь создать конечную точку минимального API ASP.NET Core 8 и пытаюсь заставить ее возвращать HttpProblemDetails
, когда параметры строки запроса недействительны. Конечно, я могу реализовать собственную проверку, но я пытаюсь использовать для этого фреймворк.
По сути, если у меня есть параметр строки запроса (например, целое число), а входные данные не являются допустимым целым числом, то я получаю обратно «неправильный запрос», но без какого-либо тела. Из-за этого потребителю сложно понять, что именно не так.
Вот воспроизведение модульного теста C# (я использую TestServer, но получаю тот же результат, когда использую пустельгу):
using System.Net.Http;
using System.Net;
using System.Reflection;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Shouldly;
namespace TestProject1
{
public class HttpProblemDetailsTests
{
[Fact]
public async Task Should_return_problem_details_if_querystring_not_provided()
{
var (host, testClient) = await SetupWebApp();
var response = await testClient.GetAsync("/problem");
response.StatusCode.ShouldBe(HttpStatusCode.BadRequest);
var text = await response.Content.ReadAsStringAsync();
// Fails on this line
text.ShouldNotBeEmpty();
await host.StopAsync();
}
[Fact]
public async Task Returns_ok_if_querystring_provided()
{
var (host, testClient) = await SetupWebApp();
var response = await testClient.GetAsync("/problem?abc=123");
response.StatusCode.ShouldBe(HttpStatusCode.OK);
await host.StopAsync();
}
private async Task<(IHost host, HttpClient testClient)> SetupWebApp()
{
var b = new HostBuilder()
.ConfigureWebHost(c =>
{
c.UseTestServer();
c.ConfigureServices(services =>
{
services.AddProblemDetails();
services.AddRouting();
});
c.Configure(app =>
{
app.UseExceptionHandler();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/problem", Problem);
});
});
});
var host = await b.StartAsync();
var testClient = host.GetTestClient();
testClient.DefaultRequestHeaders.Add("Accept", "application/json");
return (host, testClient);
}
public class MyParameters
{
public int Abc { get; set; }
}
private async Task<IResult> Problem([AsParameters] MyParameters p)
{
return Results.Text("Hello, World!");
}
}
}
Я пробовал еще несколько вещей:
IProblemDetailsWriter
, но, похоже, она не подходит[FromQuery]
, а не [AsParameters]
. Это дает тот же результат@beautifulcoder, как бы ты это сделал? Я не вижу никаких вариантов для этого ни в классе RouteOptions, ни в EndpointMiddleware.
Сначала вам нужно будет отправить неверный запрос:
var builder = WebApplication.CreateBuilder(args);
builder.Services.Configure<RouteHandlerOptions>(options =>
{
options.ThrowOnBadRequest = true;
});
Затем, как только выдается исключение. У вас должна быть возможность подключить обработчик исключений с помощью промежуточного программного обеспечения.
app.UseExceptionHandler("/error");
app.Map("/error", (HttpContext context) =>
{
var exception = context.Features.Get<IExceptionHandlerFeature>()?.Error;
if (exception is BadHttpRequestException badRequestException)
{
return Results.BadRequest(new ErrorResponse
{
Error = "Invalid Parameter",
Details = badRequestException.Message
});
}
return Results.Problem("An unexpected error occurred.");
});
Идея состоит в том, чтобы уловить как можно больше деталей и вернуть ответ с телом.
Спасибо. В итоге я решил обработку ошибки следующим образом: ''' Services.AddProblemDetails(opt => opt.CustomizeProblemDetails = context => { if (context.Exception is BadHttpRequestException ex) { context.HttpContext.Response.StatusCode = 400; context.ProblemDetails.Detail = ex.Message context.ProblemDetails.Status = 400 } }); '''
но «выброс неверных запросов» определенно был трюком. Должен быть более заметным в документации.
Вы можете настроить промежуточное программное обеспечение маршрутизации для выдачи ошибок при неправильном запросе. Это позволит вам обработать исключение и добавить тело.