Why is my async function hanging when calling task.run function - c#

I want to make a function async since I'd like to return the results to the UI and don't want to make this hang, but it is anyway.
Can someone tell me why this would be hanging?
public ActionResult Index()
{
return View(FunctionThreeAsync().Result);
}
private async Task<MyType> FunctionThreeAsync()
{
return await FunctionThree();
}
private Task<MyType> FunctionThree()
{
return Task.Run<MyType>(() => { /* code */ });
}

This:
return View(FunctionThreeAsync().Result);
Is deadlocking your code. You shouldn't be blocking on an async method. Instead, mark your method as async, make it return a Task<T> and await the call:
public async Task<ActionResult> DoStuffAsync()
{
return View(await FunctionThreeAsync());
}
Async goes all the way. When you have a method that's async, it will need to be asynchronously waited on, not synchronously blocked on. This means spreading async throughout your code base.

Related

How can I call an async method within a sync method?

I'm trying to call an async task (SIn) within a synch method (SignIn). I need the synch method because I'm passing ref to that method. But when I'm calling the async task, the GUI is frozen. The async task is a simple login with the onedrive sdk.
I've tried to waited the task, but the GUI still frozen. I've also tried creating a new Thread, but it didn't work too. How can I call the async method?
public override bool SignIn(ref User user)
{
try
{
signInEnd = false;
signinUser = user;
Task<bool> task = SIn();
task.Wait();
return task.Result;
}
catch(Exception e)
{
return false;
}
}
public async Task<bool> SIn()
{
var msaAuthProvider = new MsaAuthenticationProvider(
this.oneDriveClientId,
this.oneDriveReturnUrl,
this.scopes,
new CredentialVault(this.oneDriveClientId));
await msaAuthProvider.AuthenticateUserAsync();
driveClient = new OneDriveClient(this.oneDriveBaseUrl, msaAuthProvider);
}
Calling Wait() blocks the UI thread which means that the continuation of SIn(), i.e. the part that will eventually be executed once the Task returned by AuthenticateUserAsync() has completed, won't be able to execute on this thread. This results in a deadlock.
You may be able to get around this by avoiding capturing the context by calling ConfigureAwait(false) in SIn():
public async Task<bool> SIn()
{
var msaAuthProvider = new MsaAuthenticationProvider(
this.oneDriveClientId,
this.oneDriveReturnUrl,
this.scopes,
new CredentialVault(this.oneDriveClientId));
await msaAuthProvider.AuthenticateUserAsync().ConfigureAwait(false);
driveClient = new OneDriveClient(this.oneDriveBaseUrl, msaAuthProvider);
}
But the "real" solution to this kind of issues is not to mix asynchronous and synchronous code, i.e. SignIn should be asynchronous and await SIn(). Don't block on asynchronous code by calling Wait() or Result:
public Task<bool> SignIn(User user)
{
try
{
...
return await SIn();
}
catch (Exception e)
{
return false;
}
}
Please refer to #Stephen Cleary's blog post for more information about this.
mm8 is right that not calling async from inside a sync method is the best way to solve your issue,
remember that the public async void EventHandler() method was specifically designed for running long running tasks from a gui linked control
However it isn't always possible to rewrite an entire system to be async when only one small section needs changing
In this case you should avoid waiting for the results as this makes the async process pointless, what you can do though is break your synchronous code into 2 parts a before and after
the before method will prep and launch the task,
the after handles the results
ie
public async Task<string> GetData(int delay)
{
await Task.Delay(delay);
return "complete";
}
public void StartGettingData()
{
GetData(5000).ContinueWith(t => CompleteGetData(t.Result), TaskScheduler.Current);
}
public void CompleteGetData(string message)
{
UpdateStatus(message);
}
this method does have the added complexity of requiring you to ensure thread safety yourself, which is why the async/await functionality was introduced

Convert conventional method to Asynchronous

I have an API which is responsible for inserting text message details in database.
It does by making synchronous call to repository which I think could be implemented asynchronous way.How can I achieve this? Or what could be the best way to handle this scenario.Code snippet example is highly appreciated as I am still getting my ahead wrapping around .NET.
api:
public IHttpActionResult SendSMSNotification([FromBody] SMSNotification smsNotification)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
_service.SendSMS(smsNotification);
return Ok();
}
Service:
internal void SendSMS(SMSNotification smsNotification)
{
_repository.Notify(_mapperService.GetSMSNotification(smsNotification));
}
mapper:
public SMSNotification GetSMSNotification(SMSNotification message)
{
return AutoMapper.Mapper.Map<SMSNotification>(message);
}
repo:
public virtual bool Notify(SMSNotification request)
{
using (var sql = _sqlMapper.CreateCommand('Database', 'Stored proc'))
{
sql.AddParam("#fMessage", request.Message);
//..............
//.............. more params
var retvalParamOutput = sql.AddOutputParam("#fRetVal", System.Data.SqlDbType.Int);
sql.Execute();
return retvalParamOutput.GetSafeValue<int>() == 1;
}
}
sql here is a custom thing and it has following methods:
public static int Execute(this IDataCommand #this);
[AsyncStateMachine(typeof(<ExecuteAsync>d__1))]
public static Task<int> ExecuteAsync(this IDataCommand #this);
Changing a blocking, typically IO-bound call (such as database, network or file system work) to async can make your app scale better.
This does have a flow-on affect through your API. That is, you need to be awaiting on asynchronous calls all the way up to the top-most call, otherwise, somewhere is going to block and you're just lost the benefit of calling an async API.
To demonstrate that, let's start from the bottom at the repository call, as that's the possibly expensive blocking operation can be made async. We alter sql.Execute to use the asynchronous version ExecutAsync version instead:
repo:
public virtual async Task<bool> Notify(SMSNotification request)
{
using (var sql = _sqlMapper.CreateCommand('Database', 'Stored proc'))
{
sql.AddParam("#fMessage", request.Message);
//..............
//.............. more params
var retvalParamOutput = sql.AddOutputParam("#fRetVal", System.Data.SqlDbType.Int);
await sql.ExecuteAsync();
return retvalParamOutput.GetSafeValue<int>() == 1;
}
}
Now here we have to change the signature of the method to return a Task wrapping a result of bool.
We also mark the method as async, so then we can use the "await" operator further down. Without doing this, we'd have to do more refactoring to manipulate and return the Task result ourselves, but the "async" modifier and "await" keyword let the compiler do that magic for us, and the rest of our code mostly looks like normal.
The mapper call doesn't really need to change:
mapper:
public SMSNotification GetSMSNotification(SMSNotification message)
{
return AutoMapper.Mapper.Map<SMSNotification>(message);
}
The service call is now making a call to an async method, so because we want to await and not block on that async call, we have to also change this previously void method to an async method. Note we change it from "void" to "async Task"; you CAN mark a void method as "async void", but that's intended as a workaround for event handlers in Windows Forms and WPF apps; in every other case you want to change a "void" method to "async Task" when making it async.
Service:
internal async Task SendSMS(SMSNotification smsNotification)
{
await _repository.Notify(_mapperService.GetSMSNotification(smsNotification));
}
Then finally, our API call can be made async, and await our service call:
api:
public async Task<IHttpActionResult> SendSMSNotification([FromBody] SMSNotification smsNotification)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
await _service.SendSMS(smsNotification);
return Ok();
}
It's sometimes recommended that after you do a refactor like this, to rename the methods to end in "Async" by convention; however I don't think this is really compulsory, as so much of the .NET API surface is becoming async, it's almost redundant now.
It's worth getting your head around the async / await stuff though; I've tried to keep the example relatively brief. But I hope this at least gets you started.

Error on calling Task.Run to create an async process

I've been reviewing the code an app dev company has been doing for me in Xamarin. When I try to compile
namespace AppName.Droid
public class SplashActivity : AppCompatActivity
{
protected override void OnStart ()
{
base.OnStart ();
Task.Run (Login);
}
async void Login()
{
await LoadCurrentProfile().ContinueWith(result => {
if (ApplicationState.Profile== null)
{
GoLogin ();
}
else
{
GoBegin ();
}
});
}
}
There is an error on "Task.Run(Login)" that
'void SplashActivity.Login()' has the wrong return type
Is there something that I can change so that I can compile the app on my machine?
There's several things wrong with your approach to async. I recommend you read my async intro blog post and async best practices article.
In particular, you should follow these conventions:
Don't use ContinueWith. Use await instead.
Avoid async void. Use async Task unless you have to use async void.
Use Task.Run to push CPU-bound work off the UI thread. In the case of your code, there's no reason to use Task.Run.
Combining these, the code is quite simplified, and also has more reasonable semantics (in particular, login errors are not silently ignored):
protected override async void OnStart ()
{
base.OnStart();
await LoginAsync();
}
async Task LoginAsync()
{
await LoadCurrentProfile();
if (ApplicationState.Profile == null)
{
GoLogin();
}
else
{
GoBegin();
}
}
Change the signature of Login to return a Task like this:
async Task Login()
{
//...
}
And call it like this:
Task.Run( (Func<Task>) Login);
or
Task.Run(() => Login());
Please note that since Login is an asynchronous method, you can also call it directly without using Task.Run like this (I am assuming that you want to fire and forget):
Login();

Is async keyword necessary in the method signature when calling another async method internally?

Here's a C# async code snippet. Is GetAsync the same as GetAsync2? Is GetAsync a right implementation?
public Task<IHttpActionResult> GetAsync()
{
return GetOneAsync();
}
public async Task<IHttpActionResult> GetAsync2()
{
return await GetOneAsync();
}
private async Task<IHttpActionResult> GetOneAsync()
{
using (var httpClient = new HttpClient())
{
await httpClient.GetAsync("http://baidu.com");
}
return Ok();
}
It is not the same. GetAsync does not generate a state machine and does not wait for the result of GetOneAsync, which is the preferred option when the result of the async method is not needed in this method.
The resulting code is more efficient as well as no state machine is generated and no context switch is required.
See Understanding the cost of Async/Await article for more info.

MVC4 Task<IEnumerable> not awaitable

I'm looking at examples, just trying to understand the await keyword in a MVC AsyncController. I feel like the following should work as I am just trying to return a list asynchronously. This was just an example for understanding the async keyword:
public async Task<ActionResult> Index()
{
var s = await SelectAsync();
return View(s);
}
private async Task<IEnumerable<Student>> SelectAsync()
{
var ctx = new Test.MVC4.Repository.StudentDataContext;
return await ctx.Students.ToList();
}
I get that Task<IEnumerable<Student>> is not awaitable. I was under the impression that Tasks are awaitable.
Updated: What about something like this (assuming the EF code has been abstracted to the .Select method?
public async Task<ActionResult> Index()
{
var s = await SelectAsync();
return View(s);
}
private async Task<IEnumerable<Student>> SelectAsync()
{
return _repo.Select();
}
Or do I also need to use Task.Run inside the SelectAsync method as well? I'm used to doing this sort of thing in client-side so I appreciate the help here with these methods...
You are calling awaiton ctx.Students.ToList(). This method (ToList()) does not return a Task and therefor is not awaitable.

Categories

Resources