4

We have a Restful Client-Sever environment and I am trying to debug my code where client code looks like following:

await Client.DoWork(Id);

While server code looks like following:

 public virtual async Task<IActionResult> DoWork(long Id)
 {
     return Ok();
 }

Please note that the client is a webclient for the service which is auto-generated from https://github.com/swagger-api/swagger-codegen code.

The point in auto-generated code that it never comes back looks like like below:

var response_ = await client_.SendAsync(request_,
    System.Net.Http.HttpCompletionOption.ResponseHeadersRead,
    cancellationToken).ConfigureAwait(false);

This is where the control is gone

  • One thing which may or may not be helpful here is that the service calls are going through a proxy. Not sure if that changes anything

When Client call the API I can see it goes to Return OK() and I see in Fiddler that it did return 200OK but control never comes back to calling method. How can I solve this?

Andrii Litvinov
  • 12,402
  • 3
  • 52
  • 59
Lost
  • 12,007
  • 32
  • 121
  • 193
  • 3
    That usually means deadlock. It's nature depends on environment. For example your client might be UI application (like WPF or win forms) or asp.net application, and you do something like Task.Wait or Tadk.Result somewhere up the stack. – Evk May 17 '17 at 18:23
  • 1
    It's a webClient and we are using swagger with `ConfigureAwait(false)`. I thought that it should be suffice. – Lost May 17 '17 at 18:26
  • If you call that from asp.net application - the above still applies. Hard to tell more without more code and information (what exactly is client, how it calls api, what is inside that Client.DoWork and so on). – Evk May 17 '17 at 18:33
  • Ok for the simplicity's sake I changed my DoWork() code to do only one thing that is to return OK(). It still does not return to the client. Our client is a swaggerWebClient which is auto generated using `https://github.com/swagger-api/swagger-codegen`. If you would like I can also post auto-generated code from the client – Lost May 17 '17 at 18:49
  • 3
    Deadlock is on client, not on server, so only client code is relevant. It is still not clear what client application is. I understand that you generated api code with swagger but from which *application* do you use that api? – Evk May 17 '17 at 18:54
  • I just updated question with auto-generated client code for the method. Client is a windows Client which is using Swagger-Client – Lost May 17 '17 at 19:10
  • What makes you think that the control never returns? What if you set a breakpoint on a very next line after `await Client.DoWork(Id);`? – Andrii Litvinov May 19 '17 at 18:06
  • Yes, I do have a break-point at the very next line and it never hits that next line.. – Lost May 19 '17 at 18:07
  • What if you try to call the API with HttpClient directly? What if you try to do it from console app, not winforms or what you are using now? – Andrii Litvinov May 19 '17 at 18:09
  • Also, I just edited my question to add the details that all the calls are going through a `proxy` don't know if that is a helpful detail – Lost May 19 '17 at 18:10
  • @AndriiLitvinov It is an HttpClient and it is a Console application – Lost May 19 '17 at 18:11
  • 3
    As @Evk mentioned, the server code isn't relevant especially if you can see in Fiddler that the response is coming back. It's something in the client. Just because the `SendAsync` line has `ConfigureAwait(false)` doesn't mean the rest of the stack is good. The common culprit is a `.Wait()` somewhere below or above the line you're looking at. – Nate Barbettini May 19 '17 at 18:12
  • In other words, make sure it's async all the way down, and nowhere in your code are you blocking synchronously. Maybe something isn't implemented with best practices in the auto-generated code? – Nate Barbettini May 19 '17 at 18:13
  • I don't see how deadlock can be caused in console app. There is no sync context. I know the autogen client is using HttpClient, I am suggesting you to try making a call directly with HttpClient to see if it works without code gen client. – Andrii Litvinov May 19 '17 at 18:15
  • Ok guys. Thank you for your comments. Now I found what works for me.There was a calling Console Application which initiates the Dll that contains web Client. Now, interesting part is the call is inside the Main() method which cannot be async and it I cannot put await there. However, at the end of method call putting `wait()`. solved the problem. The funny thing is that its quite opposite to what we originally thought. We thought wait() is a problem but in this case it is the solution. I think a nice explanation would be nice as an answer.. – Lost May 19 '17 at 18:46

1 Answers1

4

You already found that adding .Wait() to your async method in console application solves the problem. Here is a good answer on How Async and Await works. And the article mentioned in the answer Async and Await.

When the await operator is passed an incomplete task ... then by default await will capture the current context and return an incomplete task from the method.

So basically when client start async communication with server method returns incomplete task. And because it is not awaited in Main method console application exits before client gets response from the server.

There is no SynchronizationContext in console application so it is safe to use .Wait() method or .Result property to block thread in Main method until async operation completes.

Community
  • 1
  • 1
Andrii Litvinov
  • 12,402
  • 3
  • 52
  • 59