I'm having an issue where a task is completing, but not returning back. I have a website and a web service on different servers. The website makes a call to the web service which utilizes a library with function myFunction(). If I make a call to myFunction from a console app on the web service's server, it will return as expected. However, when I make the call from the website to the web service to call myFunction(), it will get to "Step 3", but not "Step 4". I have a simplified version of the calls below.
private string myFunction()
{
string myStr = myDoWork().GetAwaiter().GetResult();
return myStr;
}
private async Task<string> myDoWork()
{
logger.Debug("Step 1");
string answer = await aFunction();
logger.Debug("Step 4");
return answer;
}
public async Task<string> aFunction()
{
logger.Debug("Step 2");
return await bFunction(CancellationToken.None);
}
AsyncLock myLock = new AsyncLock();
public Task<string> bFunction(CancellationToken cToken)
{
return Task.Run(
async () =>
{
using (await myLock(cToken))
{
logger.Debug("Step 3");
result = "Hello";
return result;
}
},
cToken);
}
I'm new to async and await, so any help would be appreciated.
If you use a Task return type for an async method, a calling method can use an await operator to suspend the caller's completion until the called async method has finished. In the following example, the WaitAndApologizeAsync method doesn't contain a return statement, so the method returns a Task object.
If you don't await the task or explicitly check for exceptions, the exception is lost. If you await the task, its exception is rethrown. As a best practice, you should always await the call. By default, this message is a warning.
The only time we truly want to await is when we do something with the result of the async task in the continuation of the method. Note that if we don't have return await, but return a Task<T> instead, the return happens right away, so, if the code is inside a try/catch block, the exception will not be caught.
DoSomething()' is an async method that returns 'Task', a return keyword must not be followed by an object expression.
It's almost certainly a deadlock in myFunction()
. Step 4 is scheduled to execute on the main thread, but it can't because the main thread is blocked waiting on GetResult()
.
It should be something closer to this:
private string myFunction()
{
// This is NOT good style - you should avoid blocking on the result of a task.
string myStr = Task.Run(async () => await myDoWork()).GetAwaiter().GetResult();
return myStr;
}
private async Task<string> myDoWork()
{
logger.Debug("Step 1");
string answer = await aFunction();
logger.Debug("Step 4");
return answer;
}
public Task<string> aFunction()
{
logger.Debug("Step 2");
return bFunction(CancellationToken.None);
}
AsyncLock myLock = new AsyncLock();
public async Task<string> bFunction(CancellationToken cToken)
{
using (await myLock(cToken))
{
logger.Debug("Step 3");
return "Hello";
}
}
In general, Task.Run()
should be called from the highest level possible. Keep things as synchronous as possible and let the caller decide if they want to use a background thread.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With