The code below works for sending a HTTP post to Webhook.site, but when doing the same request to my own azurewebsite the debugger stops at postasync and the ’response’ variable remains null.
My azure website returns 200 from json-string POST from ReqBin. My excel application can send working http posts to Webhook.site using the code below, just not to my own azurewebsite. What am I missing?
Some resources suggest SSL validation might cause problems? Not sure if this is the case.
private static readonly HttpClient client = new HttpClient();
public async Task<HttpResponseMessage> PostRequest(IRibbonControl control)
{
var content = new StringContent(json_object.ToString(), System.Text.Encoding.UTF8, "application/json");
//This is where i input my own website and it doesn't work
HttpResponseMessage response = await client.PostAsync("https://webhook.site/9b994ad0-81a1-496f-b910-d48d0567b1b8", content).ConfigureAwait(false);
var responseString = await response.Content.ReadAsStringAsync();
return response;
}
Thank you for your help.
To see result of postAsync method in debug execute 2 steps. Screenshot: postAsync debug
return HttpResponseMessage from method with postAsync:
private static async Task<HttpResponseMessage> methodWithPostAsync(){
...
response = await client.PostAsync(url, data);
return response
}
call method and wait for response message status:
Task<HttpResponseMessage> content= methodWithPostAsync();
while (!content.IsCompleted)
{
Console.WriteLine("busy");
System.Threading.Thread.Sleep(1000);
}
Related
Does anyone know why HttpClient - PostAsync doesn’t return. It just does nothing. I have had it working occasionally especially for one off posts but it seems sometimes to not do anything especially under load and it doesn't throw an exception which of course makes my code unreliable and hard to debug.
I have tried adding ConfigureAwait(false) It makes not difference.
I suspect the Task is failing to 'pack'
This is in a core 3.0 console app run on macOS Catalina using visual studio code
This code is pretty much copied from Microsoft's documentation and I’m calling Microsoft Graph when posting.
public static async Task PostAsync(HttpClient httpClient, string url, string token, HttpContent content, Action<JObject> processResult, ILogger log)
{
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
// content.Headers.Clear();
content.Headers.Add("Content-Type", "application/json");
try
{
HttpResponseMessage response = await httpClient.PostAsync(url, content);
if (response.IsSuccessStatusCode)
{
var json = await response.Content.ReadAsStringAsync();
var result = JsonConvert.DeserializeObject(json) as JObject;
processResult(result);
}
else
{
var errorContent = await response.Content.ReadAsStringAsync();
log.LogError(errorContent);
}
}
catch (System.Exception ex)
{
log.LogError(ex, ex.Message);
throw;
}
}
Here is an example of the calling code
public async Task SendInvitation(string token, Invitation invitation, ILogger logger)
{
var stringContent = new StringContent(JsonConvert.SerializeObject(invitation), Encoding.UTF8, "application/json");
await HttpHelpers.PostAsync(
Client,
"https://graph.microsoft.com/v1.0/invitations",
token,
stringContent,
result => logger.LogInformation(DebugHelpers.Print(result)),
logger);
}
Answered (Sort of)
If I change
HttpResponseMessage response = await httpClient.PostAsync(url, content);
to
HttpResponseMessage response = httpClient.PostAsync(url, content).GetAwaiter().GetResult();
It seems to work but it's slow because what I'm doing is using blocking code. I think this is a quirk of core 3 on macOS. I don't like that this is happening.
More Info
I'm doing a lot of looping.
It seems that if I put all the things I'm awaiting in a taskList it behaves properly.
\\ Pseudo Code
var taskList = new List<Task>();
foreach(var thing in things){
taskList.Add(HttpHelpers.PostAsync(...things));
}
await Task.WhenAll(taskList);
Please check whether all calls you make in the code execution path support asynchronousity. For example once I spent quite some time figuring out a nuget package called CommandLineParser did not support async calls. I was using it like so :
public static void Main(string[] args)
{
Parser.Default.ParseArguments<Options>(args)
.WithParsed(async options =>
{ await httphelper.PostAsync(...);
}
}
I fixed the issue by changing it to something like
public static void Main(string[] args)
{
Parser.Default.ParseArguments<Options>(args)
.WithParsed(options =>
{ httphelper.PostAsync(...).Result;
}
}
So please check you are not using some calls that do not support async in the way.
You can wait for HttpResponseMessage certain condition. Inspect HttpResponseMessage in debug, with 2 given steps. Screenshot of debug process: postAsync debug
return HttpResponseMessage from method with postAsync:
private static async Task<HttpResponseMessage> methodWithPostAsync(){
...
response = await client.PostAsync(url, data);
return response
}
call method and wait for response message status:
Task<HttpResponseMessage> content= methodWithPostAsync();
while (!content.IsCompleted)
{
Console.WriteLine("busy");
System.Threading.Thread.Sleep(1000);
}
try ConfigureAwait like this
HttpResponseMessage response = await httpClient.PostAsync(url, content).ConfigureAwait(false);
I have a WS that I call like this:
HttpResponseMessage response = await client.PostAsync(url, new StringContent(json));
the WS will throw an Exception (Forbidden) and in my Blazor application that made the PostAsync call, I will get an HttpResponseMessage with response code 405, not sure why its 405, it should be 403 (Postman returns 403).
I have enabled CORS (ServiceStack code):
Plugins.Add(new CorsFeature(allowedOrigins: "*",
allowedMethods: "GET, POST, PUT, DELETE, OPTIONS",
allowedHeaders: "*",
allowCredentials: true));
This is some Console.Writeline I did, just before the PostAsync:
Failed to load resource: the server responded with a status of 405 ()
** UPDATED **
This are the two methods:
public async Task<TResponse> PostAsync<TResponse, TRequest>(string requestUri, TRequest request)
{
string url = GetUrl(requestUri);
Console.WriteLine("URI: " + url);
string json = JsonConvert.SerializeObject(request);
Console.WriteLine($"{url} | {json}");
HttpResponseMessage response = await client.PostAsync(url, new StringContent(json));
return await GetResponseOrThrowHttpException<TResponse>(response);
}
private async Task<T> GetResponseOrThrowHttpException<T>(HttpResponseMessage response)
{
Console.WriteLine($"GetResponseOrThrowHttpException: {response.StatusCode}");
string responseString = await response.Content.ReadAsStringAsync();
Console.WriteLine($"GetResponseOrThrowHttpException ContentStringResult: |{responseString}|");
if (!response.IsSuccessStatusCode)
{
Newtonsoft.Json.Linq.JObject jsonObject = Newtonsoft.Json.Linq.JObject.Parse(responseString);
string responseStatusString = jsonObject["ResponseStatus"].ToString();
Console.WriteLine($"GetResponseOrThrowHttpException 4: {responseStatusString}");
ResponseStatus responseStatus = JsonConvert.DeserializeObject<ResponseStatus>(responseStatusString);
Console.WriteLine($"Throwing HttpException: {response.StatusCode} {responseStatus.Message}");
throw new HttpException(response.StatusCode, responseStatus.Message);
}
return JsonConvert.DeserializeObject<T>(responseString);
}
When I try to get the string value of the response, it is empty:
string responseString = await response.Content.ReadAsStringAsync();
and the responseString is an empty (length 0) string.
If I run the exact same request in Postman, I get a valid response:
So, the response JSON, seen at the bottom in the image above, is what I want to work with in the Blazor app, and parse it as a JSON object and move on from there.
I also note that I get here a 403 error, which I expected, and in the Blazor app, I get a 405.
Is this a CORS issue even though I have enabled CORS on the WS side?
I guess your content should be posted like that:
new StringContent(json, Encoding.UTF8, "application/json")
Even if this is not the cause of your suffering, it's better to use this so...
Hope this helps...
Verify that you have setup proper CORS configuration for the domain.
Looks like you made call to another domain:port combination from your Blazor application. Even if this C#, all security rules inside browser still applies.
I am trying to write call a web page that then posts to a web service that outputs a JSON file.
The problem I have is that the GetAsync returns a null value for response. This in turn doesn't provide the proper URL for call back for the GetTestResultAsync method.
Here's my code:
static HttpClient client = new HttpClient();
static async Task RunAsync()
{
// New code:
client.BaseAddress = new Uri("http://10.1.10.10:8080/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
try
{
Uri url = await CallTestAsync();
string response = await GetTestResultAsync(url.PathAndQuery);
Console.WriteLine(response);
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
static async Task<Uri> CallTestAsync()
{
HttpResponseMessage response = await client.GetAsync("test.html");
response.EnsureSuccessStatusCode();
// return URI of the created resource.
return response.Headers.Location;
}
static async Task<string> GetTestResultAsync(string path)
{
HttpResponseMessage response = await client.GetAsync(path);
string streamResponse = string.Empty;
if (response.IsSuccessStatusCode)
{
streamResponse = await response.Content.ReadAsStringAsync();
}
return streamResponse;
}
static void Main(string[] args)
{
RunAsync().Wait();
}
HttpClient by default will automatically redirect 3xx responses, which means that the response you get when calling GetAsync will not have the Location header as it would have already redirected to the proper location.
To override this behaviour you have to provide an HttpMessageHandler with this feature disabled. For example:
static HttpClientHandler handler = new HttpClientHandler { AllowAutoRedirect = false };
static HttpClient client = new HttpClient(handler);
The important part here being setting the handler's AllowAutoRedirect to false.
Important: By overriding the default behaviour for redirect responses you'll have to handle any 3xx manually, which might add unnecessary work for you as in many cases the default behaviour is sufficient. If you were to leave it as is, it'd already make the 2nd request that you're doing, for you.
Also note that a 3xx response is not a success response, which means that if you don't use the auto-redirect feature when you call response.EnsureSuccessStatusCode(); it'll throw an exception.
Furthermore, although most servers are quite forgiving when it comes to headers such as the Accept header, you are most likely using the wrong one in this case as an HTML page should be a text/html rather than an application/json (which should be used when expecting a JSON object as a response).
I am trying to send an Http Get message to the Google location Api which is supposed to have Json data such as this
https://maps.googleapis.com/maps/api/geocode/json?address=Los%20Angeles,CA=AIzaSyDABt
as you noticed the response is in Json. I want to give a a Http Call to that URL and save the Json content in a variable or string. My code does not give out any errors but it is also not returning anything
public async System.Threading.Tasks.Task<ActionResult> GetRequest()
{
var client = new HttpClient();
HttpResponseMessage response = await client.GetAsync("https://maps.googleapis.com/maps/api/geocode/json?address=Los%20Angeles,CA=AIzaSyDABt");
string data = response.Content.ToString();
return data;
}
I want to send out a Get Request using HttpClient() or anything that will send out the URL request and then save that content into a string variable . Any suggestions would be appreciated, again my code gives no errors but it is not returning anything.
Use ReadAsStringAsync to get the json response...
static void Main(string[] args)
{
HttpClient client = new HttpClient();
Task.Run(async () =>
{
HttpResponseMessage response = await client.GetAsync("https://maps.googleapis.com/maps/api/geocode/json?address=Los%20Angeles,CA=AIzaSyDABt");
string responseString = await response.Content.ReadAsStringAsync();
Console.WriteLine(responseString);
});
Console.ReadLine();
}
If you use response.Content.ToString() it is actually converting the datatype of the Content to string so you will get System.Net.Http.StreamContent
Try this.
var client = new HttpClient();
HttpResponseMessage httpResponse = await client.GetAsync("https://maps.googleapis.com/maps/api/geocode/json?address=Los%20Angeles,CA=AIzaSyDABt");
string data = await httpResponse.Content.ReadAsStringAsync();
How about using the Json framework for .NET powered by Newtonsoft ?
You can try to parse your content to a string with this.
Well, your code can be simplified:
public async Task<ActionResult> GetRequest()
{
var client = new HttpClient();
return await client.GetStringAsync("https://maps.googleapis.com/maps/api/geocode/json?address=Los%20Angeles,CA=AIzaSyDABt");
}
However...
My code does not give out any errors but it is also not returning anything
This is almost certainly due to using Result or Wait further up the call stack. Blocking on asynchronous code like that causes a deadlock that I explain in full on my blog. The short version is that there is an ASP.NET request context that only permits one thread at a time; await by default will capture the current context and resume in that context; and since Wait/Result is blocking a thread in the request context, the await cannot resume executing.
Try this
public async static Task<string> Something()
{
var http = new HttpClient();
var url = "https://maps.googleapis.com/maps/api/geocode/json?address=Los%20Angeles,CA=AIzaSyDABt";
var response = await http.GetAsync(url);
if (response.IsSuccessStatusCode)
{
var result = await response.Content.ReadAsStringAsync();
result = JsonConvert.DeserializeObject<string>(result);
return result;
}
return "";
}
var result = Task.Run(() => Something()).Result;
I have some very simple code that I have been using in a windows 8 store app without any issue. However When I shared the code with windows phone app It just hangs forever. See sample below. This calls any web url and returns its source as a string. both the post and get methods hang in the same way. any help is much appreciated, Thank you.
public static string GetWebSource(string Url)
{
HttpClient client = new HttpClient();
Task<HttpResponseMessage> Resp = client.GetAsync(Url);
//code hangs on following line forever
//Resp.status always stays at waiting for activation
Task.WaitAll(Resp);
if (Resp.Result.IsSuccessStatusCode)
{
Task<string> response = Resp.Result.Content.ReadAsStringAsync();
Task.WaitAll(response);
return response.Result;
}
return "";
}
public static string PostWebSource(string Url, string data)
{
HttpClient client = new HttpClient();
StringContent sc = new StringContent(data);
Task<HttpResponseMessage> Resp = client.PostAsync(Url, sc);
//code hangs on following line forever
//Resp.status always stays at waiting for activation
Resp.Wait();
if (Resp.Result.IsSuccessStatusCode)
{
Task<string> response = Resp.Result.Content.ReadAsStringAsync();
Task.WaitAll(response);
return response.Result;
}
return "";
}
You should be using an HttpWebRequest on Windows Phone. See this link: http://social.msdn.microsoft.com/Forums/wpapps/en-us/9b4c1ef2-853c-468a-bca8-97477a02583c/httpclient-for-windows-phone-8?forum=wpdevelop