Async/await redux (Oxygene on .NET)

I know this has been gone over numerous times before, not least in this thread but just as I think I’ve gotten my head around things, some seemingly anomalous behaviour creeps in and my understanding disappears like mist on hot glass.

Context:

I am implementing an ASP.NET WebAPI App Service (to be hosted on Azure). Cross platform issues w.r.t async/await are not involved. I am interested purely in implementing the async/await patterns routinely found in ASP.NET code and how that relates to async/await usage in Oxygene.

Specifically, I have been following a series of articles on securing API’s with OAuth and spent 2 days trying to figure out why my Oxygene version of the very simple initial scaffolding was not working. It now appears to be due to some misunderstanding about async/await and/or the alternative/equivalent incantations.

When implementing a custom OAuthAuthorizationServerProvider there are two methods I need to override in a simple subclass.

First, I shall use the simplest of the two methods (ValidateClientAuthentication) alone to explore the first question that I have around the declaration of async methods (by which I mean .NET async methods, which according to the Oxygene docs appears to be equivalent, at least when used as a method decorator as opposed to in an async expression):

With my overrides I can declare the override of a method either as async or as returning a Task, but not both:

AuthorizationServerProvider = public class(OAuthAuthorizationServerProvider)
public
  // I can declare EITHER this:
  method ValidateClientAuthentication(context: OAuthValidateClientAuthenticationContext): Task; override; 

  // OR this:
  method ValidateClientAuthentication(context: OAuthValidateClientAuthenticationContext); async; override; 

  // But NOT this (no method to override):
  method ValidateClientAuthentication(context: OAuthValidateClientAuthenticationContext): Task; async; override; 
end;

This would seem to suggest that the async decorator implies the return of a Task, making the async override valid and the combination of both async and a Task return type as unnecessary (and hence invalid since it would result in a method returning a Task<Task> which is not present in the base class, yes ?).

Worth noting is that in the tutorial steps I am following, the C# I am trying to replicate/translate is:

public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)

But when I come to the implementation of the method, a significant difference emerges between the required implementations of the two possible valid declarations. First, if I implement the async override:

  method AuthorizationServerProvider.ValidateClientAuthentication(context: OAuthValidateClientAuthenticationContext); // declared async, therefore no Task return type
  begin
      context.Validated;
  end;

My override is never called. A breakpoint placed on the context.Validated is never hit. But if I implement the Task override I get a different problem:

  method AuthorizationServerProvider.ValidateClientAuthentication(context: OAuthValidateClientAuthenticationContext): Task;
  begin
      context.Validated;
  end;

The above code is most nearly equivalent to the C# code:

    public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
    {
        context.Validated();
    }

Now, in my Oxygene implementation, a breakpoint on the context.Validated call will be hit, but the a null object reference exception is then thrown by the server, presumably because the method failed to return a Task - i.e. returned a null task which the OAuth pipeline then crashes into.

I found that the only way to make this work was to explicitly instantiate and return a started Task:

  method AuthorizationServerProvider.ValidateClientAuthentication(context: OAuthValidateClientAuthenticationContext): Task;
  begin
    result := new Task(-> begin
      context.Validated;
    end);

    result.Start;
  end;

Is this really what I have to do ? Isn’t async specifically supposed to take care of this scaffolding ?

I know that in this case there is no call to await in the async method, which as I understand it means that the async is itself superfluous in this case (and curiously the method in the base class does not itself have the AsyncStateMachineAttribute on it). But the same question arises with the next, more complex method which does use await (but which similarly does not have the state machine attribute on the base class implementation).

That other method is GrantResourceOwnerCredentials() which has essentially the same declaration as the previous method, only with a different type for the passed in context parameter. i.e. the same issue of declaring async or as returning Task in the override applies and equally I need to scaffold and start my own Task instance in the implementation.

But this method also uses an await call. First, the full body of the method (as most nearly equivalent to the C# implementation):

method AuthorizationServerProvider.GrantResourceOwnerCredentials(context: OAuthGrantResourceOwnerCredentialsContext): Task;
begin
  result := new Task(-> begin
    // This response header is required for CORS (Cross-Origin Resource Sharing)

    context.OwinContext.Response.Headers.Add('Access-Control-Allow-Origin', ['*']);

    // Simple username/password check:  If no user exists with the specified
    //  username and password then we will return an error.

    using repo := new AuthRepository do
    begin
      var user := await repo.FindUser(context.UserName, context.Password);

      if user = nil then
      begin
        context.SetError('invalid_grant', 'The user name or password is invalid');
        exit;
      end;
    end;

    // SUCCESS!  Initialise a ClaimsIdentity - when we validate the context we will pass in the 
    //  claims to be used to produce the bearer token (which will be returned to the client)

    var identity := new ClaimsIdentity(context.Options.AuthenticationType);
    identity.AddClaim(new Claim('sub', context.UserName));
    identity.AddClaim(new Claim('role', 'user'));

    context.Validated(identity);
  end);

  result.Start;
end;

The focus here is on the use of the await when calling into the repo.

      var user := await repo.FindUser(context.UserName, context.Password);

As implemented above, if I place a breakpoint on the var user := … line and step over (assuming valid user credentials have been supplied) the repo.FindUser() method has returned an IdentityUser and this is what the user variable contains if I inspect it in the debugger. If I step through, I see that the code then follows the path for a successful token request initialises the identity and terminates on the context.Validated(identity) call.

But the response back to my REST client is “invalid_grant”. I cannot explain this at all.

I have however found that if I remove the await call with (what I think) is equivalent scaffolding:

    var user := repo.FindUser(context.UserName, context.Password);
    user.Wait;

    if user.Result = nil then

Again, stepping through this in the debugger I see that user now holds a Task<IdentityUser> reference and following the Wait call, user.Result indeed holds the expected IdentityUser. The code then proceeds again to follow the flow for a successful token request but this time a valid token is returned to my client !!!

Can anyone explain what in the doo-hickey is going on here ?

For completeness, here’s the decl and implementation of the repo method involved. As you can see it follows the same pattern of returning a Task but not being declared async:

type
  AuthRepository = public class(IDisposable)
    // ..
    method FindUser(userName: String; auth: String): Task<IdentityUser>;
    // ..
  end;

implementation

method AuthRepository.FindUser(userName: String; auth: String): Task<IdentityUser>;
begin
  result := await _userManager.FindAsync(userName, auth)
end;

_userManager is the usual ASP Identity Framework class (backed by a vanilla EF user store). If I remove the await from the call to the _userManager it makes absolutely no difference what-so-ever to the behaviour in my Authorization code (that is: with the await [in the Authorization code] I get an invalid grant / with ‘explicit waiting’ scaffold I get a token).

What am I not understanding correctly / at all ?

Many thanks in advance.

I had similar issues with async. I think the documentation needs to point out the difference, especially if you have experience with c#, its not so obvious as to what you have done wrong.

Maybe post a complete example for the await issue ?