Repository navigation
Replies: 4 comments
|
This is a brilliant architectural question that highlights a known gap in the transition from traditional API Controllers ( You hit the nail on the head: Here is a breakdown of why this happens, why making Why is this happening?When you return a
Because it's The SolutionsInstead of fighting the internal wrapper in an Option 1: Use
|
|
I think the key here is where each filter runs in the MVC pipeline. Looking at the current ASP.NET Core implementation, The relevant flow in var result = await filterDelegate(context);
return ConvertToActionResult(
mapper,
result,
returnType);and then if (value is IResult httpResult)
{
return new HttpActionResult(httpResult);
}So by the time an That also explains why reflection works but feels wrong: there currently isn't a public MVC abstraction on For this particular use case, I would therefore move the inspection one level earlier and use an Controller endpoints support endpoint filters, so this can also be applied to app.MapControllers()
.AddEndpointFilter<TypedResultFilter>();For example: public sealed class TypedResultFilter : IEndpointFilter
{
public async ValueTask<object?> InvokeAsync(
EndpointFilterInvocationContext context,
EndpointFilterDelegate next)
{
var result = await next(context);
var httpResult = result switch
{
INestedHttpResult nested => nested.Result,
IResult direct => direct,
_ => null
};
if (httpResult is IStatusCodeHttpResult statusResult)
{
var statusCode = statusResult.StatusCode;
// Inspect status code here.
}
if (httpResult is IValueHttpResult valueResult)
{
var value = valueResult.Value;
// Inspect response value here.
}
return result;
}
}I would prefer using the public result contracts such as The Results<Ok<MyResponse>, NotFound>because the union itself contains the actual If you need type-specific behavior, you can of course still inspect the concrete result: if (httpResult is Ok<MyResponse> ok)
{
var response = ok.Value;
}Regarding making
What I think would be more useful, if MVC result filters are expected to support this scenario, would be a public abstraction that allows an But with the APIs available today, if the purpose of the filter is to inspect a So I don't think you're missing a way to unwrap |
|
I think the important distinction here is where the result is being inspected in the pipeline. When a controller returns a So I would avoid depending on For this use case, an endpoint filter seems like a cleaner boundary because controller actions can also have endpoint filters applied: app.MapControllers()
.AddEndpointFilter(async (context, next) =>
{
var result = await next(context);
if (result is IStatusCodeHttpResult statusResult)
{
var statusCode = statusResult.StatusCode;
// inspect status
}
if (result is IValueHttpResult valueResult)
{
var value = valueResult.Value;
// inspect response value
}
return result;
});If you're returning a typed union such as: Results<Ok<MyResponse>, NotFound>I'd also account for var result = await next(context);
var httpResult = result switch
{
INestedHttpResult nested => nested.Result,
IResult direct => direct,
_ => null
};
if (httpResult is IStatusCodeHttpResult status)
{
Console.WriteLine(status.StatusCode);
}
if (httpResult is IValueHttpResult value)
{
Console.WriteLine(value.Value);
}
return result;That has a couple of advantages over checking concrete types such as
So I don't think you're overlooking a public way to unwrap If the purpose of the filter is specifically to inspect the original |
|
You're not missing anything: HttpActionResult is internal and there's no There is a supported extension point though. The conversion from an action's Then your result filter can pattern match without reflection. The IResult If you'd rather not replace a framework service, the alternative is opening an If this solves it, feel free to mark it as the answer. |
Uh oh!
There was an error while loading. Please reload this page.
Hi community,
I'm using ASP.NET core version 10.0.7 with API contrllers.
We're currently using the
IActionResultinterface as return type on our controller actions and would like to migrate to TypedResults, as this provides strong typing for responses AND automatically documents the response types in our OpenAPI specifications.With the old ActionResults i was able to create an IAsyncResultFilter and inspect the type of the result. This can be done quite easily by using pattern checking on the type
ObjectResult, or other derived types such asNotFoundResult. However, for the TypedResult classes, the result type isHttpActionResult, which is an ASP.NET core internal type. So for now, i don't have a way to access the (typed) result using this filter, other than using reflection to access theResultproperty of theHttpActionResult, but that doesn't feel like the way to do it.I could not find any documentation on other filters that are able to access the (typed) result, so am i missing something, or should the
HttpActionResulttype be public instead of internal?All reactions