await HttpClient.SendAsync not throwing exception when expected - c#

I have a Windows Phone 8 app containing code as follows:
using (var client = new HttpClient())
{
var httpRequest = new HttpRequestMessage(method, uri);
try
{
var response = client.SendAsync(httpRequest);
var httpResponse = await response;
if (httpResponse.IsSuccessStatusCode)
{
var result = await httpResponse.Content.ReadAsStringAsync();
return result;
}
else
{
HandleError(httpResponse);
return null;
}
}
catch (Exception ex)
{
throw;
}
}
If the client successfully connects to the server, I will get the expected results, including all the appropriate HTTP status codes and reason phrases.
If the client is unable to contact the server (e.g. incorrect domain/IP/port in the URL), the awaited task completes after some delay, with a 404 status and no reason phrase. The task never throws an exception. The task (the response variable in the code snippet) has the status of "ran to completion". Nothing about the result is indicative of the actual problem - be it networking failure, unreachable server, etc.
How can I capture more meaningful errors in the case where the URL points to a non-existent or unreachable server, socket connection refused, etc.? Shouldn't SendAsync be throwing specific exceptions for such cases?
FWIW, the client code is built into a PCL library using VS 2013 update 3 and running in the Windows Phone emulator, using System.Net.Http 2.2.28 from NuGet

Windows Phone's implementation of the .NET HttpClient is different from Desktop's implementation (wininet vs. custom stack). This is one of the incompatibilities that you need to be aware of, if there is a semantic difference for you.
In my simple test I do get a ReasonPhrase of "Not Found" on the phone emulator. Also you can see that the Headers collection is empty whereas if the server was found and actually returned a real 404 then there would be headers.

Related

Adding SSL cert causes 404 only in browser calls

I am working in an internal corporate environment. We have created a webapi installed on iis on port 85. We call this from another MVC HelperApp on port 86. It all works as expected. Now we want to tighten security and add an SSL cert to iis on port 444 and bind it to our API.
Initially we test it with Postman, SoapUI, and a C# console app and it all works. Now we try calling it from our MVC HelperApp and it returns a 404 sometimes.
Deeper debugging; I put the code into a C# DLL (see below). Using the console app I call the Dll.PostAPI and it works as expected. Now I call that same Dll.PostAPI from the MVC HelperApp and it won't work. When I step through the code I make it as far as this line await client.PostAsync(url, data); and the code bizarrely ends, it doesn't return and it doesn't throw an exception. Same for Post and Get. I figure it makes the call and nothing is returned, no response and no error.
Also, if I change the url to "https://httpbin.org/post" or to the open http port85 on iss it will work. I have concluded that the C# code is not the problem (but I'm open to being wrong).
Therefore I have come to the conclusion that for some reason the port or cert is refusing calls from browsers.
We are looking at:
the "Subject Alternative Name" but all the examples show
WWW.Addresses which we are not using.
the "Friendly Name" on the cert creation.
and CORS Cross-Origin Resource Sharing.
These are all subjects we lack knowledge in.
This is the calling code used exactly the same in the console app and the web app:
var lib = new HttpsLibrary.ApiCaller();
lib.makeHttpsCall();
This is what's in the DLL that gets called:
public async Task<string> makeHttpsCall()
{
try
{
List<Quote> quotes = new List<Quote>();
quotes.Add(CreateDummyQuote());
var json = JsonConvert.SerializeObject(quotes);
var data = new StringContent(json, Encoding.UTF8, "application/json");
var url = "https://httpbin.org/post"; //this works in Browser
//url = "https://thepath:444//api/ProcessQuotes"; //444 DOES NOT WORK in browsers only. OK in console app.
//url = "http://thepath:85/api/ProcessQuotes"; //85 works.
var client = new HttpClient();
var response = await client.PostAsync(url, data); //<<<this line never returns when called from browser.
//var response = await client.GetAsync(url); //same outcome for Get or Post
var result = await response.Content.ReadAsStringAsync();
return result;
}
catch (Exception ex)
{
throw;
}
}

HttpTwo client on server 2008 (APNS with JWT)

EDIT - Due to probable misintepretation:
This is not about the server side of HTTP/2 - its about a client HTTP/2 request from an older server OS. Also, i got it to work using python (gobiko.apns) , so it seems to me it should be possible.
EDIT 2
It seems this question has not so much to do with HTTP2, but rather the cipher required by apple. TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 is not used by the SslStream in versions pre-win10. However, since it can be done using python, it seems to me that it should be possible. Any help would be appreciated.
We found some code here and there to get our connection to the APNS working on our development environment. We are using the .p8 certificate and sign a token as authorization (not the 'old' interface).
This works on my dev pc (win10) but when i transfer it to a server 2008 R2 it gives a weird warning. It seems having to do with the setup of the tls connection, however, i'm not too familiar with that area. I really searched but the only thing i can come up with is that server 2008R2 will not support it due to ciphers or something (which seems unreasonable to me).
The code that is working from my pc (using nuget HttpTwo and Newtonsoft):
public static async void Send2(string jwt, string deviceToken)
{
var uri = new Uri($"https://{host}:443/3/device/{deviceToken}");
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
ServicePointManager.ServerCertificateValidationCallback = delegate
{
Console.WriteLine("ServerCertificateValidationCallback");
return true;
};
string payloadData = Newtonsoft.Json.JsonConvert.SerializeObject(new
{
aps = new
{
alert = new
{
title = "hi",
body = "works"
}
}
});
//PayloadData always in UTF8 encoding
byte[] data = System.Text.Encoding.UTF8.GetBytes(payloadData);
var httpClient = new Http2Client(uri);
var headers = new NameValueCollection();
headers.Add("authorization", string.Format("bearer {0}", jwt));
headers.Add("apns-id", Guid.NewGuid().ToString());
headers.Add("apns-expiration", "0");
headers.Add("apns-priority", "10");
headers.Add("apns-topic", bundleId);
try
{
var responseMessage = await httpClient.Send(uri, HttpMethod.Post, headers, data);
if (responseMessage.Status == System.Net.HttpStatusCode.OK)
{
Console.WriteLine("Send Success");
return;
}
else
{
Console.WriteLine("failure {0}", responseMessage.Status);
return;
}
}
catch (Exception ex)
{
Console.WriteLine("ex");
Console.WriteLine(ex.ToString());
return;
}
}
is throwing
System.Security.Authentication.AuthenticationException: A call to SSPI failed, see inner exception. ---> System.ComponentModel.Win32Exception: The message received was unexpected or badly formatted
from server 2008R2.
I also tried it with a WinHttpHandler, which also works from my PC, but throws
System.Net.Http.HttpRequestException: An error occurred while sending the request. ---> System.Net.Http.WinHttpException: A security error occurred
Stacktraces are mostly async thingies, but it boils down to HttpTwo.Http2Connection.<Connect> for the HttpTwo implementation and System.Net.Http.WinHttpHandler.<StartRequest> for the WinHttpHandler.
Is there something i have to add to the server in order to work / will we get it to work?
UPDATE
I included the sourcefiles from HttpTwo in my project and debugged it. The exception occurs on
await sslStream.AuthenticateAsClientAsync (
ConnectionSettings.Host,
ConnectionSettings.Certificates ?? new X509CertificateCollection (),
System.Security.Authentication.SslProtocols.Tls12,
false).ConfigureAwait (false);
on my Win8 test pc. Now, when i use the method overload with only the host argument on my own PC it throws the same exception, i guess because the tls protocol is off then.
According to this Github issue it could have to do with the ciphers. I had some problems before in that area, but it seems to me that at least a WIN8 PC must be able to agree upon secure enough ciphers, right?
Schannel is complaining about "A fatal alert was received from the remote endpoint. The TLS protocol defined fatal alert code is 40.", so that points into that direction also afaik.
It's the cipher... The ciphers Apple uses are not included into SChannel below Win10/Server2016.
(see Edit 2)

Windows store app HttpClient issue

i'm testing some code here and came across a really weird issue. The HttpClient class works like a charm if my tablet is on but whenever the battery safe state kicks in and the screen is locked the HttpClient class throw an exception and the app suddendly exits giving me small chances to log the exception. If i'm not mistaken the error seems to be a send request error but that's weird since i have full access to the internet while the tablet is on.
Here the code i'm using and the one that crash on that state(System.Net.Http namespace ):
private static async Task<string> HttpGet(string uri)
{
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("User-Agent", BotUserAgent);
var response = await client.GetAsync(uri);
return await response.Content.ReadAsStringAsync();
}
}
Alternatively i've used the client of the web.http namespace with the same result:
using(var client = new Windows.Web.Http.HttpClient())
{
client.DefaultRequestHeaders.Add("User-Agent", BotUserAgent);
var response = await client.GetAsync(new Uri(uri));
return await response.Content.ReadAsStringAsync();
}
This is the error i get(after adding an exception logger):
An error occurred while sending the request.
Any ideas?
The problem is that your WinRT-device sends your app to the background when the battery safe state kiks in.
whenever the user moves your app into the background, your app can be suspended or frozen, essentially stopping any downloads dead in their tracks. In some scenarios, the app might
even be terminated, forcing you to create a new instance of the class in an attempt to start the download again. Fortunately, WinRT provides a way to handle this specific scenario using a background task.
This is a quote from http://www.informit.com/articles/article.aspx?p=2229233&seqNum=6
On this site is an easy tutorial to follow on how to use BackgroundTransfers in the Windows.Networking.BackgroundTransfer-Namespace.

HttpClient GET request fails, POST Succeeds

In a Xamarin application (backed by ASP.NET WebApi), I'm having trouble getting [all of] my GET requests to succeed -- they return 404. In fact, when watching network traffic in Fiddler, I don't even see the request happen.
Here is [basically] what I'm doing:
public async Task<bool> ValidateSponsor(string attendeeId, string sponsorId)
{
string address = String.Format("{0}/Sponsors/?attendeeId={1}&sponsorId={2}", BASE_URI, attendeeId, sponsorId);
var response = await client.GetAsync(address);
var content = response.content;
if (!response.IsSuccessStatusCode)
throw new HttpRequestException("Check your network connection and try again.");
string result = await content.ReadAsStringAsync();
return Convert.ToBoolean(result);
}
If I copy out the address variable and paste it into a browser, it succeeds. POST requests (to different methods, of course) succeed. I've also tried using the PCL version RestSharp but get the same results -- POST succeeds and GET fails.
Edit:
This looks like it also may only be a problem when deployed to Azure, it works fine locally.

Downloading webpages in WinRT throws an exception

I'm using this code to download a web page in my Metro Style app:
public static async Task<string> DownloadPageAsync(string url)
{
HttpClientHandler handler = new HttpClientHandler();
handler.UseDefaultCredentials = true;
handler.AllowAutoRedirect = true;
HttpClient client = new HttpClient(handler);
HttpResponseMessage response = await client.GetAsync(url);
response.EnsureSuccessStatusCode();
string responseBody = response.Content.ReadAsString();
return responseBody;
}
the problem is that when the line client.GetAsync(url) runs, it throws an exception that says:
An error occurred while sending the request. From type: HttpRequestException.
EDIT:
I've used the InnerException to get more info. The first exception thrown is SocketException with the message below:
An attempt was made to access a socket in a way forbidden by its access permissions
at System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult)
at System.Net.Http.HttpClientHandler.GetResponseCallback(IAsyncResult ar)
EDIT 2:
I've downloaded and ran the sample from Microsoft and I get the same error:
http://code.msdn.microsoft.com/windowsapps/HttpClient-Upload-Sample-f1abcc4e
EDIT 3:
I ran this on another machine and it worked fine. So I guess there's nothing wrong with the code. I copied the solution and it means that there's nothing wrong with the solution either. I'm trying to re-install Windows Developer Preview to see if it fixes my problem.
OK. I found the answer. The exception was because I installed NetLimiter product on Windows 8 Developer Preview and somehow it prevented my app from accessing the internet.
UPDATE:
First of all, this is the code working in EVERY version of Windows 8.
public static async Task<string> DownloadPageAsync(string url)
{
try
{
HttpClientHandler handler = new HttpClientHandler { UseDefaultCredentials = true, AllowAutoRedirect = true };
HttpClient client = new HttpClient(handler);
HttpResponseMessage response = await client.GetAsync(url);
response.EnsureSuccessStatusCode();
string html = await response.Content.ReadAsStringAsync();
return html;
}
catch (Exception)
{
return "";
}
}
Secondly, if this doesn't work, chances are, you have a network-related software preventing your app to access the Internet. One popular case is proxifier. If you have proxifier installed your MetroStyle apps won't be able to access the internet. To make it work, please refer to my blog at:
http://anoori.me/blog/general/use-proxifier-in-windows-8-without-fiddler2
pretty sure netlimiter was running your internet request through a localhost proxy, and your app didn't have the "local network" capability which would allow such access to the local network

Categories