1
public async static Task<string> GetResponse(string host, string request, HttpClient client)
{
    HttpContent content = new StringContent(request, Encoding.UTF8, "application/xml");
    HttpResponseMessage message = await client.PostAsync(host, content).ConfigureAwait(false);  // issue here
    string response = await message.Content.ReadAsStringAsync().ConfigureAwait(false);
    return response;
}

The calling code within the same namespace -

public async Task<string> Post(Transaction transaction)
{
    string postXml = PostXml.Create(transaction); // serializes object to XML
    string response = await GetResponse(host, postXml, client); // client initialized in constructor of this class
    return await Deserialize.Response(response);
}

The above methods run as expected when calling them directly from Unit Tests.

I have an interface to take advantage of dynamic loading of different services - which calls the Task<string> Post(Transaction transaction) method. When calling this method from my main project - the relevant service is loaded (depending on settings), but I get no response from client.PostAsync(host, content).

No exception or errors. I have tried to debug the issue with breakpoints but got nothing. It hits the PostAsync and continuing just escapes the rest of the code.

Note 1: everything is async all the way through and there is no thread blocking code such as .Wait() or .Result anywhere

Note 2: i have tried running it by removing the ConfigureAwait as well. In both cases, the unit tests run perfectly. Somehow it doesnt work when i reference this project in my main project. I still dont understand, cause I still reach that part of the code. Beyond which, the program still runs without blocking the UI thread but there is no response.



UPDATE

To get the host, I was reading a configuration json file. Reading this file caused the issue I am facing, when I hardcode the host to a variable, everything works fine. Initially the reading of this file was Asynchronous, but to debug the issue I changed it to synchronized reading - this still did not resolve the issue.

NOTE - Using the App.Config works well.

I am using newtonsoft to read a custom json settings file. I am not a big fan of reading configuration from the app.config due to its XML structure and complex way of accessing custom section.

public static ServerConfig GetServerSettings()
{
    string json = File.ReadAllText("appSettings.json");
    return JsonConvert.DeserializeObject<ServerConfig>(json);
}

ServerConfig has properties namely the string host and string company (i.e. which company's data) I want to access.

Bandook
  • 658
  • 6
  • 21
  • Have you already tried removing ConfigureAwait(false) if it will work or not on the line where it has an issue? – tontonsevilla Aug 09 '20 at 10:49
  • 2
    Not related; but I see you create HttpClient in each call. Best practice and the recommended usage is reusing the HttpClient. Please check: https://learn.microsoft.com/en-us/aspnet/web-api/overview/advanced/calling-a-web-api-from-a-net-client#create-and-initialize-httpclient – Safak Ulusoy Aug 09 '20 at 11:26
  • @tontonsevilla yes i have tried that and i am still having the same issue. – Bandook Aug 09 '20 at 12:31
  • @TheodorZoulias actually i didnt have a try-catch. its cause of this issue i tried several things and this was the last thing i tried before copy-pasting it into SO – Bandook Aug 09 '20 at 12:37
  • @SafakUlusoy thats a good point. Im trying to change my current design pattern as per your suggestion. Though i am not sure if this will solve my issue but i understand this is good practice. – Bandook Aug 09 '20 at 12:57
  • 1
    @Bandook basically, if possible you can declare and initialize a static HttpClient property in the same class; and then use this in your method. I assumed you don't make us of DI/IoC and you don't want to convert your static class/method to a non-static version. I would rather inject HttpClient via constructor, and create/register my helper class and HttpClient as singleton (via DI container) and use it like that. – Safak Ulusoy Aug 09 '20 at 12:59
  • @SafakUlusoy yes just finished doing that though i am not using IoC. but i guess i should consider using it as i am already using Prism.DryIoC for WPF. Currently it still hasn't solved the issue. I believe it has an issue getting back on the thread/context, when being called from outside. Which is why my Unit Tests are running but not the project that refers this library. – Bandook Aug 09 '20 at 13:06
  • Have you tried to call the `GetResponse` method directly from an async event handler of your WPF application (on the click event of a button for example), and display the results in a message box or something, while running the application without the debugger attached? (Ctrl + F5) – Theodor Zoulias Aug 09 '20 at 16:23
  • @Bandook: How exactly do you call the `GetResponse` when it fails? You should provide a [minimal repo](https://stackoverflow.com/help/minimal-reproducible-example) of your issue. – mm8 Aug 10 '20 at 15:17
  • Sorry, I dont understand your question @mm8 I call the GetResonse as shown in the second code snippet seen in my question. – Bandook Aug 12 '20 at 07:27
  • I am having this exact issue. The XML post silently fails. Cannot find a solution for hours – pnizzle Sep 03 '22 at 12:18

1 Answers1

0

Within WPF/WinForm and (old) ASP.NET you MUST use CongigureAwait(true).
Put it simple ConfigureAwait:

  • True: After the async code finish it return to the original thread, on Win/WPF application this is necessary because only the main thread can alter the GUI.
  • False: After the async code finish not necessary return to the original thread.

More info MSDN Magazine

Max
  • 6,821
  • 3
  • 43
  • 59
  • This is inside a library. Also i have tried it with configureawait and im still having the same issue. – Bandook Aug 09 '20 at 12:31
  • 1
    `true` is useless redundancy unless you want to change `ConfigureAwait` behavior at runtime. Better not to use `ConfugureAwait` then. – aepot Aug 09 '20 at 13:44
  • yes thats what i meant. removed ConfigureAwait entirely, same issue. – Bandook Aug 09 '20 at 13:48