Why is System.Net.Http HttpClient encoding my request URL? - c#

I use the HttpClient in System.Net.Http to make requests to a web service as below:
using (var client = new HttpClient())
{
using (var response = client.GetAsync(url).Result)
{
var result = response.Content.ReadAsStringAsync().Result;
}
}
I have a sandbox application and a live application. The sandbox application has identical code (in a shared repository) which works fine, but when client.GetAsync(url).Result is called in the live application, for some reason Fiddler shows me that the requested URL has been encoded which messes the request up.
Requested URL is supposed to look like this:
/advert?paginate=1&page=1&language=en&filters[updated_at][ge]=2016-03-21%2012:19:05
But ends up looking like this:
/advert?paginate=1&page=1&language=en&filters%5Bupdated_at%5D%5Bge%5D=2016-03-21%2012:19:05
Any idea why? Thanks
N.B. Im using the Microsoft.Net.Http library from Nuget in .NET Framework 4.5

Please be very specific about your question:
you use Microsoft.Net.Http version what?
you compile under .NET version what?
Turned out that you compile under .NET 4.0 and this is a bug I would say, because the behavior is not identical to the .NET Fx 4.5 System.Http
You can fix it by setting dontEscape to true in the Uri class:
var url = new Uri(#"http://google.com/advert?paginate=1&page=1&language=en&filters[updated_at][ge]=2016-03-21%2012:19:05", dontEscape: true);

Related

HttpClient and WebClient give 401 error yet direct link in browser works

I'm the middleman on an integration project between a Woocommerce site and a retail POS system. The POS is trying to synchronize products with the Woocommerce store. The site has an SLL certificate so all communication is over SSL. The POS vendor tells me they are using TLS1.2. We have a URL that contains a customer key and secret so I can't paste the full URL here, but the problem is as follows...
The same URL pasted directly into the browser works perfectly well, returning the expected JSON payload. The same URL used with a .NET WebClient or HttpClient returns a 401 Not Authorized error. Here is an example of an integration test using WebClient;
[Test]
public void DownloadString_UsingWebClient_ReturnsNonEmptyResponse()
{
using (var client = new WebClient())
{
var response = client.DownloadString("https://demostore.mycompany.com.au/wp-json/wc/v2/settings/tax/woocommerce_prices_include_tax?consumer_key=ck_xxxskeyxxx&consumer_secret=cs_xxxsecretxxx");
Assert.IsNotEmpty(response);
}
}
And here is a similar test using HttpClient;
[Test]
public async Task DownloadString_UsingHttpClient_ReturnsNonEmptyResponse()
{
using (var client = new HttpClient())
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
var response = await client.GetStringAsync("https://demostore.mycompany.com.au/wp-json/wc/v2/settings/tax/woocommerce_prices_include_tax?consumer_key=ck_xxxskeyxxx&consumer_secret=cs_xxxsecretxxx"");
Assert.IsNotEmpty(response);
}
}
Both tests never make it to the Assert. Just to reiterate, if I take the same URL and paste it into my browser, everything works as expected. I've tried a couple of different things, including enforcing the security protocol type (as in the latter example), but it is all just a poke in the dark, really.
The website is using the latest version of Wordpress, and it is in a shared linux hosting environment.
Is there something I'm missing with WebClient and HttpClient? Do I go back to the web hosting company and find out if there is something in the configuration that would prevent a .NET client from performing the same as a browser (I have logged a support ticket to this effect, but I'm not getting any headway)?
If you're in a corporate network and the browser works and your code doesn't, it's likely you're missing the Proxy settings for the WebClient or HttpClient instance.
I typically pass a HttpClientHandler instance with Preauthenticate = true and UseDefaultCredentials = true to the HttpClient.
I found that usually when something works in the browser, but not outside of it, that suggests that the API relies on User-Agent header being present in the request.
One of the reasons for this may be a reverse-proxy/firewall in front of that API.

HTTP Request in Xamarin.Forms

I'm building a Xamarin.Forms App for Android and iOS which is supposed to consume an API. The API is kind of built in a REST spirit, I'm hosting the API on a local IIS Express server and my Android emulator has no problem finding it (tested on various endpoints and I can also display the api-doc).
I'm trying to get in touch with a http://IPOfMyComputer/api/Stuffs endpoint which gives me a JSON list of Stuff. Using Postman I successfully get all the stuff I needed, a valid auth token in that case, to build a proper HTTP GET request. I'm using the Microsoft.Net.Http NuGet package to build this request as it seemed to be the proper tool to do the job. I'm doing this request building process in Xamarin.Forms "Main" project (not the iOS or Android one, the other one which I don't know how to name which is automatically by Visual Studio).
My code looks like this:
var rootUri = "http://IPOfMyComputer"
var requestedUri = "/api/Stuffs"
var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer",
"blablabla");
var response = await client.GetAsync(rootUri + requestedUri);
And this gives me an error "NotSupportedException" on the last instruction.
I'm clueless here so some help would be really appreciated.
Edit
The proper error message is
"System.InvalidCastException: Specified cast is not valid."
I found the source of that error:
Turns out it wasn't directly linked with the GetAsync method but with some mess in the code related with async/await use.
There was a bunch of crappy code everywhere. I dropped it all to go back to a regular MVVM logic and I put the async/await logic into methods invoked by eventhandlers (instead of trying to "create" an async builder for a class...).

WebException SecureChannelFailure when invoking web service over https from Xamarin Droid app

I'm creating a Xamarin.Droid app with Visual Studio (C#).
I have a RESTful web service (WebAPI) from which I want to retrieve some data in a Xamarin Droid project, using HttpWebRequest. The fact that it's WebAPI and HttpWebRequest is not the key as I had the exact same problem (described below) with some older WSE 3.0 web services and the use of HttpClient in the generated proxies. In the case of those WSE 3.0 web services we solved the problem by extending the generated proxy class to use ModernHttpClient instead. We didn't realize this problem manifests outside of HttpClient. I now think we must be doing something wrong, as opposed to blaming HttpClient.
In the current iteration, connecting to WebAPI, I'm using HttpWebRequest. Whether using HttpWebRequest or HttpClient, everything works fine as long as I'm connecting via http. As soon as I try to connect via https the request fails. For clarification, the web server hosting the web service does have a valid certificate (it's not expired, and has a valid CA.)
I have not been able to find any solution to this problem, despite a ton of Googling. I can barely find references to other people having this problem, much less a solution, which makes me think there must be something wrong in what I'm doing.
Basically, you can this method to a Xamarin.Forms Droid project and call it. If url is using https then request.GetResponse() throws a WebException: "Error: SecureChannelFailure (The authentication or decryption has failed.)". If url is using plain http then the call executes cleanly and returns the expected data.
using System;
using System.IO;
using System.Net;
using Android.App;
using Android.Content.PM;
using Android.OS;
// ...
private string FetchData()
{
// Public test server that's handy for testing JSON code.
// http://jsonplaceholder.typicode.com
string url = "https://jsonplaceholder.typicode.com/posts/1";
// Create an HTTP web request using the URL:
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Timeout = 10 * 1000; // 10 seconds
request.Accept = "application/json";
request.Method = "GET";
string result = "";
try
{
using (WebResponse response = request.GetResponse())
{
result = "Presumably, do something with response.GetResponseStream()";
}
}
catch (Exception ex)
{
result = $"{ex.GetType().Name}: {ex.Message}";
}
return result;
}
The basic pattern there comes from a Xamarin "recipe": Call a REST Web Service. I changed it to be synchronous because when I change request.GetResponse() to request.GetResponseAsync() (and async-await) then the call either times out, or hangs indefinitely, obfuscating the underlying WebException (SecureChannelFailure).
This is a simple HTTP GET, and any browser, or REST/SOAP utility (e.g. "Simple REST Client" for Chrome) can be used to build and send that exact same request, and it works fine with both http and https. Similarly, I can take that code above and paste it into a Windows Console application and it works fine with both http and https.
For the record, love it or hate it, I have also tried adding a delegate of { return true; } to the System.Net.ServicePoint.ServerCertificateAuthenticationCallback event. To me that wouldn't be a solution anyway, but it might help diagnose the problem. Too bad a breakpoint set in that delegate is never tripped, indicating my code never even gets to that point.
It seems impossible to me that invoking web services through https is not supported in a Xamarin Droid app, so I'm going on the assumption that I'm doing something wrong. What could be causing this failure in Xamarin Droid, when it works fine in a browser, and in a plain Windows Console app?
if you call a HTTP url and get this exception , be sure set redirect to false:
request.AllowAutoRedirect = false;
if you call a HTTPS url then put these lines before your request code:
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;

Receiving BAD REQUEST when called Okta API from C# MVC application

I am creating a sample application (i.e., a proof of concept) for creating users with the Okta platform. I am using API calls but consistently receiving "BAD REQUEST" when running the C# MVC application from Visual Studio 2013 update 5 to my Okta development instance. I'm wondering if the problem is between CORS and a local app?
Here is what I have so far:
Tested out the API calls using Postman to my dev environment and the calls work (i.e., users get created in my Okta dev admin environment)
Created an API Token and call it with a prefix of "SSWS" in the Authorization header
Using an HttpClient and .PostAsJsonAsync() method to make the API call
My application code works as expected when calling a GET with the API call /api/v1/users?limit=25 and .GetAsync()
Using the following Api call: /api/v1/users?activate=false (create a user with password; this works in Postman, but not in the MVC app)
Used http://json2csharp.com/ to create C# classes that conform to Okta's JSON hierarchy (obtained from Okta's Postman API libraries)
Using the classes above, the JSON displayed in Visual Studio's Text Viewer (obtained while stepping through the code) works with a POST call when pasted into Postman
HttpResponse contains the error message "The request body was not well-formed"
Here is the code used for creating and serializing (with Json.NET) the C# classes:
RootObject root = new RootObject();
root.profile = new Profile();
root.profile.firstName = model.FirstName;
root.profile.lastName = model.LastName;
root.profile.email = model.Email;
root.profile.login = model.UserName;
root.credentials = new Credentials();
root.credentials.password = new OktaTest.Models.Password();
root.credentials.password.value = model.Password;
string rootJson = JsonConvert.SerializeObject(root);
This produces the following JSON (this contains dummy data):
{"profile":{"firstName":"Test","lastName":"User","email":"user#test.org","login":"user#test.org"},"credentials":{"password":{"value":"Testing123"}}}
Here is the line of code that makes the POST call:
HttpResponseMessage responseMessage = await client.PostAsJsonAsync(url, rootJson);
Here is the line that sets the Accept header:
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
Since I'm able to use the JSON in Postman, and since that JSON comes out as valid when using JSONLint, I'm thinking that the problem is not with the JSON but something around security between my local app and the development environment. Should this test only be run from a hosted application so that a site can be explicitly assigned in the CORS section of the Okta admin environment? At this point, and I'm still researching and experimenting, I'm not sure what I'm missing, but I think I'm close.
Any advice or guidance would be greatly appreciated! Thank you!
I recommend you to use the Okta C# SDK which you can add to your application using the Okta.Core.Client NuGet package.
A sample console app shows how to use it to create Okta users: https://github.com/oktadeveloper/okta-sdk-dotnet-console-user-create
I hope this helps!

HttpClient for C# application

just starting to create an API to my a web application using the ASP.NET MVC4 Web API project template. http://www.asp.net/mvc/mvc4
No problems with the API so far, but I was about to write a small C# app to test the API.
Almost all the sample I can find is using the a class called HttpClient.
Where can I find the HttpClient and how do I install it?
Rather than using the build in HttpClient class of the .NET framework which has a lot of issues when dealing with StatusCodes that are different than the expected ones. I recommend using a library called RestSharp.
It has become .NET Http/Rest client of choice, you can get it here: http://restsharp.org/
It is a very powerful library that is perfectly suited to do what you want.
It's on nuget, search for HttpClient
http://nuget.org/packages/System.Net.Http
Use WebRequest as described here
// Create a new 'Uri' object with the specified string.
Uri myUri =new Uri("http://www.contoso.com");
// Create a new request to the above mentioned URL.
WebRequest myWebRequest= WebRequest.Create(myUri);
// Assign the response object of 'WebRequest' to a 'WebResponse' variable.
WebResponse myWebResponse= myWebRequest.GetResponse();
If its a REST interface use RestSharp but you would need XSD first.
If the class is not available from your code, then you could download it from a NuGet package, like described in the article:
http://code.msdn.microsoft.com/Introduction-to-HttpClient-4a2d9cee
or you can try to locate it inside the namespace: System.Net.Http
There is also an example for you wich should get you started!

Categories

Resources