C
C#3w ago
Wrenpo

Safely getting a result from a async method within a sync method

I have an async method that returns a response object. In the calling sync method, what is the best way to get the result and capture any possible exceptions?
public static Task<ResponseObj> AsyncMethod()
{
// ... does stuff
return responseObj;
}

public void SyncMethod()
{
// ... does stuff;
// How to handle this safely?
var response = AsyncMethod();
}
public static Task<ResponseObj> AsyncMethod()
{
// ... does stuff
return responseObj;
}

public void SyncMethod()
{
// ... does stuff;
// How to handle this safely?
var response = AsyncMethod();
}
17 Replies
Omnissiah
Omnissiah3w ago
afaik there is always the possibility of screwing up (ergo deadlock) when using sync over async, and there is no real solution
SleepWellPupper
Async functions are infectious, so there is a solution: make your synchronous function async as well. The other poster is partially correct with the deadlock danger. Depending on how your sync method is called, you run the risk of a deadlock if you synchronously (blocking) await the task. So if you see ai or other peopls reccommend things like AsyncMethod().Result, safely disregard that and try to make the calling method async instead, so you may properly await the task.
Omnissiah
Omnissiah3w ago
wrapping the AsyncMethod in a Task.Run could be less dangerous than a direct .Result/.Wait(); if you can describe what is the general architecture of your software maybe someone can come up with a better advice
SleepWellPupper
The best advice in most cases is to make your calling method async. See here : https://blog.stephencleary.com/2012/07/dont-block-on-async-code.html for an explanatikn
Don't Block on Async Code
This is a problem that is brought up repeatedly on the forums and Stack Overflow. I think it’s the most-asked question by async newcomers once they’ve learned the basics.
FusedQyou
FusedQyou3w ago
Using async void puts in a massive risk of breaking your application when there's an uncaught exception. Please wrap code in a try-catch if you really want to do that Assuming that method doesn't return a response, you could make it async void. If it does return a response, then the parent method above that might also have to be async But this is a lot of code, and there's one thing you could consider: If this method runs once and not in parallel, then you could also just make AsyncMethod fully synchronous and just have it block the main thread for a period People often suggest to make everything async, but often code is simply too synchronous. In this case you might just want to block the thread when there's nothing else that rely on it. This obviously does cause issues when you work with a web api, for example. But making async work in some cases might just not be worth it since you end up calling it synchronously from the root anyway So in this case, if you can make the root truly asynchronous, go ahead and just make everything async. However, if SyncMethod can't be async because it returns a synchronous response and the project in general can handle blocking, then just wait for .Result If it doesn't want a response, then by all means make it async void as long as you handle exceptions What you can also do is make AsyncMethod async void in a similar manner, and store the response in a class-scoped field/property Then you can have some other method use the result when it exists, either by having AsyncMethod call a method when it is done, or by keeping AsyncMethod a Task and using ContinueWith If you want my 2 cents, then use ContinueWith
SleepWellPupper
make it async void
There is absolutely no need for this in the code OP shared; this is genuinely bad advice. Unless you are writing event handlers for a UI framework dictating a void returning handler, you should not use async void.
FusedQyou
FusedQyou3w ago
Have you read the rest of my message? I doubt you have Also async void is not bad advice, it's just risky if not handled correctly The answer here depends entirely on context and whether or not a result is being awaited for. async void is one of many solutions
SleepWellPupper
Why use async void (risky) over async Task (not risky)? I'd ask you kindly not to assume what I read please. I did read your message but none of what OP presented requires async void. If they want to synchronously block await on a task, then .Result will do (caveats like deadlock risks apply, of course), if they don`t, then just throw away the task.
FusedQyou
FusedQyou3w ago
This makes literally no difference when the parent method remains synchronous At best you discard the task and end up with the same behaviour Now to repeat my first message: Please wrap code in a try-catch if you intend to call an async method from a synchronous method. This way you ensure you don't leave uncaught dangling exceptions that put a massive risk of breaking your application. This article also specifically mentions the usefulness of Tasks when you must await a result. Unless it's async void. You don't have to wait for the result of a method that you don't care about. You can fire-and-forget the method, as long as you properly handle any exceptions that happen. But anyway, it doesn't really matter here. OP needs a response object so the best way is to either block the response or use the Task ContinueWith method, which I specifically also pointed out as a better solution
SleepWellPupper
Op specified
capture any possible exceptions
async void does not do that, async Task does. There is no relevant upside to using async void over async Task for this. ContinueWith might as well be implemented using async/await
FusedQyou
FusedQyou3w ago
async void does not do that, async Task does. There is no relevant upside to using async void over async Task for this.
Yes, I know, that's why I specifically mentioned that it doesn't matter here since they are waiting for a response
ContinueWith might as well be implemented using async/await
Again, you don't know that. If the method itself is required to be synchronous and it's not possible to just block a thread like that, then you can't use .Result or refactor the parent to be async
The answer here depends entirely on context
SleepWellPupper
This I agree with.
FusedQyou
FusedQyou3w ago
I simply listed all possibilities on what OP might use in this situation, making sure that they are aware why you would use one over the other
SleepWellPupper
I'd like to know why the method needs to be synchronous @Wrenpo
Wrenpo
WrenpoOP3w ago
Sorry, was busy at work and didn't get back to this. Thank you for all the responses! I am aware of the deadlocking possibilities and have read up on some of Stephen Cleary's articles about this including his SO answers to similar questions. I have since converted my async method into a synchronous one. I am running into a situation now where the remote server is closing the request early. I am working with Azure AD B2C and .NET Framwork 4.8. Inside our middleware (OWIN), a synchronous method is establishing the initial connection with Azure AD B2C to identify a user and allow them into the app. However, what this does not handle is giving back the refresh token. It was assumed that it did this automatically. It does not. It disposes it and does not store it anywhere. So, I have been manually trying to do this from what was originally my async method. I can take my authorization code that I get from B2C and with a request body, send a GET over to the token endpoint on Postman and get what I want. I am going a bit crazy trying to get this working from the app.
Omnissiah
Omnissiah3w ago
good luck i guess
Want results from more Discord servers?
Add your server