I am converting a authentication process to support async and the VS 2015 IDE is warning me with the following message: The async method lacks 'await' operators and will run synchronously... etc...
Anyway, the code connects to a LDAP store and verifies a user's account and etc... I have tried various things with await, but I am just missing something here. I put the code back to what it was before.. I would appreciate any guidance in getting it to support async correctly...
Here is the code:
public async Task<User> GetAsyncADUser(PrincipalContextParameter param)
{
try
{
if (UseLDAPForIdentityServer3)
{
using (var pc = new PrincipalContext(ContextType.Domain, param.ADDomain, param.ADServerContainer, param.ADServerUser, param.ADServerUserPwd))
{
UserPrincipal userPrincipal = UserPrincipal.FindByIdentity(pc, param.UserNameToValidate);
if (userPrincipal != null)
{
bool isvalid = pc.ValidateCredentials(userPrincipal.DistinguishedName, param.UserPasswordToValidate, ContextOptions.SimpleBind);
if (isvalid)
{
User user = new User { ad_guid = userPrincipal.Guid.ToString(), Username = param.UserNameToValidate, Password = param.UserPasswordToValidate };
return user;
}
}
}
}
}
catch (Exception ex)
{
throw;
}
return null;
}
Just as it says, your code is synchronous. If you wrapped whatever
UserPrincipal.FindByIdentity
andPrincipalContext.ValidateCredentials
do in a Task and return that, then you could have this do its work async.As Stephen Cleary's comment said, if there is a lower level you can perform the work in async, do it there and pass the async/await up to this level. Hard to say without knowing what those methods look like though.
That would allow you to put awaits on them and your code would be async.
The try catch block can be left.... To run the code async, just put it in an action within
Task.Run
:From MSDN:
The following characteristics summarize what makes an async method:
The name of an
async
method, by convention, ends with an "Async" suffix. The return type is one of the following types:Task<TResult>
if your method has a return statement in which the operand has typeTResult
.Task
if your method has no return statement or has a return statement with no operand.Void
if you're writing an async event handler.The method usually includes at least one await expression, which marks a point where the method can't continue until the awaited asynchronous operation is complete. In the meantime, the method is suspended, and control returns to the method's caller. The next section of this topic illustrates what happens at the suspension point.
You can use
return Task.Run(() => { /* your code here */ })
and return aTask<User>
. Then you can call this method as :That way, you don't need to use the
async
keyword in the methodGetAsyncADUser
, but you need to mark the method that uses the above line of code with theasync
keyword.It appears in this code block there is no asynchronous call to be awaited.... By that I mean, no method call that returns a Task.
For example, if the method
UserPrincipal.FindByIdentity()
was an async method, (returnsTask<UserPrincipal>
) then it could be awaited like so:UserPrincipal userPrincipal = await UserPrincipal.FindByIdentity();
But, it is not an async method therefore there is nothing to be awaited. One thing you can do here is wrap the code you want to run asynchronously in a helper method, execute that helper method via
Task.Run(() => RunMeAsync());
and await the result of the new task you just started.var result = await Task.Run(() => RunMeAsync());
where
RunMeAsync()
is the helper method that you want to run asynchronously.