Post to HTTP and get JSON response back in c# - c#

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).

Related

HTTP PostAsync returns nothing

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);
}

How can I execute an url call from C# code on a ASP website on a ASCX page?

I need to call a Custom protocol (something like: "custom:signDocs?param1=value?param2=value") that is registered on a client.
I have a working one that is executed via JavaScript on a button click.
But I need to call the url to execute the program I have on the clients pc.
The program is for signing documents and sending them back to the server, and, in the code I have a 15min timer that waits for the status of the documents to change to signed then it shows the documents to the user.
I also tried using webrequest:
//Method that uses the webrequest
{
System.Net.WebRequest.RegisterPrefix("customProtocolName", new PrototipoIDPTRequestCreator());
System.Net.WebRequest req = System.Net.WebRequest.Create(protocolUrlWithParams);
var aux = req.GetResponse();
}
internal class CustomRequestCreator : System.Net.IWebRequestCreate
{
public WebRequest Create(Uri uri)
{
return new CustomWebRequest(uri);
}
}
class CustomWebRequest: WebRequest
{
public override Uri RequestUri { get; }
public CustomWebRequest(Uri uri)
{
RequestUri = uri;
}
}
But this does nothing, I do not know it its even the right path...
Does anyone know of a way to accomplish this?
You can use HttpClient from System.Net.Http like the following example.
Simple get call from a test api endpoint.
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("YOUR_BASE_URL"); //https://localhost:8000
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await client.GetAsync("api/test"); //api uri
response.EnsureSuccessStatusCode();
string responseBody = await response.Content.ReadAsStringAsync();
}
Note: For more details refer, HttpClient Doc

HttpClient changing request URI when called from WebAPI

I am implementing a transparent server-side proxy for an ASP.NET MVC application which wants to communicate with an API on another server; the code is fairly straightforward:
public class TransparentProxyDelegatingHandler : DelegatingHandler
{
private static readonly Uri ApiUri;
private static readonly HttpClient Client;
static TransparentProxyDelegatingHandler()
{
var apiServer = new Uri(ConfigurationManager.AppSettings["ApiUrl"]);
ApiUri = new Uri(apiServer);
Client = new HttpClient();
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
request.Headers.Add("X-Forwarded-For", request.GetClientIpAddress());
request.RequestUri = TranslateIncomingRequestToUpstreamApi(request);
request.Headers.AcceptEncoding.Clear();
var response = await Client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
return response;
}
private static Uri TranslateIncomingRequestToUpstreamApi(HttpRequestMessage request)
{
var forwardUri = new UriBuilder(request.RequestUri)
{
Host = ApiUri.Host,
Path = request.RequestUri.AbsolutePath.Replace("/Proxy", string.Empty)
};
return forwardUri.Uri;
}
}
So if I query GET https://ui.myserver.com/proxy/timesheets?from=2018-01-01, the request URI gets changed by the proxy to GET https://api.myserver.com/timesheets?from=2018-01-01, and I can verify this in the debugger; however, when the SendAsync method is invoked, the hostname part of the request URI is changed back to https://ui.myserver.com, and the call fails.
Why is it changing the value of request.RequestUri when I call SendAsync ? I've checked the source in GitHub (https://github.com/dotnet/corefx/blob/master/src/System.Net.Http/src/System/Net/Http/HttpClient.cs), but none of the conditions for changing the value seem to apply in my case. Unfortunately the GitHub source does not align with the debug symbols, so I can't seem to step into the HttpClient source to figure out what's really going on.
OK, I found the cause of my problem; I needed to set change the Host header; the initial request to the proxy set it to the hostname of the UI (ui.myserver.com), and that overrides the hostname of the proxy that was set in the request. So if I add the following:
request.Headers.Host = $"{ApiUri.Host}:{ApiUri.Port}";
then everything magically works.

How to get and print response from Httpclient.SendAsync call

I'm trying to get a response from a HTTP request but i seem to be unable to. I have tried the following:
public Form1() {
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("someUrl");
string content = "someJsonString";
HttpRequestMessage sendRequest = new HttpRequestMessage(HttpMethod.Post, client.BaseAddress);
sendRequest.Content = new StringContent(content,
Encoding.UTF8,
"application/json");
Send message with:
...
client.SendAsync(sendRequest).ContinueWith(responseTask =>
{
Console.WriteLine("Response: {0}", responseTask.Result);
});
} // end public Form1()
With this code, i get back the status code and some header info, but i do not get back the response itself. I have tried also:
HttpResponseMessage response = await client.SendAsync(sendRequest);
but I'm then told to create a async method like the following to make it work
private async Task<string> send(HttpClient client, HttpRequestMessage msg)
{
HttpResponseMessage response = await client.SendAsync(msg);
string rep = await response.Content.ReadAsStringAsync();
}
Is this the preferred way to send a 'HttpRequest', obtain and print the response? I'm unsure what method is the right one.
here is a way to use HttpClient, and this should read the response of the request, in case the request return status 200, (the request is not BadRequest or NotAuthorized)
string url = 'your url here';
// usually you create on HttpClient per Application (it is the best practice)
HttpClient client = new HttpClient();
using (HttpResponseMessage response = client.GetAsync(url).GetAwaiter().GetResult())
{
using (HttpContent content = response.Content)
{
var json = content.ReadAsStringAsync().GetAwaiter().GetResult();
}
}
and for full details and to see how to use async/await with HttpClient you could read the details of this answer

Get URL using HttpClient C# .NET

I am trying to get the URL of a page using HttpClient. I've previously only used HttpWebRequest, but I need to make this an async method.
In the code below, myUri always returns null which results in throwing an exception when I try to handle it later on.
Is the location header the wrong thing to be using?
string myUrl = "http://www.example.com/";
Uri myUri= new Uri(myUrl);
using (HttpClient client = new HttpClient())
using (HttpResponseMessage response = await client.GetAsync(myUri))
{
if (response.IsSuccessStatusCode)
{
myUri= response.Headers.Location;
Debug.WriteLine("True "+ myUri);
}
else {
Debug.WriteLine("False " + myUri);
}
}
It's because HttpClient will automatically follows redirects. If you need the URL a page redirects to, you need to stop it from automatically following:
Change your code to the following:
string myUrl = "http://www.example.com/";
Uri myUri= new Uri(myUrl);
HttpClientHandler httpClientHandler = new HttpClientHandler();
httpClientHandler.AllowAutoRedirect = false;
using (HttpClient client = new HttpClient(httpClientHandler))
Here is an async way to resolve the final redirect URL:
public static async Task<string> ResolveFinalRedirectAsync(string url)
{
try
{
var req = WebRequest.CreateHttp(url);
req.AllowAutoRedirect = true;
var res = await req.GetResponseAsync();
return res.ResponseUri.AbsoluteUri;
}
catch
{
Console.WriteLine("Couldn't resolve '{0}'", url);
}
return null;
}
See #Rob's answer about AllowAutoRedirect.
Once you do that, note
The line
if (response.IsSuccessStatusCode)
evaluates to false if you receive a HTTP 301 redirect (anything outside of the 200-299 range)
A value that indicates if the HTTP response was successful. true if HttpStatusCode was in the Successful range (200-299); otherwise false.
(source)
OK thanks I'm trying to get redirected URLs anyway
If you prevent automatically following redirects, you will get an HTTP response in the 3xx range for the redirect. Your check for valid codes will have to be modified accordingly.

Categories

Resources