When does WebApi2 use OnAuthorizationAsync vs OnAu

2020-06-14 08:21发布

问题:

We've recently implemented API authentication by implementing a custom AuthorizationFilterAttribute, using credentials stored in Azure Document DB. DocDB mandates everything use Async.

Through experimenting we found that WebApi2 synchronous controllers will use the OnAuthorizationAsync if present, and OnAuthorization if no async method. We also found that asyc controller methods can use either auth method. But I'm not 100% sure it is working correctly. We only saw that code did hit breakpoints.

Oddly, you can also override OnAuthorization mark it as async

public async override Task OnAuthorization(....)

This last method compiles and executes fine, but the controller will not wait for the auth filter to finish executing before the action method begins. Usually the result is an ASP error:

An asynchronous module or handler completed while an asynchronous operation was still pending

Seems like this manipulation of the override should have been a compile error and not allowed.

Regardless.... There are many mysteries about AuthorizationFilterAttribute and a few other posts exist about the confusion. Custom Authorization in Asp.net WebApi - what a mess?

My question is how do you know which will execute and in which order of precedence? It does appear if both exist in the filter, only one method is executed.

  1. If your controller action is async, must you override the OnAuthorizationAsync method?

  2. If you have async await in your auth logic, and are forced to use OnAuthorizationAsync (like I am), does this then mean I have to change all my controller actions to now all be async controller actions?

I can't find any documentation that lays out scenarios for async action filters.

回答1:

If you take a look at the source code of AuthorizationFilterAttribute then you can see that the base implementation of OnAuthorizationAsync is the one actually calling OnAuthorization.

public virtual void OnAuthorization(HttpActionContext actionContext)
{
}

public virtual Task OnAuthorizationAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
{
    try
    {
        OnAuthorization(actionContext);
    }
    catch (Exception ex)
    {
        return TaskHelpers.FromError(ex);
    }

    return TaskHelpers.Completed();
}

As you can see, you can actually override either method you want and you don't need to call the base implementation. Just choose the one which makes more since for your scenario - it doesn't matter if the controller is async or not.

And regarding your question about marking OnAuthorization itself as async - the code compiles since that's the way C# async support is designed, but it indeed causes the calling code to not wait for the async part to complete (it actually can't wait since the method is marked async void and not async Task. You can read more about async avoid here.