I am doing Async
and Await
with C# ASP.Net MVC, with Target .Net Framework 4.8 using Visual Studio 2022. So no matter what, I always get an exception when I call httpClient.PostAsync(...)
. I can call httpClient.PostAsync(...).ConfigureAwait(false)
which doesn’t give me an immediate exception and my code after proceeds normally, but I still get an exception by the last closing bracket of my method.
So first, I am making httpClient
a private static
variable in my class, and I think this is the recommended practice:
private static readonly HttpClient httpClient = new HttpClient();
Here is the code where I call httpClient.PostAsync(...)
but I don’t call ConfigureAwait(false)
and this gives me an immediate exception in the Visual Studio 2022 debugger and I never make it to the end curly bracket of my method (I simplified the code a little):
private async Task MyMethod(string json, Dictionary<string, string> headerDictionary)
{
string accessToken = GetAccessToken();
string webhookID = WebConfigurationManager.AppSettings["PayPalWebhookID"];
var paypalVerifyRequestJsonString = ... ...;
string payPalServHref = WebConfigurationManager.AppSettings["PayPalV2ServHref"];
httpClient.DefaultRequestHeaders.Clear();
httpClient.DefaultRequestHeaders.Add("authorization", "Bearer " + accessToken);
var content = new StringContent(paypalVerifyRequestJsonString, Encoding.UTF8, "application/json");
// if I return here, there is no exception
//return;
var resultResponse = await httpClient.PostAsync(payPalServHref + "/v1/notifications/verify-webhook-signature", content);
// the end curly bracket of this method (the } below) is never reached
}
An exception is immediately thrown when I call httpClient.PostAsync(...)
:
Now I just change httpClient.PostAsync(...)
to httpClient.PostAsync(...).ConfigureAwait(false)
and my code proceeds normally when I debug it, but an exception is always thrown by the end curly bracket of my method (again, I simplified the code a little):
private async Task MyMethod(string json, Dictionary<string, string> headerDictionary)
{
string accessToken = GetAccessToken();
string webhookID = WebConfigurationManager.AppSettings["PayPalWebhookID"];
var paypalVerifyRequestJsonString = ... ...;
string payPalServHref = WebConfigurationManager.AppSettings["PayPalV2ServHref"];
httpClient.DefaultRequestHeaders.Clear();
httpClient.DefaultRequestHeaders.Add("authorization", "Bearer " + accessToken);
var content = new StringContent(paypalVerifyRequestJsonString, Encoding.UTF8, "application/json");
// if I return here, there is no exception
//return;
var resultResponse = await httpClient.PostAsync(payPalServHref + "/v1/notifications/verify-webhook-signature", content).ConfigureAwait(false);
// lines after httpClient.PostAsync(...).ConfigureAwait(false); are reached and I can debug it, but there will always be an exception
// thrown by the end curly bracket below (the } below)
// if I undo this comment for return, the return statement is called but an exception is still thrown by the end curly bracket below (the } below)
// return;
}
And as I said, ConfigureAwait(false)
allows my code to proceed normally, but an exception is always thrown by the end curly bracket of my method:
I am calling MyMethod(...)
as follows (actually, PayPal Sandbox is calling my C# ASP.Net Webhook method and inside my Webhook method, the call is made to await MyMethod(...)
:
await MyMethod(json, headerDictionary);
The interesting thing is, if I remove all instances of Async and Await, and I forcefully call httpClient.PostAsync(...)
synchronously, that is I call
httpClient.PostAsync(...).Result
, everything works and I don’t get any exceptions at all:
var resultResponse = httpClient.PostAsync(payPalServHref + "/v1/notifications/verify-webhook-signature", content).Result;
Does anybody know why I keep getting exceptions when using Async
and Await
when calling httpClient.PostAsync(...)
or calling httpClient.PostAsync(...).ConfigureAwait(false)
?
Edit: Some people requested the function that is calling MyMethod(…). So here is the function that is calling MyMethod(…). It’s just a Webhook method that PayPal Sandbox calls:
public async Task<ActionResult> WebhookTester()
{
try
{
// get the JSON from PayPal
Stream req = Request.InputStream;
req.Seek(0, System.IO.SeekOrigin.Begin);
string json = new StreamReader(req).ReadToEnd();
// Get the header from PayPal and store it in a dictionary
var headers = HttpContext.Request.Headers;
Dictionary<string, string> headerDictionary = new Dictionary<string, string>();
var nvc = headers.AllKeys.SelectMany(headers.GetValues, (k, v) => new { key = k, value = v });
foreach (var header in nvc)
{
headerDictionary.Add(header.key, header.value);
}
// Verify the JSON and header. If PayPal returns SUCCESS then process the order. If it's FAILURE, don't process the order.
await MyMethod(json, headerDictionary);
}
catch (Exception ex)
{
}
return new HttpStatusCodeResult(200);
}
2
Answers
I moved all my code from
MyMethod(...)
toWebhookTester()
, including the awaithttpClient.PostAsync(...).ConfigureAwait(false)
call. When I did that, no exception was thrown.I don't know the exact reason why calling await
MyMethod(...)
from myWebhookTester()
method is causing the exception and why moving all the code toWebhookTester()
works all of a sudden and no exceptions are thrown. My theory is that the class I am using that contains bothWebhookTester()
andMyMethod(...)
, is inheriting another base class, and some property in my base class is generating a null exception whenawait MyMethod(...)
is finished being called. However, the Visual Studio debugger never shows me the null exception in my base class - my overall experience is that debugging asynchronous code with Visual Studio is pretty hard. Anyways, this is my theory - in the end, I don't know exactly why putting my code inawait MyMethod(...)
leads to an exception, but taking the same code and putting it inWebhookTester()
does not cause an exception. Maybe it's also an issue with nested asynchronous methods where the class is inheriting another base class.I can’t comment yet, so apologies for writing an answer.
This might be happening because you are using HttpClient as a static variable. Having said that, just reading Microsoft’s site, it suggests it is the correct way. If somewhere in the code HttpClient is being disposed, it could lead to an exception. Check if HttpClient is not disposed somewhere in the code.
Try this with the using statement:
This helps prevent potential issues related to reusing the same HttpClient instance across multiple requests. Hope it helps