WP8 C# communicate with web server over SSL - c#

I have been struggling the entire day to get my C# Windows Phone 8 to talk to my PHP web server over SSL (HTTPS). My server is implemented in such a way that it reads the GET parameters sent to it and then echos an appropriate response. It already works fine in the Windows Phone internet browser by going to https://sub.mysite.com/mypage.php?param=value but for the likes of me I cannot get it to work with my app.
Now I should mention that the server has a self-signed certificate which I have included with my application and at first start up I prompt the user to install the certificate using:
await Launcher.LaunchFileAsync(await Package.Current.InstalledLocation.GetFileAsync("server.cer"));
This seems to work fine because after the certificate is installed Internet Explorer on the device does not warn me about an uncertified certificate anymore.
The thing is though that trying to access the server via either WebClient or WebRequest both give me this error:
An exception of type 'System.Net.WebException' occurred in System.Windows.ni.dll and wasn't handled before a managed/native boundary
An exception of type 'System.Net.WebException' occurred in System.Windows.ni.dll and wasn't handled before a managed/native boundary
'TaskHost.exe' (CLR C:\windows\system32\coreclr.dll: Silverlight AppDomain): Loaded 'C:\windows\system32\en-US\System.debug.resources.DLL'. Module was built without symbols.
A first chance exception of type 'System.Reflection.TargetInvocationException' occurred in System.ni.dll
An exception of type 'System.Reflection.TargetInvocationException' occurred in System.ni.dll and wasn't handled before a managed/native boundary
System.Reflection.TargetInvocationException: An exception occurred during the operation, making the result invalid. Check InnerException for exception details. ---> System.Net.WebException: The remote server returned an error: NotFound. ---> System.Net.WebException: The remote server returned an error: NotFound.
at System.Net.Browser.ClientHttpWebRequest.InternalEndGetResponse(IAsyncResult asyncResult)
at System.Net.Browser.ClientHttpWebRequest.<>c_DisplayClasse.b_d(Object sendState)
at System.Net.Browser.AsyncHelper.<>c_DisplayClass1.b_0(Object sendState)
--- End of inner exception stack trace ---
at System.Net.Browser.AsyncHelper.BeginOnUI(SendOrPostCallback beginMethod, Object state)
at System.Net.Browser.ClientHttpWebRequest.EndGetResponse(IAsyncResult asyncResult)
at System.Net.WebClient.GetWebResponse(WebRequest request, IAsyncResult result)
at System.Net.WebClient.DownloadBitsResponseCallback(IAsyncResult result)
--- End of inner exception stack trace ---
at System.ComponentModel.AsyncCompletedEventArgs.RaiseExceptionIfNecessary()
at System.Net.DownloadStringCompletedEventArgs.get_Result()
at HttpsDing.MainPage.client_DownloadStringCompleted(Object sender, DownloadStringCompletedEventArgs e)
The implementation for both of them though work fine when accessing a normal site like http://bing.com or even https://bing.com.
The code for the webclient method is:
WebClient client = new WebClient();
client.DownloadStringAsync(new Uri("https://sub.mysite.com"));
client.DownloadStringCompleted += client_DownloadStringCompleted;
And the code for the webrequest is:
public static class Extensions
{
public static System.Threading.Tasks.Task<System.IO.Stream> GetRequestStreamAsync(this System.Net.WebRequest wr)
{
if (wr.ContentLength < 0)
{
throw new InvalidOperationException("The ContentLength property of the WebRequest must first be set to the length of the content to be written to the stream.");
}
return Task<System.IO.Stream>.Factory.FromAsync(wr.BeginGetRequestStream, wr.EndGetRequestStream, null);
}
public static System.Threading.Tasks.Task<System.Net.WebResponse> GetResponseAsync(this System.Net.WebRequest wr)
{
return Task<System.Net.WebResponse>.Factory.FromAsync(wr.BeginGetResponse, wr.EndGetResponse, null);
}
}
And then:
await AuthenticateAsync();
This is all rather confusing to me, any ideas?

Related

C# REST - Send Request Body, Receive Response Body

I'm using the WebClient class. I've had some luck with the OpenReadTaskAsync method with a GET, but right now, I want to call a POST, or PUT REST method. I figured that I should use UploadStringTaskAsync. But, when I call this method on a working REST service, I get this error:
System.Net.WebException: An exception occurred during a WebClient request. ---> System.NotSupportedException: Specified method is not supported on this request.
at System.Net.Browser.BrowserHttpWebRequest.set_Method(String value)
at System.Net.WebClient.GetWebRequest(Uri address)
at System.Net.WebClient.UploadStringAsync(Uri address, String method, String data, Object userToken)
--- End of inner exception stack trace ---
at Microsoft.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at Microsoft.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccess(Task task)
at Microsoft.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at CF.RESTClientDotNet.Silverlight.Sample.MainPage.d__3.MoveNext()
This is the code
var webClient = new WebClient();
var returnValue = await webClient.UploadStringTaskAsync(uri.AbsoluteUri, "POST", bodyString);
I ended up completely redesigning my library. There are samples here:
https://bitbucket.org/MelbourneDeveloper/restclient-.net/src/master/
NuGet: Install-Package RESTClient.NET

ASP.NET Web.API - An existing connection was forcibly closed by the remote host

After reading countless posts on Stack Overflow I figured it would hurt to throw this out there to see if anyone can help me out...
I have an ASP.NET Web.API released. I also have a Windows Service released on a ship that has a very slow Internet connection (and often none at all).
The service runs on a timer and, once the timer elapses, start off verifying that it is able to connect to my API.
// Verify the remote connection via the RAC Sync Service
public bool CheckConnection()
{
//using (HttpClient c = new HttpClient())
//{
HttpClient c = new HttpClient();
log.Debug("Verifying the remote connection");
c.Timeout = new TimeSpan(0, 0, 10, 0);
c.BaseAddress = new Uri(ConfigurationManager.AppSettings["RACAPIAddress"]);
var userID = Int32.Parse(ConfigurationManager.AppSettings["userID"]);
//log.Debug("Attempting to connect using " + ".../api/RAC/CheckConnection?userID=" + userID);
//var result = c.GetAsync(String.Format(#"/api/RAC/CheckConnection?userID={0}", userID)).Result;
//log.Debug("Finished the attempt");
//log.Debug("Reading the string");
//var content = result.Content.ReadAsStringAsync().Result;
var httpRequest = new HttpRequestMessage();
httpRequest.Version = HttpVersion.Version10;
httpRequest.RequestUri = new Uri(ConfigurationManager.AppSettings["RACAPIAddress"] + "/api/RAC/CheckConnection?userID=" + userID);
httpRequest.Headers.Add("Connection", new[] { "Keep-Alive" });
var result = c.SendAsync(httpRequest).Result;
var content = result.Content.ReadAsStringAsync().Result;
c.Dispose();
if (result.IsSuccessStatusCode)
{
log.Debug("Received a status success code");
var response = JsonDeserialize<string>(content);
log.Debug(response);
return true;
}
else
{
log.Debug("Received Status Code: " + result.StatusCode.ToString());
var error = result.Headers.FirstOrDefault(x => x.Key == "Error").Value.FirstOrDefault();
throw new Exception("CheckConnection() failed with message " + error);
}
//}
}
When I use Remote Desktop Connection to view the logs I'm seeing this:
2015-04-01 17:02:44,546 [4] DEBUG Logger Sync Service started
2015-04-01 17:02:44,562 [4] DEBUG Logger The sleep time is set to expire every 5 seconds
2015-04-01 17:02:49,578 [4] DEBUG Logger Sleep time expired
2015-04-01 17:02:49,593 [4] DEBUG Logger Verifying the remote connection
2015-04-01 17:02:51,234 [4] ERROR Logger One or more errors occurred.
2015-04-01 17:02:51,250 [4] ERROR Logger System.AggregateException: One or more errors occurred. ---> System.Net.Http.HttpRequestException: An error occurred while sending the request. ---> System.Net.WebException: The underlying connection was closed: An unexpected error occurred on a receive. ---> System.Net.Http.HttpRequestException: An error occurred while sending the request. ---> System.Net.WebException: The underlying connection was closed: ---> System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host
at System.Net.Sockets.Socket.EndReceive(IAsyncResult asyncResult)
at System.Net.Sockets.NetworkStream.EndRead(IAsyncResult asyncResult)
--- End of inner exception stack trace ---
at System.Net.Sockets.NetworkStream.EndRead(IAsyncResult asyncResult)
at System.Net.PooledStream.EndRead(IAsyncResult asyncResult)
at System.Net.Connection.ReadCallback(IAsyncResult asyncResult)
--- End of inner exception stack trace ---
at System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult)
at System.Net.Http.HttpClientHandler.GetResponseCallback(IAsyncResult ar)
--- End of inner exception stack trace ---
--- End of inner exception stack trace ---
at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
at System.Threading.Tasks.Task.Wait(Int32 millisecondsTimeout, CancellationToken cancellationToken)
at System.Threading.Tasks.Task`1.get_Result()
at RAC.SyncService.SyncService.CheckConnection()
at RAC.SyncService.SyncService.TimerElapsed(Object sender, ElapsedEventArgs args)
---> (Inner Exception #0) System.Net.Http.HttpRequestException: An error occurred while sending the request. ---> System.Net.WebException: The underlying connection was closed: An unexpected error occurred on a receive. ---> System.IO.IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host. ---> System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host
at System.Net.Sockets.Socket.EndReceive(IAsyncResult asyncResult)
at System.Net.Sockets.NetworkStream.EndRead(IAsyncResult asyncResult)
--- End of inner exception stack trace ---
at System.Net.Sockets.NetworkStream.EndRead(IAsyncResult asyncResult)
at System.Net.PooledStream.EndRead(IAsyncResult asyncResult)
at System.Net.Connection.ReadCallback(IAsyncResult asyncResult)
--- End of inner exception stack trace ---
at System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult)
at System.Net.Http.HttpClientHandler.GetResponseCallback(IAsyncResult ar)
--- End of inner exception stack trace ---<---
Oddly enough, if I attempt to call the CheckConnection function while remoted in (using a browser) everything looks normal. The ship has Internet connection and the response is returned. Any ideas out there?
I've tried (from other posts):
- Adding logging (see above)
- Removing my using block and calling dispose instead
- Using a webRequest as opposed to httpClient
- Adding HttpVersion.Version10
- Including "Keep-Alive"
- Maxing the timeouts and file sizes both on the client and server
Could there be a firewall preventing my call? If so, why would I be able to do it using a browser?
Any help with this would be GREATLY appreciated.

Windows Phone Web Exception 404 not found but server gets requests

As the title says I am trying to run a Windows Phone App which is supposed to communicate with a Restful API(running on localhost). My server is actually getting my Http requests but Visual Studio keeps throwing this error:
"The remote server returned an error: NotFound."
private void connect_tap(object sender, System.Windows.Input.GestureEventArgs e)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.BeginGetResponse(GetResponseCallback, request);
}
void GetResponseCallback(IAsyncResult result)
{
HttpWebRequest request = result.AsyncState as HttpWebRequest;
if (request != null)
{
WebResponse response = request.EndGetResponse(result);
Stream streamResponse = response.GetResponseStream();
StreamReader streamRead = new StreamReader(streamResponse);
string read = streamRead.ReadToEnd();
Dispatcher.BeginInvoke(() =>
{
MessageBox.Show(read);
NavigationService.Navigate(new Uri("/MainPage.xaml", UriKind.Relative));
});
streamResponse.Close();
streamRead.Close();
response.Close();
}
}
This is the full error:
{System.Net.WebException: The remote server returned an error: NotFound. ---> System.Net.WebException: The remote server returned an error: NotFound.
at System.Net.Browser.ClientHttpWebRequest.InternalEndGetResponse(IAsyncResult asyncResult)
at System.Net.Browser.ClientHttpWebRequest.<>c__DisplayClasse.b__d(Object sendState)
at System.Net.Browser.AsyncHelper.<>c__DisplayClass1.b__0(Object sendState)
--- End of inner exception stack trace ---
at System.Net.Browser.AsyncHelper.BeginOnUI(SendOrPostCallback beginMethod, Object state)
at System.Net.Browser.ClientHttpWebRequest.EndGetResponse(IAsyncResult asyncResult)
at IonisSphere.Connect.GetResponseCallback(IAsyncResult result)
at System.Net.Browser.ClientHttpWebRequest.<>c__DisplayClass1d.b__1b(Object state2)}
The Web Exception occurs at the EndGetResponse() call. I removed the try/catch around to see the error but when it's there it always goes in the catch section and nothing happens.
I don't understand what is it not finding since my server gets my requests ...
It works fine with Postman by the way. I also tried with a POST method but got exactly the same result.
I'm stuck with this since a few days and I couldn't find anyhing helpful on the internet. I am quite new on Windows Phone and I know this is propably a stupid mistake but thanks in advance for the ones who will try to teach me =)

Windows Phone - failing to get a string from a website with login information

I am new to accessing web services with Windows Phone 7/8. I'm using a WebClient to get a string from a php-website. The site returns a JSON string but at the moment I'm just trying to put it into a TextBox as a normal string just to test if the connection works.
The php-page requires an authentication and I think that's where my code is failing. Here's my code:
WebClient client = new WebClient();
client.Credentials = new NetworkCredential("myUsername", "myPassword");
client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(client_DownloadStringCompleted);
client.DownloadStringAsync(new Uri("https://www.mywebsite.com/ba/php/jsonstuff.php"));
void client_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
try
{
string data = e.Result;
this.jsonText.Text = data;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
}
This returns first a WebException and then a TargetInvocationException. If I replace the Uri with for example "http://www.google.com/index.html" the jsonText TextBox gets filled with html text from Google (oddly enough, this also works even when the WebClient credentials are still set).
So is the problem in the setting of the credentials? I couldn't find any good results when searching for guides on how to access php-pages with credentials, only without them. Then I found a short mention somewhere to use the WebClient.Credentials property. But should it work some other way?
Update: here's what I can get out of the WebException (sorry for the bad formatting):
System.Net.WebException: The remote server returned an error: NotFound. --->System.Net.WebException: The remote server returned an error: NotFound.
at System.Net.Browser.ClientHttpWebRequest.InternalEndGetResponse(IAsyncResult asyncResult)
at System.Net.Browser.ClientHttpWebRequest.<>c_DisplayClasse.b_d(Object sendState)
at System.Net.Browser.AsyncHelper.<>c_DisplayClass1.b_0(Object sendState)
--- End of inner exception stack trace ---
at System.Net.Browser.AsyncHelper.BeginOnUI(SendOrPostCallback beginMethod, Object state)
at System.Net.Browser.ClientHttpWebRequest.EndGetResponse(IAsyncResult asyncResult)
at System.Net.WebClient.GetWebResponse(WebRequest request, IAsyncResult result)
at System.Net.WebClient.DownloadBitsResponseCallback(IAsyncResult result)
Update 2: Here's the error log line:
Nov 16 17:51:12 myservice httpd[21036]: 127.0.0.1 - - [16/Nov/2012:17:51:12 +0200] "GET /ba/php/jsonstuff.php?origpath=/ba/php/jsonstuff.php HTTP/1.1" 401 290 "-" "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)"
401 I guess would suggest false credentials?
In my opininion you really need to see how the server handles your request. "NotFound" in WebException could mean that you're referring to a location that doesn't exist. But I'm sure that you pass the right URL. So there must be some logic on the server that redirects you.
If you go to the url using your desktop browser - do you have any kind of SSL certificate error or warning? Maybe that's the reason. Try navigating on your phone using IE.
Or you could set up another host just to give it a try.
I'll set up a host on my machine and try it.
The problem is with the SSL certificate I guess. WP is very strict when it goes to checking SSL certificates, so you should try without ssl or install cert on your emulator/phone or install valid (not self generated) cert on your server.
Okay, so I found a way to get this working. The problem was that the WebClient class couldn't properly handle the cookies of the web service.
After some Google searches I found this solution and it works perfectly:
http://firebelly.net/post/3341374382/cookie-aware-webclient-for-wp7
So basically you just make your own client class that extends the WebClient class which can store cookies.

WCF and What does this mean?

I have a WCF where all the calls work. All of them to silver light. But this one call it says it cannot find, yet it exists and it also shows silver light side. I am stumped for the lat 4 hours. Any ideas?
This works:
_client.GetHandSetsCompleted += new EventHandler<GetHandSetsCompletedEventArgs>(_client_GetHandSetsCompleted);
_client.GetMarketsCompleted += new EventHandler<GetMarketsCompletedEventArgs>(_client_GetMarketsCompleted);
_client.GetCountByKeyCompleted += new EventHandler<GetCountByKeyCompletedEventArgs>(_client_GetCountByKeyCompleted);
_client.GetHandSetsAsync();
_client.GetMarketsAsync();
But as soon as I hit this:
private void UsrExchangeExportClicked(object sender, ExchangeQuerySetArg e)
{
XchangeQuerySet x = new XchangeQuerySet();
x.End = e.End;
x.Start = e.Start;
x.Handset = e.Handset;
//x.Markets = new ObservableCollection<int>(e.Markets);
_client.GetCountByKeyAsync(x);
}
It throws the error. Makes no sense.
System.ServiceModel.CommunicationException was unhandled by user code
Message=The remote server returned an error: NotFound.
StackTrace:
at System.ServiceModel.AsyncResult.End[TAsyncResult](IAsyncResult result)
at System.ServiceModel.Channels.ServiceChannel.EndCall(String action, Object[] outs, IAsyncResult result)
at System.ServiceModel.ClientBase`1.ChannelBase`1.EndInvoke(String methodName, Object[] args, IAsyncResult result)
at ExWarranty.XchangeRef.XchangeServiceClient.XchangeServiceClientChannel.EndGetCountByKey(IAsyncResult result)
at ExWarranty.XchangeRef.XchangeServiceClient.ExWarranty.XchangeRef.IXchangeService.EndGetCountByKey(IAsyncResult result)
at ExWarranty.XchangeRef.XchangeServiceClient.OnEndGetCountByKey(IAsyncResult result)
at System.ServiceModel.ClientBase`1.OnAsyncCallCompleted(IAsyncResult result)
InnerException: System.Net.WebException
Message=The remote server returned an error: NotFound.
StackTrace:
at System.Net.Browser.AsyncHelper.BeginOnUI(SendOrPostCallback beginMethod, Object state)
at System.Net.Browser.BrowserHttpWebRequest.EndGetResponse(IAsyncResult asyncResult)
at System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelAsyncRequest.CompleteGetResponse(IAsyncResult result)
InnerException: System.Net.WebException
Message=The remote server returned an error: NotFound.
StackTrace:
at System.Net.Browser.BrowserHttpWebRequest.InternalEndGetResponse(IAsyncResult asyncResult)
at System.Net.Browser.BrowserHttpWebRequest.<>c__DisplayClass5.<EndGetResponse>b__4(Object sendState)
at System.Net.Browser.AsyncHelper.<>c__DisplayClass4.<BeginOnUI>b__1(Object sendState)
InnerException:
Are you able to browse or hit the "GetCountByKeyAsync" web method from Fiddler or IE.
Try to generate a request and hit the method from fiddler and see if you get back a success response. If that works then inspect the request from the application through fiddler to see what is causing the issue.
Make sure that the object being passed "XchangeQuerySet" is serializable.
Also to get some info on server side you can enable tracing. To enable tracing follow this link.
It means that there might be an error on WCF server side. Try checking activity tracing or eventlog for more info.
Also check a possible duplicate question

Categories