WebResultEndpoint transforms the result returned by its HandleAsync method —a WebResult object encapsulating business result— into appropriate HTTP status code and response format, providing consistent and type-safe API behavior. This process relies on ExecuteAsync method implementation of the returned WebResult object. Since encapsulated business result may be in Ok or Failed state with any failure type, ExecuteAsync method is responsible for mapping different business result states to corresponding HTTP responses.
WebResults static class provides factory methods to create various WebResult implementations for common scenarios:
FromResultmethod: This creates a default implementation ofWebResult.WithLocationUriOnSuccessmethod: This creates aWebResultthat returns aLocationheader set to provided Uri when mapped HTTP response is either201 Createdor202 Accepted. Otherwise, it behaves like a defaultWebResult.WithLocationRouteOnSuccessmethod: This creates aWebResultthat returns aLocationheader based on a named route when mapped HTTP response is either201 Createdor202 Accepted. Otherwise, it behaves like a defaultWebResult.
There are several ways to customize how responses are mapped:
-
One way is to implement a custom class inheriting abstract
WebResult, where you overrideExecuteAsyncmethod to provide your custom mapping logic. Then return an instance of the customWebResultclass from the endpoint handler method, -
Another way to customize response mapping is by overriding the
ConvertResultToResponseAsyncmethod. This method is invoked- after
HandleAsyncto transform the business result into an HTTP response. - or after
HandleValidationFailureAsyncif request validation fails.
- after
By default, ConvertResultToResponseAsync method just calls the ExecuteAsync method of the input parameter WebResult object, but you can override it to implement your own mapping logic.
internal class GetBookById(ServiceDbContext db)
: WebResultEndpoint<GetBookByIdRequest, GetBookByIdResponse>
{
protected override void Configure(
EndpointConfigurationBuilder builder,
EndpointConfigurationContext configurationContext)
{
builder.MapGet("/{Id}")
.Produces<GetBookByIdResponse>();
}
protected override ValueTask<IResult> ConvertResultToResponseAsync(
WebResult<GetBookByIdResponse> result,
HttpContext context,
CancellationToken ct)
{
// Custom mapping logic here
}
protected override async Task<WebResult<GetBookByIdResponse>> HandleAsync(
GetBookByIdRequest req,
CancellationToken ct)
{
// implementation
}
}