YouTube Api Xamarin Android App PCL HttpClient issue - c#

I have created a PCL in Visual Studio targeting: .NET 4.5, Windows Phone 8, Windows Store Apps, Xamarin Android and Xamarin iOS.
This PCL integrates with the YouTube Data API v3 via HttpClient requests (have some issues using the client library directly).
I have written and successfully run unit tests which test this integration in Visual Studio (test project referencing PCL project), however, when I consume those methods in a Xamarin Android project (in Xamarin Studio) I am getting a Forbidden 403 error on one of the GET methods (search.list - GetStringAsync below), POST methods appear to work fine.
The method in question is as follows:-
public async Task<Google.Apis.YouTube.v3.Data.SearchListResponse> GetVideosForChannelManual(string channelId, string apiKey, string pageToken)
{
var requestString = "https://www.googleapis.com/youtube/v3/search?part=snippet&maxResults=50";
requestString += "&channelId=" + channelId;
requestString += "&key=" + apiKey;
if (!String.IsNullOrEmpty(pageToken))
{
requestString += "&pageToken=" + pageToken;
}
using (HttpClient client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var task = await client.GetStringAsync(requestString);
var deserializedResponse = JsonConvert.DeserializeObject<Google.Apis.YouTube.v3.Data.SearchListResponse>(task);
return deserializedResponse;
}
}
The detail of the exception is below:-
[0] {System.Net.Http.HttpRequestException: 403 (Forbidden)
at System.Net.Http.HttpResponseMessage.EnsureSuccessStatusCode () [0x00000] in <filename unknown>:0
at System.Net.Http.HttpClient+<GetStringAsync>c__async5.MoveNext () [0x00000] in <filename unknown>:0
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x00000] in <filename unknown>:0
at System.Runtime.CompilerServices.TaskAwaiter`1[System.String].GetResult () [0x00000] in <filename unknown>:0
at YouTubeHelpers.YouTubeRepository+<GetVideosForChannelManual>d__27.MoveNext () [0x000fa] in c:\...\YouTubeRepository.cs:187
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x00000] in <filename unknown>:0
at System.Runtime.CompilerServices.TaskAwaiter`1[Google.Apis.YouTube.v3.Data.SearchListResponse].GetResult () [0x00000] in <filename unknown>:0
at YouTubeHelpers.YouTubeRepository+<GetAllVideosForChannelManual>d__20.MoveNext () [0x00061] in c:\..\YouTubeRepository.cs:160 } System.Net.Http.HttpRequestException
My initial thoughts are that the Http request headers are different when running it on Android compared to directly in VS and so attempted to compare in Fiddler using a reverse proxy on the emulator (problem exists in emulator and on hardware device), but I was unable to get the app to send web traffic through the proxy (even though browser traffic was sent to fiddler correctly).
Presumably the HttpClient handler would have to be set for this proxy, but with limited access to System.Net libraries in the PCL it wasn't clear how to achieve this.
Is there something which I should be setting additionally for these GET requests bearing in mind that in the POST requests (insert like, insert subscription for example) where I explicitly send an OAuth2 token as an authentication header (required) work fine?
Any advice would be appreciated.
UPDATE
Tried using ModernHttpClient, but the exception still persists. Still feel this is something to do with the request headers, but no smoking gun as yet.

So the issue was limited to the YouTube data API and not a generic PCL issue (thankfully). It seems that when making an unauthenticated request to the YouTube API (such as search etc) then you need to use the Web API Key, rather than an Android API key?! Even though when making an authenticated request (using OAuth2) you need to use the Android Key and associate the request with the solutions SHA1 key. Hopefully this may help someone else if they encounter this issue too.
I suppose this does raise the question of why there is an option to add an Android API key for the Public API access when it doesn't appear to work and the Web API key should be used?

Related

Xamarin Android FTP authentication problem on startup

I'm developing an Android application in C# language with Xamarin.
In this application I need a service that starts after the device boot and upload files in a FTP server.
If I start this service with a button click action all works good, but if I use a BroadcastReceiver and I intercept the BOOT_COMPLETED event to start the FTP connection, I receive this error:
ex.Message: The authentication or decryption has failed.
ex.StackTrace: at System.Net.FtpWebRequest.EndGetRequestStream (System.IAsyncResult asyncResult)
at System.Net.FtpWebRequest.GetRequestStream ()
at TestProject.FTPUtility.upload (System.String userName, System.String password, System.String sourceFile, System.String targetFile)
I don't understand why I receive the authentication or decryption error only if the service starts on startup. I tried also to start the connection only after a ping success (to wait the device internet connection) but nothing is changed.
I solved the problem with this line of code:
System.Net.ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };

Mono HTTPS Error - "Error Writing Headers"

Scope:
I am trying to integrate with an external centralized Logging service provider, using HTTPS requests to post the logs to it.
We are running C# on top of Mono, using Ubuntu 14.04 LTS as the OS.
We have been using mono for years already, so we are somehow familiar with it's behaviors and potential flaws / issues.
Previous Setup
When you google this issue, you find basically two solutions to it, and none of them worked to me, for this case. Here's what I have done so far
Basic Mono-Complete Setup + ca-certificates-mono (that would potentially solve HTTPS related issues).
Other than that, I know that mono does not trust any certificate by default, having it's own certificates-chain, and that we have to import them to it. To do that I ran mozroots --import --sync --ask-remove and it printed me that "140 certificates were downloaded and installed".
Aditionally, we overrode the CertificateValidationCallback using this nasty one-liner:
ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => { return true; };
None of the above solved our issue.
Errors, Errors and more Errors:
Note that all of the codes below do work on Windows.
So far we have tried:
Using Native .NET WebClient Async Calls (PostAsync).
As the result, we get errors such as Cant find file system.net.http.dll, and once we actually copy the one from our windows system to it, we get another error Task Exception (can't remember the exact message there).
Using ModernHttpClient
Apparently, using this client on Xamarin programs tend to solve the issues people have, but we still get the same errors listed above, using the standard HttpClient class from .NET
Writing our own WebRequests Wrapper
This was the closest we got to an actual solution, that leads to Error Writing Headers when running it on Mono.
Small Code Sample:
using (WebRequests webClient = new WebRequests ())
{
// Client Configuration
webClient.BufferSize = 32 * 1024;
webClient.Accept = "application/json";
webClient.ContentType = "application/json; charset=" + Encoding.UTF8.HeaderName;
webClient.Timeout = 60000;
webClient.ReadWriteTimeout = 60000;
webClient.Encoding = Encoding.UTF8.WebName;
// Dummy Logz Payload - One Json Per Line
string LogzPayload = "{id:'1', value='1'}\n{id:'2', value='2'}";
// Request to Logz
webClient.Post ("https://listener-4.logz.io:8071/?token=OUR_TOKEN&type=json", LogzPayload);
}
Update 1:
Just tried running the following command and got an exception right away:
certmgr --ssl https://listener-4.logz.io:8071/?token=OUR_TOKEN&type=json --machine
Exception:
Unhandled Exception:
System.IO.IOException: The authentication or decryption has failed. ---> System.IO.IOException: The authentication or decryption has failed. ---> Mono.Security.Protocol.Tls.TlsException: The authentication or decryption has failed.
at Mono.Security.Protocol.Tls.RecordProtocol.EndReceiveRecord (IAsyncResult asyncResult) <0x4192e470 + 0x00132> in <filename unknown>:0
at Mono.Security.Protocol.Tls.SslClientStream.SafeEndReceiveRecord (IAsyncResult ar, Boolean ignoreEmpty) <0x4192e3a0 + 0x00031> in <filename unknown>:0
at Mono.Security.Protocol.Tls.SslClientStream.NegotiateAsyncWorker (IAsyncResult result) <0x4192abb0 + 0x00225> in <filename unknown>:0
--- End of inner exception stack trace ---
I'm not very familiar with Mono but I know that they use their own TLS stack whereas .NET uses the TLS stack from the OS. If I'm correct than the available cipher suites are defined in CipherSuiteFactory.cs which shows that no ECDHE and no DHE ciphers are available. But from what I can see the server supports only ECDHE and DHE ciphers and thus there will be no shared ciphers and the TLS handshake will fail. The ciphers supported by the server are:
ECDHE-RSA-AES256-GCM-SHA384
ECDHE-RSA-AES128-GCM-SHA256
DHE-RSA-AES256-GCM-SHA384
DHE-RSA-AES128-GCM-SHA256
ECDHE-RSA-AES256-SHA384
ECDHE-RSA-AES256-SHA
DHE-RSA-AES256-SHA256
DHE-RSA-AES256-SHA
Most of these are ciphers need TLS 1.2 which is not supported by Mono at all (see State of TLS in Mono). But even the rest is DHE or ECDHE only which Mono does not seem to support. They are actively working on a new TLS stack but it looks like it is not done yet.
If you have access to the server you might try to configure the cipher AES256-SHA which is probably the best cipher currently supported by Mono.
I recommend you to switch to Ubuntu 16.04 because that brings a version of Mono's packages that syncs certificates by default and therefore you don't need to run mozroots, and you will more likely to not have problems around this area.

ParseExceptions not getting thrown for CallFunctionAsync

I recently updated my client sdk to parse 1.6.2 for xamarin, and I noticed that ParseExceptions are no longer getting thrown properly.
When calling something like this:
string result = await ParseCloud.CallFunctionAsync<string>( "function" )
If that function calls response.error I get:
System.Net.WebException The remote server returned an error: (400) Bad Request.
Raw
at System.Net.HttpWebRequest.EndGetResponse (IAsyncResult asyncResult) [0x0005e] in /Users/builder/data/lanes/2377/73229919/source/maccore/_build/Library/Frameworks/Xamarin.iOS.framework/Versions/git/src/mono/mcs/class/System/System.Net/HttpWebRequest.cs:944
Where as in the pass it would generate a ParseException with the contents of the response.error. The WebException also does not have an inner exception to inspect.
I also thought it had something to do with my cloud code, but I find a similar problem with user login. A bad password generates this exception now:
System.Net.WebException The remote server returned an error: (404) Not Found.
Raw
at System.Net.HttpWebRequest.EndGetResponse (IAsyncResult asyncResult) [0x0005e] in /Users/builder/data/lanes/2377/73229919/source/maccore/_build/Library/Frameworks/Xamarin.iOS.framework/Versions/git/src/mono/mcs/class/System/System.Net/HttpWebRequest.cs:944
A few other things were upgraded when I updated the parse sdk. I'm now using xamarin forms 2.* instead of 1.5.* and I think the mono system libraries were also updated.

Timeout Exception: Calling Soap API from Within a REST API

I have a very odd problem. I have a REST API that uses ServiceStack that does a few things like save payment data etc. From within that API I start building payment object so I can fire off a payment to a Payment Gateway. This payment gateway is a Soap API Using SoapHttpClientProtocol.
The problem I am having is that the Soap API Times out. I have a stack trace that lead me to believe it is happening inside the framework somewhere.
System.Net.WebException: Error: ConnectFailure (Connection timed out) ---> System.Net.Sockets.SocketException: Connection timed out
at System.Net.Sockets.Socket.Connect (System.Net.EndPoint remoteEP) [0x00000] in <filename unknown>:0
at System.Net.WebConnection.Connect (System.Net.HttpWebRequest request) [0x00000] in <filename unknown>:0
--- End of inner exception stack trace ---
at System.Net.HttpWebRequest.EndGetRequestStream (IAsyncResult asyncResult) [0x00000] in <filename unknown>:0
at System.Net.HttpWebRequest.GetRequestStream () [0x00000] in <filename unknown>:0
at System.Web.Services.Protocols.SoapHttpClientProtocol.Invoke (System.String method_name, System.Object[] parameters) [0x00000] in <filename unknown>:0
Above is the exception I got so I believe it is happening inside the Invoke method. Here is the code which is in the proxy file.
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("paymenturl", RequestNamespace="gatewayurl", ResponseNamespace="gatewayurl", ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped, Use=System.Web.Services.Description.SoapBindingUse.Literal)]
public string SubmitPayment(string trnXML) {
object[] results = this.Invoke("SubmitPayment", new object[] {
trnXML});
return ((string)(results[0]));
}
Does anyone know why this would happen?
Now the SOAP Payment API works though the UI. So if call it straight from the UI I can make a payment and get a successful response back. When I do it from the API it doesn't work.
Is this perhaps a Architectural problem which does not allow an API call from within another API?
Has anyone come across anything like this before?
Any help will appreciated.
Found the problem. It was because there was a mono.security.dll in my bin folder. This is not needed apparently so removed it. Once I did that it worked.
Credit goes to this Post: Mono Apache2 HttpWebRequest crashes with "The request timed out"

HttpWebRequest NameResolutionFailure exception in .NET (with Mono on Ubuntu)

I have a .NET program running on Ubuntu via Mono 2.10
The program downloads a webpage via an HttpWebRequest every minute or so which works fine most of the time:
String result;
WebResponse objResponse;
WebRequest objRequest = System.Net.HttpWebRequest.Create(url);
using (objResponse = objRequest.GetResponse())
{
using (StreamReader sr =
new StreamReader(objResponse.GetResponseStream()))
{
result = sr.ReadToEnd();
// Close and clean up the StreamReader
sr.Close();
}
}
The problem is that after few days I start getting exceptions thrown:
DateTime: 01/25/2012 08:15:41
Type: System.Net.WebException
Error: Error: NameResolutionFailure
Stack:
at System.Net.HttpWebRequest.EndGetResponse (IAsyncResult asyncResult) [0x00000] in <filename unknown>:0
at System.Net.HttpWebRequest.GetResponse () [0x00000] in <filename unknown>:0
at socks_server.Program.readHtmlPage (System.String url) [0x00000] in <filename unknown>:0
at socks_server.Program.getAccessKeysProc () [0x00000] in <filename unknown>:0
The server is still abel to resolve DNS, for example
wget http://www.google.com
Will return the file without any probelm as will ping and other commands that resolve DNS.
My program however will continue to throw that exception until I restart it. After restarting the application it will start working again as it should.
I have checked open file counts on the system (400 ish), memory usage (327mb of 4gb), CPU usage (2-3%) and all are OK.
Any ideas?
You can solve it by translating the host name to ip and add the host name to Headers collection or to Host property.
If your url is http://example.com/uri. Resolve the host yourself. Suppose its 1.2.3.4. It'll be http://1.2.3.4/uri. Now add Host: example.com header to your request. I think it can be done by setting HttpWebRequest.Host property.
I know this is an old post, but was facing the same error, so thought to share the solution.
The best solution I found, when that exception occurs while the Wifi
is connected, is just to retry my server call with a slight sleep in
between. It works most of the time, otherwise if the second call
fails I cancel the request.
This error can also raise if the user's Wifi is very unstable or the
signal is very low. The same error occurs if there is no internet
connection at all, even if connected to Wifi.
This is in line with my ans on :
System.Net.WebException: Error: NameResolutionFailure when Calling WCF Services throwing exception in mono android application
Well I use the HttpClient - but it might be a similar problem. I had the same issue on a Android device (it worked on a Windows Phone)... But after I added the Host to the header it worked!
client.DefaultRequestHeaders.Host = "mydomain.com";
You can still use the name in the url (you don't have to use the IP address)
I was experiencing the same issue in my mono application on raspbian. I've tried different solutions described in this and other threads but none worked. Eventually, I was able to fix the problem by changing the name servers in /etc/resolv.conf to the google ones https://developers.google.com/speed/public-dns/
Mirko
I was getting this error when I started the mobile app (android or iOS it does not matter) without internet connection. After restored the connection every request returns "NameResolutionFailure exception". I had to wait 120 seconds for having the http request working again. Setting the following line of code anywhere in the app startup the error was finally gone.
System.Net.ServicePointManager.DnsRefreshTimeout = 0;
The default DnsRefreshTimeout value is 120 seconds.

Categories

Resources