Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does async/await method in attribute never return

Ok so bear with me this might take some explaining, i have a simple Account controller thus;

[RoutePrefix("api/account")]
[Authorize]
[HmacAuthentication]
public class AccountController : ApiController
{
    public async Task<IHttpActionResult> Register(UserModel userModel)
    {
        if (!this.ModelState.IsValid)
        {
            return this.BadRequest(this.ModelState);
        }

        IdentityResult result = await this._userService.RegisterUser(userModel);

        var errorResult = this.GetErrorResult(result);
        if (errorResult != null)
        {
            return errorResult;
        }

        return this.Ok();
    }
}

The HmacAuthentication attribute is here:

public class HmacAuthenticationAttribute : Attribute, IAuthenticationFilter
{
    public Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken)
    {
        ...

        var isValid = this.IsValidRequest(req, appId, incomingBase64Signature, nonce, requestTimeStamp);

        if (isValid.Result)
        {
            ...
        }
        ...
    }

    private async Task<bool> IsValidRequest(
        HttpRequestMessage req, 
        string appId, 
        string incomingBase64Signature, 
        string nonce, 
        string requestTimeStamp)
    {
        ...
        var user = await this.UserService.FindUser(userId); // this never gets a return value
        ...
    }
}

The method called in the UserService is this:

public async Task<ApplicationUserModel> FindUser(int id)
{
    var user = await this._userBusiness.FindAsync(id);
    return this.MapToModel(user);
}

and in the business class is this:

public async Task<ApplicationUser> FindAsync(int id)
{
    var result = await this._userManager.FindByIdAsync(id);
    return result;
}

The problem that i am facing is that when the Register method is called the HmacAuthentication attribute fires and the AuthenticateAsync filter method executes. The call in IsValidRequest to lookup a user is never actually getting a return value, if i try a request through postman it never completes.

Can anyone help with this please?

like image 615
Neil Stevens Avatar asked Jan 08 '23 01:01

Neil Stevens


1 Answers

public async Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken)
    {
        ...

        var isValid = await this.IsValidRequest(req, appId, incomingBase64Signature, nonce, requestTimeStamp);

        if (isValid)
        {
            ...
        }
        ...
    }

As the compiler suggested, you can only use the await keyword inside of a method marked as async. So I have updated the signature for AuthenticateAsync accordingly. Also note that you can just check isValid now instead of doing isValid.Result since the value of the boolean will be available past the await line.

This can be a little confusing as the interface for IAuthenticationFilter doesn't specify async (interfaces can't, they can only indicate that the method will return a Task). It is up to the implementer to determine whether or not the method will simply return the task or will supply an async so that values can be awaited inside the method body.

like image 77
Jesse Carter Avatar answered Jan 12 '23 00:01

Jesse Carter