I have 2 Applications here. One is a Xamarin Application and the other is a Asp.Net MVC Application which has the WebApi to connect to a SqlServer Database "where the database is on a Hosted Website of like some IP Address xxx.xxx.xxx.xxx" .
I run the MVC application Locally to IIS, and then Once the Website is Up in IIS, I run the Xamarin Application from the second instance of Visual Studio.
Firstly I don't think the MVC WebApi gets called, because I tried putting Breakpoints there and it does not come there. I don't know why. Because I had done the same thing with a Winforms and MVC application (WebApi), then at least the WebApi was getting called which I saw with breakpoints in the MVC application.
Now in Xamarin I am getting this error
System.Net.Http.HttpRequestException: 'Network subsystem is down'
in the line
var responseTask = await client.GetAsync("ConnectToAscDatabase");
I have this code in Xamarin Application's MainPage.cs
private async void Button_OnClicked(object sender, EventArgs e)
{
HttpClientHandler handler = new HttpClientHandler();
handler.UseDefaultCredentials = true;
using (var client = new HttpClient(handler))
{
client.BaseAddress = new Uri("http://localhost:49252/api/");
// !!! This Line gives the error System.Net.Http.HttpRequestException: 'Network subsystem is down'
var responseTask = await client.GetAsync("ConnectToAscDatabase");
var readTask = responseTask.Content.ReadAsAsync<Microsoft.Data.SqlClient.SqlConnection>();
SqlConnection con = readTask.Result;
var staty = con.State;
}
}
and this is a WebApi
public class ConnectToAscDatabaseController : ApiController
{
public async Task<Microsoft.Data.SqlClient.SqlConnection> Get()
{
string SqlServer_ServerPath_Server = "SomeServer";
string SqlServer_Database_Server = "SomeDatabase";
string SqlServer_User_Server = "SomeUser";
string SqlServer_Password_Server = "SomePassword";
int timeOutInSeconds = 15;
string connectionString = "data source=" + SqlServer_ServerPath_Server + ";" + "initial catalog=" + SqlServer_Database_Server + ";" + "user id=" + SqlServer_User_Server + ";" + "Password=" + SqlServer_Password_Server + ";" + "Trusted_Connection=false" + ";" + "Connection Timeout=" + timeOutInSeconds + ";" + "Persist Security Info=False";
SqlConnection con = new SqlConnection(connectionString);
con.Open();
return con;
}
}
From this documentation, Android's Network Address Space is responsible as there is no direct connection from the emulator to your local machine, except with the IP Address "10.0.2.2". You can attach your port number to target whatever services you are trying to reach.
It is also worth noting that for service running with self-signed certificates, you still may not get a connection because of trust issues as Android and IOS will not honor connections to services running with self-signed certificates. Read more from here.
I use the following codes to resolve those issues (On Android):
Shared Project (Add the following interface):
using System.Net.Http;
namespace DemoApp.Services
{
public interface IHttpClientHandlerService
{
HttpClientHandler GetInsecureHandler();
}
}
Android Project (Add the following class):
using DemoApp.Droid.Services;
using DemoApp.Services;
using System.Net.Http;
using Xamarin.Forms;
[assembly: Dependency(typeof(HttpClientHandlerService))]
namespace DemoApp.Droid.Services
{
public class HttpClientHandlerService : IHttpClientHandlerService
{
public HttpClientHandler GetInsecureHandler()
{
HttpClientHandler handler = new HttpClientHandler
{
ServerCertificateCustomValidationCallback = (message, cert, chain, errors) =>
{
if (cert.Issuer.Equals("CN=localhost"))
return true;
return errors == System.Net.Security.SslPolicyErrors.None;
}
};
return handler;
}
}
}
Now from within your codes you can create a new HttpClient using the following:
#if DEBUG
HttpClientHandler insecureHandler = DependencyService.Get<IHttpClientHandlerService>().GetInsecureHandler();
HttpClient client = new HttpClient(insecureHandler);
#else
HttpClient client = new HttpClient();
#endif
Note: There are better ways of creating an HttpClient (like using dependency injection and IHttpClientFactory) and it is up to the reader to use what suites them best.
For the BaseAddress of HttpClient, you can use the following code as well:
public static string BaseAddress =
DeviceInfo.Platform == DevicePlatform.Android ? "http://10.0.2.2:5000" : "http://localhost:5000";
public static string TodoItemsUrl = $"{BaseAddress}/api/todoitems/";
where port 5000 may be the port to reach your service and todoitems may be the api url to invoke.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With