Deadlock while logging http requests into main UI C#

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP



Deadlock while logging http requests into main UI C#



In my WinForms app I want to see raw request/response data when it interacts with webApi. I need to show request/response in UI RichTextBoxes. To do this I set up my HttpClient as follows:


private HttpClient client;
private void CreateService()

client = new HttpClient(new LoggingHandler(new HttpClientHandler(), this))

BaseAddress = new Uri(this._URI)
;
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));



My Logging Handler:


public class LoggingHandler : DelegatingHandler

private SimplySignRestClientAsync _client;

public LoggingHandler(HttpMessageHandler innerHandler, SimplySignRestClientAsync client) : base(innerHandler)

this._client = client;


protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)

string p_Request = "";
if (_client._updateRequest != null)

p_Request = request.ToString();
if (request.Content != null)

p_Request += "nnContent:n" + FormatJsonString(await request.Content.ReadAsStringAsync());


//_client._request.Text = p_Request; << this works but causes a cross-thread exception in debug only
SetText(p_Request); << This deadlocks the UI


return response;


delegate void SetTextCallback(string text);

private void SetText(string text)

if (_client._request.InvokeRequired)

SetTextCallback d = new SetTextCallback(SetText);
_client._response.Invoke(d, new object text );

else

_client._request.Text = text;





If i try to access richtextbox directly it works only when i execute app without debugging. But during debug it comes up with cross-thread exception.



This is how I call httpClient:


//This is how the original call gets initiated from UI
private void uiLogin_Click(object sender, EventArgs e)

Agent resp = Client.Login(new Credentials(uiUsername.Text, uiPassword.Text));
uiAuthToken.Text = Client.getAuthToken();


//this method has to stay synchronous, but it in turn calls an async method below
public Agent Login(Credentials loginInfo)

var task = Task.Run(async () => await LoginAsync(loginInfo));
return task.Result.Content; <<< this is where the application stops if i hit pause during debug when deadlock happens


//
async public Task<RestResponse<Agent>> LoginAsync(Credentials loginInfo)

HttpResponseMessage response = await client.PostAsJsonAsync(this._URI + "api/users/login", loginInfo);

var content = await response.Content.ReadAsStringAsync();
RestResponse<Agent> respAgent respAgent = JsonConvert.DeserializeObject<RestResponse<Agent>>(content);

return respAgent;



as I understand my "return task.Result.Content" blocks the UI thread and "_client._response.Invoke(d, new object text );" is waiting for that to unblock causing deadlock. But I'm not sure how to make invoke wait too.





Check this on how to run async code synchronously stackoverflow.com/questions/5095183/…
– cellik
Aug 10 at 15:09




1 Answer
1



If you want to do it using proper asynchronous constructs, you need to make the entry point (your Click event handler) asynchronous, and never block on asynchronous code as it causes the deadlock you are facing.


Click


//This is how the original call gets initiated from UI
private async void uiLogin_Click(object sender, EventArgs e)

Agent resp = await Client.Login(new Credentials(uiUsername.Text, uiPassword.Text));
uiAuthToken.Text = Client.getAuthToken();


public async Task<Agent> Login(Credentials loginInfo)

var result = await LoginAsync(loginInfo);
return result.Content;





Login(Credentials loginInfo) function has to stay synchronous
– AnKing
Aug 10 at 15:03





@AnKing Why? There's no way you can make this correctly with a synchronous method
– Camilo Terevinto
Aug 10 at 15:04





because i'm using req/resp outputs in a testApp. The main app is using all synchronous calls. I wanted to imitate synchronous calls in a test app too
– AnKing
Aug 10 at 15:10





@AnKing You are presumably connecting to an online service to handle the login, yes? That means you have exactly two options. A] You handle the login asynchronously, or B] you block the UI thread (a.k.a. freeze the entire app) while you wait for the online service to respond.
– Abion47
Aug 10 at 15:45






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

Firebase Auth - with Email and Password - Check user already registered

Dynamically update html content plain JS

How to determine optimal route across keyboard