How can I call an async method within a sync method? - c#

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

Related

c# Task.WhenAll to block while awaiting completion

I have a simple Winforms application. I would like to background TCP connections/print requests and check the output of all tasks at a set point in my code.
I would expect ReportOnTasks to block until WaitAll is complete. Please could someone explain why this is not the case? I'm also worried I haven't structured this correctly.
Edit, to clarify my intentions:
I would like to send the print jobs as soon as I receive the data. Then continue with some other DB operations. Once all the print operations are complete, I would like to update the UI to state the result.
I've attempted to simplify the code as much as I can. Maybe too much. HomeController just inits some stuff. There are buttons on the form and file watchers that trigger the main functionality.
public class HomeController
{
public HomeController(){
MessageBox.Show("1");
oPrintController.PrintAsync("192.168.2.213", Encoding.ASCII.GetBytes("string to print"));
MessageBox.Show("2");
// Block here untill tasks are complete
ReportOnTasks();
MessageBox.Show("Report on tasks complete");
}
public async void ReportOnTasks()
{
await Task.WhenAll(oPrintController.Tasks);
foreach(Task<PrintController.PrintResult> PR in oPrintController.Tasks)
{
// do something with the result of task
}
}
}
and the PrintController
public class PrintController
{
public List<Task<PrintResult>> Tasks = new List<Task<PrintResult>>();
public async void PrintAsync(string sIP, List<byte[]> lsToPrint, int iPort = 9100)
{
var s = await Task.Run(() => PrintAsync1(sIP, lsToPrint));
}
public async System.Threading.Tasks.Task<PrintResult> PrintAsync1(string sIP, List<byte[]> lsToPrint, int iPort = 9100)
{
using (TcpClient tc = new TcpClient())
{
await tc.ConnectAsync(sIP, iPort);
using (var ns = tc.GetStream())
{
foreach (byte[] btLabel in lsToPrint)
{
await ns.WriteAsync(btLabel, 0, btLabel.Length);
}
}
}
Thread.Sleep(10000);
return new PrintResult();
}
}
public class PrintResult
{
bool bSuccess = false;
}
You are not awaiting the call to ReportOnTasks()
Moreover, you can't await within a ctor, because they can't be async.
Depending on how your HomeController is used, you could use a static async method which returns an instance of HomeController, created by a private ctor instead:
Something like this:
public class HomeController
{
//notice private - you can't new up a HomeController - you have to use `CreateInstance`
private HomeController(){
MessageBox.Show("1");
//not clear from your code where oPrintController comes from??
oPrintController.PrintAsync("192.168.2.213", Encoding.ASCII.GetBytes("string to print"));
MessageBox.Show("2");
MessageBox.Show("Report on tasks complete");
}
public static async Task<HomeController> CreateInstance() {
var homeController = new HomeController();
await homeController.ReportOnTasks();
return homeController;
}
//don't use async void! Change to Task
public async Task ReportOnTasks()
{
//not clear from your code where oPrintController comes from??
await Task.WhenAll(oPrintController.Tasks);
foreach(Task<PrintController.PrintResult> PR in oPrintController.Tasks)
{
// do something with the result of task
}
}
}
Usage:
var homeControllerInstance = await HomeController.CreateInstance();
It's generally not recommended to perform heavy operations in class constructors, but I suppose you won't change that part, so in order to wait for ReportOnTasks to finish, you need to make it synchronous.
Take into account, that constructor itself doesn't support async/await, it's not possible to mark it async.
Having said that, you won't have real performance enhancement marking void ReportOnTasks as async. In addition, it is not recommended to mark void methods as async due to issues with exceptions handling, which is usually not possible.
So, you can either postpone ReportOnTasks like Alex showed you, or you can synchronously wait until all tasks are finished (which is possible inside ctor).
public void ReportOnTasks()
{
Task.WhenAll(oPrintController.Tasks).GetAwaiter().GetResult(); //synchronously wait
foreach(Task<PrintController.PrintResult> PR in oPrintController.Tasks)
{
// do something with the result of task
}
}
However, I wouldn't suggest this approach, because instance creation will take a while and most importantly block UI thread - and that's usually signal something is really fishy

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.

await Task.Delay(2000) is not completed In Winform [duplicate]

I have the following four tests and the last one hangs when I run it. Why does this happen:
[Test]
public void CheckOnceResultTest()
{
Assert.IsTrue(CheckStatus().Result);
}
[Test]
public async void CheckOnceAwaitTest()
{
Assert.IsTrue(await CheckStatus());
}
[Test]
public async void CheckStatusTwiceAwaitTest()
{
Assert.IsTrue(await CheckStatus());
Assert.IsTrue(await CheckStatus());
}
[Test]
public async void CheckStatusTwiceResultTest()
{
Assert.IsTrue(CheckStatus().Result); // This hangs
Assert.IsTrue(await CheckStatus());
}
private async Task<bool> CheckStatus()
{
var restClient = new RestClient(#"https://api.test.nordnet.se/next/1");
Task<IRestResponse<DummyServiceStatus>> restResponse = restClient.ExecuteTaskAsync<DummyServiceStatus>(new RestRequest(Method.GET));
IRestResponse<DummyServiceStatus> response = await restResponse;
return response.Data.SystemRunning;
}
I use this extension method for restsharp RestClient:
public static class RestClientExt
{
public static Task<IRestResponse<T>> ExecuteTaskAsync<T>(this RestClient client, IRestRequest request) where T : new()
{
var tcs = new TaskCompletionSource<IRestResponse<T>>();
RestRequestAsyncHandle asyncHandle = client.ExecuteAsync<T>(request, tcs.SetResult);
return tcs.Task;
}
}
public class DummyServiceStatus
{
public string Message { get; set; }
public bool ValidVersion { get; set; }
public bool SystemRunning { get; set; }
public bool SkipPhrase { get; set; }
public long Timestamp { get; set; }
}
Why does the last test hang?
Acquiring a value via an async method:
var result = Task.Run(() => asyncGetValue()).Result;
Syncronously calling an async method
Task.Run( () => asyncMethod()).Wait();
No deadlock issues will occur due to the use of Task.Run.
You're running into the standard deadlock situation that I describe on my blog and in an MSDN article: the async method is attempting to schedule its continuation onto a thread that is being blocked by the call to Result.
In this case, your SynchronizationContext is the one used by NUnit to execute async void test methods. I would try using async Task test methods instead.
You can avoid deadlock adding ConfigureAwait(false) to this line:
IRestResponse<DummyServiceStatus> response = await restResponse;
=>
IRestResponse<DummyServiceStatus> response = await restResponse.ConfigureAwait(false);
I've described this pitfall in my blog post Pitfalls of async/await
You are blocking the UI by using Task.Result property.
In MSDN Documentation they have clearly mentioned that,
"The Result property is a blocking property. If you try to access it
before its task is finished, the thread that's currently active is
blocked until the task completes and the value is available. In most
cases, you should access the value by using Await or await instead of
accessing the property directly."
The best solution for this scenario would be to remove both await & async from methods & use only Task where you're returning result. It won't mess your execution sequence.
An addition to the answer given by #HermanSchoenfeld. Unfortunately the quote below is not true:
No deadlock issues will occur due to the use of Task.Run.
public String GetSqlConnString(RubrikkUser user, RubrikkDb db)
{
// deadlock if called from threadpool,
// works fine on UI thread, works fine from console main
return Task.Run(() =>
GetSqlConnStringAsync(user, db)).Result;
}
The execution is wrapped inside a Task.Run, this will schedule the task on the threadpool the block the calling thread. This is okay, as long as the calling thread is not a threadpool thread. If the calling thread is from the threadpool then the following disaster happens: A new task is queued to the end of the queue, and the threadpool thread which would eventually execute the Task is blocked until the Task is executed.
In library code there is no easy solution as you cannot assume under what context your code is called. The best solution is to only call async code from async code, blocking sync APIs from sync methods, don’t mix them.
Source:
https://medium.com/rubrikkgroup/understanding-async-avoiding-deadlocks-e41f8f2c6f5d
If you don't get any callbacks or the control hangs up, after calling the service/API async function, you have to configure Context to return a result on the same called context.
Use TestAsync().ConfigureAwait(continueOnCapturedContext: false);
You will be facing this issue only in web applications, but not in static void main.

Deadlock using FileOpenPicler when unit testing UWP [duplicate]

I have the following four tests and the last one hangs when I run it. Why does this happen:
[Test]
public void CheckOnceResultTest()
{
Assert.IsTrue(CheckStatus().Result);
}
[Test]
public async void CheckOnceAwaitTest()
{
Assert.IsTrue(await CheckStatus());
}
[Test]
public async void CheckStatusTwiceAwaitTest()
{
Assert.IsTrue(await CheckStatus());
Assert.IsTrue(await CheckStatus());
}
[Test]
public async void CheckStatusTwiceResultTest()
{
Assert.IsTrue(CheckStatus().Result); // This hangs
Assert.IsTrue(await CheckStatus());
}
private async Task<bool> CheckStatus()
{
var restClient = new RestClient(#"https://api.test.nordnet.se/next/1");
Task<IRestResponse<DummyServiceStatus>> restResponse = restClient.ExecuteTaskAsync<DummyServiceStatus>(new RestRequest(Method.GET));
IRestResponse<DummyServiceStatus> response = await restResponse;
return response.Data.SystemRunning;
}
I use this extension method for restsharp RestClient:
public static class RestClientExt
{
public static Task<IRestResponse<T>> ExecuteTaskAsync<T>(this RestClient client, IRestRequest request) where T : new()
{
var tcs = new TaskCompletionSource<IRestResponse<T>>();
RestRequestAsyncHandle asyncHandle = client.ExecuteAsync<T>(request, tcs.SetResult);
return tcs.Task;
}
}
public class DummyServiceStatus
{
public string Message { get; set; }
public bool ValidVersion { get; set; }
public bool SystemRunning { get; set; }
public bool SkipPhrase { get; set; }
public long Timestamp { get; set; }
}
Why does the last test hang?
Acquiring a value via an async method:
var result = Task.Run(() => asyncGetValue()).Result;
Syncronously calling an async method
Task.Run( () => asyncMethod()).Wait();
No deadlock issues will occur due to the use of Task.Run.
You're running into the standard deadlock situation that I describe on my blog and in an MSDN article: the async method is attempting to schedule its continuation onto a thread that is being blocked by the call to Result.
In this case, your SynchronizationContext is the one used by NUnit to execute async void test methods. I would try using async Task test methods instead.
You can avoid deadlock adding ConfigureAwait(false) to this line:
IRestResponse<DummyServiceStatus> response = await restResponse;
=>
IRestResponse<DummyServiceStatus> response = await restResponse.ConfigureAwait(false);
I've described this pitfall in my blog post Pitfalls of async/await
You are blocking the UI by using Task.Result property.
In MSDN Documentation they have clearly mentioned that,
"The Result property is a blocking property. If you try to access it
before its task is finished, the thread that's currently active is
blocked until the task completes and the value is available. In most
cases, you should access the value by using Await or await instead of
accessing the property directly."
The best solution for this scenario would be to remove both await & async from methods & use only Task where you're returning result. It won't mess your execution sequence.
An addition to the answer given by #HermanSchoenfeld. Unfortunately the quote below is not true:
No deadlock issues will occur due to the use of Task.Run.
public String GetSqlConnString(RubrikkUser user, RubrikkDb db)
{
// deadlock if called from threadpool,
// works fine on UI thread, works fine from console main
return Task.Run(() =>
GetSqlConnStringAsync(user, db)).Result;
}
The execution is wrapped inside a Task.Run, this will schedule the task on the threadpool the block the calling thread. This is okay, as long as the calling thread is not a threadpool thread. If the calling thread is from the threadpool then the following disaster happens: A new task is queued to the end of the queue, and the threadpool thread which would eventually execute the Task is blocked until the Task is executed.
In library code there is no easy solution as you cannot assume under what context your code is called. The best solution is to only call async code from async code, blocking sync APIs from sync methods, don’t mix them.
Source:
https://medium.com/rubrikkgroup/understanding-async-avoiding-deadlocks-e41f8f2c6f5d
If you don't get any callbacks or the control hangs up, after calling the service/API async function, you have to configure Context to return a result on the same called context.
Use TestAsync().ConfigureAwait(continueOnCapturedContext: false);
You will be facing this issue only in web applications, but not in static void main.

Async method that throws exception won't resume the thread context back to the same thread

When I am using async await and an exception is thrown the thread context is being lost. In my code I'm using dependency injection that registered to resolve per thread so I need to execute my code on the same thread.
This is how it is setup:
I have a method that will try calling different communicators using async when one throws an exception it will go onto the next one:
public async Task<TResponse> VisitRequestAsync(Context context)
{
/* ....
prepare request from context
.... */
var communicatorEnumerableInstance = _communicatorService.GetCommunicatorInstanceEnumerable();
foreach (var communicator in communicatorEnumerableInstance)
{
using (communicator)
{
var communicatorInstance = communicator as ICommunicator<TResponse, TRequest>;
try
{
return await communicatorInstance.ProcessAsync(request).ConfigureAwait(true);
break;// call will break out of the for-each loop if successful processed.
}
catch (Exception exception)
{
continue;// Continue to load next communication method/instance
}
}
}
}
Below is a unit test that contains a communicator that always throws an exception and one that tries to get a dependency that is registered onto the original thread.
public class TestDependancy : ITestDependancy
{
}
public interface ITestDependancy
{ }
public class TestCommunicatorThrowsException :
ICommunicator<ResponseType, RequestType>
{
public async Task<ResponseType> ProcessAsync(RequestType request)
{
var task = Task.Run(() =>
{
throw new Exception();
return new ResponseType();
});
return await task;
}
public void Dispose()
{
}
}
public class TestCommunicatorGetsDependency :
ICommunicator<ResponseType, RequestType>
{
public TestCommunicatorGetsDependency()
{ }
public async Task<ResponseType> ProcessAsync(RequestType request)
{
TestDependancy = DefaultFactory.Default.Resolve<ITestDependancy>();
var task = Task.Run(() => new ResponseType());
return await task;
}
public ITestDependancy TestDependancy { get; set; }
public void Dispose()
{
}
}
[TestMethod]
[TestCategory("Unit")]
public async Task it_should_be_able_to_resolve_interface_from_original_thread()
{
var secondCommunicator = new TestCommunicatorGetsDependency();
_communicators = new ICommunicator<ResponseType, RequestType>[]
{new TestCommunicatorThrowsException(), secondCommunicator};
_communicatorServiceMock.Setup(
x => x.GetCommunicatorInstanceEnumerable(It.IsAny<string>(), It.IsAny<string>()))
.Returns(_communicators);
((IFactoryRegistrar) DefaultFactory.Default).RegisterPerThread<ITestDependancy, TestDependancy>();
var firstInstance = DefaultFactory.Default.Resolve<ITestDependancy>();
await it.VisitRequestAsync(_context).ConfigureAwait(true);
var secondInstance = secondCommunicator.TestDependancy;
Assert.AreEqual(firstInstance, secondInstance);
}
When the dependencies are resolved in the unit test they are not equal. After looking into it I see that the value for CurrentThread.ManagedThreadId changes at the point when the exception gets thrown. Then when it is caught in the VistRequestAsync method the CurrentThread.ManagedThreadId is never restored to its original state. So then the dependency injection is unable to get the same instance because it is now operating on a different thread.
Originally, I was using .ConfigureAwait(false) with the await. Then I tried setting it to true and I started seeing it sometimes get the same thread back. Which sounds a lot like what is said in this answer.
This post about the synchronization context and async sounds a lot like the problem I am facing. My trouble is I'm using WebApi and need a response back when things get done so I'm not sure how to use his message pump and asynchronously wait for an answer.
Async uses the ThreadPool to process tasks. This means that there is no guarantee that an async operation will start and complete on the same thread.
When a async task is first awaited, the task is put on a work queue. As soon as possible, the task scheduler grabs that task from the queue and assigns it to one of the many available threads.
For more information, see this overview of the structure of the TPL: https://msdn.microsoft.com/en-us/library/dd460717(v=vs.110).aspx.
If you need a context that flows with the thread, look at using something like the logical call context or CallContext.LogicalSetData / LogicalGetData.
But the behavior you're seeing is correct, and as mentioned has nothing to do with whether or not an exception is thrown. You'll see different thread ids at various points of an asynchronous task's scheduling, execution, and completion.

Categories

Resources