How to wrap a synchronous function to async function in C#? [duplicate] - c#

This question already has an answer here:
Awaiting a Callback method
(1 answer)
Closed 1 year ago.
am using a synchronous 3rd function which I cannot modify, such as:
public void startDoSth(Action<string> onDone)
startDoSth spawn a new thread to do the job, and returns immediately, and when the thing is done, my onDone function would be called.
I'd like to write an asynchronous method like below to wrap it:
public async Task<string> doSthAsync();
So, someone can call it like this:
string s = await doSthAsync()
onDone(s)
In doSthasync() I call startDoSth() to do the real thing.
But I have no idea how to write the doSthAsync().
Could anyone tell if it is possible and how to do it? Thanks a lot.

You can use TaskCompletionSource to convert that into TAP:
Task<string> DoSthAsync()
{
var tcs = new TaskCompletionSource<string>();
startDoSth(tcs.SetResult);
return tcs.Task;
}
SetResult completes the returned Task (and sets the result), so that can be passed as the callback function.

Related

UI Received task got cancelled [duplicate]

This question already has answers here:
'await' works, but calling task.Result hangs/deadlocks
(6 answers)
Closed 3 years ago.
In my application, I am trying to update the user profile which calls the Rest API. API has one sync method UpdateProfile where execution getting stuck.
this line of code is ending the execution
command.UserProfile.LookupItems = GetLookupItemsByUserId(existingUser.Id).Result;
When i changed this line of code to
command.UserProfile.LookupItems = Task.Run(async () => await GetLookupItemsByUserId(existingUser.Id)).Result;
It started working without any issue.Can anybody explain to me what is going on behind the scene?
The first version is blocking the current thread, when the task complete the blocked thread cannot catch it.
YourType Signature() {
var neverUsedValue = task.Result;
}
The second one is yielding the current "thread" until the task is returned.
YourType Signature() {
var value = Task.Run(await => async MethodThatWillComplete()).Result
}
What you should do is propagate the async to the method:
async Task<YourType> SignatureAsync() {
command.UserProfile.LookupItems = await GetLookupItemsByUserId(existingUser.Id);
}
In this way you will avoid handling the AggregateException.
There is very well written article on this here:Don't block async
In a few words, blocking on async code is bad because it may be blocking the thread which is supposed to run the async code and thus generete a deadlock.

Sync call in c#

I have Following API Call in c# and I want to make it Synchronous and it should wait till it comes backs from other modules where delete logic is performed.
I belive the following code is your problem: CallExternalServiceAsync(..)
It should return a task, which you can await if you declare your function async. Otherwise, if you are just interested in waiting, you may call CallExternalServiceAsync(...).Wait(), assuming that it returns a Task.
As stated on comments, you might return a Task instead a void and perform the call of the CallExternalServiceAsync method with the await, assuming it's awaitable.
public async Task CallDeleteOrderApi()
{
var responseMsg = await CallExternalServiceAsync(_apiPath, _validatePath, requestHeader);
}
Have a look at this question which explains how and why using async Task.
Basically, just specify async void return on method declaration when it's on an Event (for example frm_Load on WinForms). On custom methods, always declare it as async Task if you would just return a void (which is actually returning a Task) and async Task<int> if you, for example, want to return an int.

How to create an awaitable method properly

I am writing some awaitable methods and I found a lot of way to do so on the internet. So I came here to know what is really happening on each way, and if some ways must be banished.
As far as I know, there is two kind of awaitable methods:
Those which call other awaitable methods :
public async Task<Foo> GetFooAsync()
{
var foo = await TrulyGetFooAsync();
// Do stuff with foo
return foo;
}
I did not find any other way to do this and I think it is the right way. Tell me if I am wrong !
Those which only call non-awaitable methods :
And here the problems come in my mind.
For example, I saw this:
Exemple 1
public async Task<Foo> GetFooAsync()
{
return await Task.Run(() => TrulyGetFoo());
}
As far as I understand, the async/await keywords are useless and can be avoided to give this:
Exemple 2
public Task<Foo> GetFooAsync()
{
return Task.Run(() => TrulyGetFoo());
}
This last example is what I was doing until now. About that, is there a difference between:
Task.Run(() => TrulyGetFoo());
and
Task.Run((Foo)TrulyGetFoo); // I don't know if the cast is required at any time but in my code, it was
???
But I recently found this way:
Exemple 3
public Task<Foo> GetFooAsync()
{
TaskCompletionSource<Foo> tcs = new TaskCompletionSource<Foo>();
tcs.SetResult(TrulyGetFoo());
return tcs.Task;
}
If I understood properly, an awaitable method does not always run on another thread ??? My guess is the third example is providing this mecanism (but how ??? I only see synchronous code in the third example), when the examples 1 and 2 will always run on a worker thread ???
May be there is still another ways to write awaitable methods, so let me know about them.
For example, I saw [Task.Run wrappers around synchronous code]
This is a bad practice. I have a blog post that explains why Task.Run should not be used as a method implementation.
As far as I understand, the async/await keywords are useless and can be avoided
Yes, but I don't recommend eliding async/await in more complex methods.
I recently found [TaskCompletionSource<T>]
As noted in the comments, your code example is still synchronous.
To make it asynchronous, your code should start some operation and return TaskCompletionSource<T>.Task. Then later, whenever that operation completes, your completion handler should call TaskCompletionSource<T>.SetResult (or similar method). For an example, see TAP wrappers for EAP or TAP wrappers for WaitHandles.
TaskFactory.FromAsync is also a wrapper around TaskCompletionSource<T>, and is used for TAP wrappers for APM.
The short version is this: anything that returns a Task can be awaited inside an async code block.
public async Task MyAsyncMethod()
{
// do some stuff
await TrulyAsyncFoo();
// do some other stuff
return;
}
If awaiting the async call is the only thing the method does, you can simply return the task itself, which will be awaited "upstream":
public Task MyAsyncMethod()
{
return TrulyAsyncFoo();
}
As far as calling synchronous (non-async) code in an async method, there's nothing to it. Just call it like normal code:
public async Task MyAsyncMethod()
{
MySyncMethod();
await TrulyAsyncFoo();
MyOtherSyncMethod();
}
Doing Task.Run(() => Foo()) is almost always a code smell that you aren't doing async/await right. Writing async code is not the same thing as writing multithreaded code. Async is just a nice way of telling the compiler that you need to wait for some network- or IO-bound task to complete.
To sum up:
Await lets you write asynchronous and synchronous code side-by-side
Async should only be used to wait for network- or IO-bound tasks, not compute-bound tasks
Async methods should always return Task or Task<T>
Avoid async void
Avoid blocking using task.Wait() and task.Result in ASP.NET and other threaded applications unless you know what you are doing
I am using this for async events that manipulate my DB
private async void btnSave_Click(object sender, EventArgs e)
{
success = await someClass.someMethod(some args);
}
and the someMethod is a task like that:
public static async Task<someObject> someMethod(args)
{
//do something here
}

Asynchronous calls with await [duplicate]

This question already has answers here:
How Async and Await works
(4 answers)
Closed 7 years ago.
I have one question about await keyword. Here is some test code:
string username = await GetUsernameAsync();
// Some other code
var some_variable = username;
My question is: Does waiting starts at first line where we called async method or at the third line where we need the result of async method? Does some other code executes after GetUsernameAsync finishes its execution, or they are executing in parallel?
It happens at the line where the await is.
If you want to delay the waiting, move the await to the moment you need the result. Remember the task, and move on. Then if you need the result, await the task:
Task<string> usernameTask = GetUsernameAsync();
// Some other code
var some_variable = await usernameTask;
The first one. Take into account the await is just sugar syntax. It will be, more or less, replaced by a Task.Wait() to obtain the result. In fact, GetUsernameAsync() will return a Task, not a string.
Take a look to this link to deep more how threads work with the asyn/await pattern

Can I make a method that returns Task<T> to run synchronously?

Consider this rather simple method:
private bool ValidateKey(HttpRequestMessage message)
{
}
The above method is called as follows
if (!ValidateKey(request))
{
//do something
}
Now I want to call a method inside ValidateKey which returns Task. Let's assume it is the ReadAsStringAsync method in HttpRequestMessage:
message.Content.ReadAsStringAsync();
Now since this method can run asynchronously I should ideally call it like this:
string output = await message.Content.ReadAsStringAsync();
But this will require me to change my method signature to include async and the return type to Task and then the caller too... ad infinitum.
It is possible to call ReadAsStringAsync synchronously, i.e, I am willing to have ValidateKey wait till ReadAsStringAsync completes. This will save me the trouble of changing the code just to cater to this one method.
No. If the operation is inherently asynchronous you can't run it synchronously. You can however block the thread and wait for it to complete.
I would highly advise against doing that though. You should make your operation async all the way or don't bother using an async operation at all.
You can also use AsyncContext by Stephen Cleary:
string output = AsyncContext.Run(() => message.Content.ReadAsStringAsync());
If you still plan on blocking then use GetAwaiter().GetResult() as it's closer in exception handling to what await would do:
string output = message.Content.ReadAsStringAsync().GetAwaiter().GetResult();
Initial (wrong) answer part (I will leave it here for future reference)
You can use Task.RunSynchronously to make the task run synchronously, while technically it is still asynchronous, but you block the current execution, so it is sort of synchronous:
Task<string> t = message.Content.ReadAsStringAsync();
t.RunSynchronously();
string result = t.Result;
This only works if your method returns a new Task (since you can only call Run once), so this won't work when the method is declared async...
Solution
Just simply wait for the result, in a synchronous way. This will block the execution.
Task<string> t = message.Content.ReadAsStringAsync();
string result = t.Result;
ReadAsStringAsync() returns a Task<string> so, in order to wait (block) for the result you just need to get the Result property:
var task = message.Content.ReadAsStringAsync();
string output = task.Result;

Categories