2

Some times you have a component, e.g. HttpClient, which offers only asynchronous methods.

That's fine when you can go "all the way up" to an async event handler or an async action method cause to my understanding the execution is returned to the IIS pipeline, for example, that can continue to run other things.

When you cant go "all the way up" you have to do something like .Result at some point.

My case is a windows service hosting a WCF service which uses HttpClient to get some data from an API. My code is in a method bound by an Interface that cannot be changed and makes no sense to be changed because the application manages threads already, directly without tasks.

In that case, is it better to go "all the way up" as much as you can and finally block or block the async method straight away and save the complexity and resources of saving and resuming (awaiting) all the way to the top for what seems like no reason?

Ares
  • 1,356
  • 1
  • 9
  • 22
  • 2
    Why cant you go all the way up? – TheGeneral Oct 05 '18 at 12:18
  • There isn't a single correct answer for this, it would depend on your situation. I have therefore voted to close this as primarily based on opinion. Be sure to read up on how to call async code in a sync method, because `...Wait()` is *probably* not what you want. – Lasse V. Karlsen Oct 05 '18 at 12:18
  • There is no point in wrapping it in a `Task.Run()`. It is the same as `DoSomethingAsync().Wait()` minus a thread. And when you can't go all the way up you usually don't have to. – bommelding Oct 05 '18 at 12:18
  • @bommelding `DoSomethingAsync().Wait()` has the potential to deadlock – TheGeneral Oct 05 '18 at 12:20
  • 2
    @Saruman - yes, but so does `Task.Run(...).Wait()`. My point is that they are equally bad or maybe just equally acceptable. – bommelding Oct 05 '18 at 12:20
  • `await` let it be free... – TheGeneral Oct 05 '18 at 12:22
  • @Saruman Can't go al the way up cause for example I am working with existing code bound to an interface that cannot be changed. – Ares Oct 05 '18 at 12:23
  • And I know that `.Result()` and `.Wait()` are "evil" but there is no other way if you are not async all the way. – Ares Oct 05 '18 at 12:25
  • My general advice - go async all the way if at all possible. If not, you must either block at some point or offload blocking operations to a distributed system like queue processor or separate API, etc. If you are in a context-less environment (console app, asp.net Core) then you will not deadlock but go async as far as you can. In a context aware environment (winforms, aspnet, wpf) you risk deadlock so block inside an isolated function that cannot be awaited (does not return Task). – Crowcoder Oct 05 '18 at 12:27
  • You can just use `Task.Run` to offload with no risk of deadlock. However, see this question https://stackoverflow.com/questions/28305968/use-task-run-in-synchronous-method-to-avoid-deadlock-waiting-on-async-method if you are worried about synchronization context and a less expensive approach, also Stephen Cleary has some great blog posts about async await and task https://blog.stephencleary.com/ – TheGeneral Oct 05 '18 at 12:29
  • @LasseVågsætherKarlsen I am not saying there is a single answer, there may not be. However based on my simple hypothesis and making certain assumptions there may be guide. So in that case this is an answer. If this is definitely not the case can you explain why? – Ares Oct 05 '18 at 13:47
  • @Ares SO is for questions that actually have answers. We also don't want questions that force everyone to make a whole bunch of assumptions about what is *actually* being asked in order to answer it. The site is designed around having questions that can have verifiable correct answers. – Servy Oct 05 '18 at 14:33
  • Sorry to add so much discomfort by this question. Should I delete it? – Ares Oct 05 '18 at 14:40
  • You've got a currently sync method and now it's been handed a `Task`. It cannot continue operating until that `Task` is complete. Now, ask yourself, is your method actually inherently synchronous or asynchronous? It would appear to be an ideal candidate for being asynchronous since it's got that "pause point" where you want to write `await`. So you keep moving up until you hit the point where you "cannot" change the current method. At that point, you write some nasty blocking code, then *raise one or more defect reports* about not being able to supply an async implementation to your callers. – Damien_The_Unbeliever Oct 05 '18 at 14:42
  • @Servy my question is very clear IMHO. – Ares Oct 05 '18 at 15:01
  • @Ares You're the one that said people can't answer it without making assumptions about what it's actually asking. That's not true of questions that are clear. – Servy Oct 05 '18 at 15:02
  • @Ares nothing prevents a *service* or *console* application from using async all the way up. WCF is even easier in a sense. ASP.NET also manages threads in the "old way". Async isn't about *thread* management. It's about releasing the current thread while waiting for an async operation to complete. The *interface* doesn't specify the service protocol. It's the attributes, conventions, operation and data contract classes that do so – Panagiotis Kanavos Oct 05 '18 at 15:14
  • @Ares in short, yes, you can use `async` in a WCF service even if it's not a SOAP service. It *does* make sense to change your methods, as they won't affect the contrats, while allowing you to avoid blocking threads. – Panagiotis Kanavos Oct 05 '18 at 15:16

1 Answers1

0

If you block async operation you can very well get a deadlock. Check this answer https://stackoverflow.com/a/39371523/2138959 and other answers to the question to get move motivation on the topic.

In generic case I'd recommend using AsyncEx.Context.

And here is great article from the author of async in C# Await, SynchronizationContext, and Console Apps: Part 3.

Andrii Litvinov
  • 12,402
  • 3
  • 52
  • 59
  • 1
    "If you block async operation you can very well get a deadlock." That depends on the type of threading context, though. – Kenneth K. Oct 05 '18 at 13:33
  • @KennethK. Indeed, but do you want to write non-portable code in your console applications? As a rule-of-thumb, blocking on a task should be avoided. The whole point of tasks is to avoid blocking. – spender Oct 05 '18 at 14:32
  • @spender Do you port console applications to ASP.NET applications often? Look, writing blocking code in a service or data layer is a bad idea. But if you're at the user layer, then you're probably re-writing that bit anyways if you change front ends. – Kenneth K. Oct 05 '18 at 14:37
  • @KennethK. Agreed, the cross-over between console apps and GUI/Server apps can be slim, but with `async` all the way to the top in console apps now (`public static async Task Main(string[] args){}`) the reasons for blocking are falling away. – spender Oct 05 '18 at 14:43
  • Thanks for AsyncEx.Context. I will have a look. – Ares Oct 05 '18 at 14:53
  • @spender You know that's just syntactic-sugar for blocking on the task, right? It's not truly async. – Kenneth K. Oct 05 '18 at 14:58