Xamarin Forms HttpClient GetAsync Fails in iOS Only - xamarin

I have a very simple REST query to our WebAPI back end (used by a number of applications) and it works fine under Android and Windows but in iOS it fails with an "Object reference not set to an instance of an object" error. In the code below, both moHttpClient and loUri are instantiated. I've tried wrapping the call to GetEmployeeRecord in Device.BeginInvokeOnMainThread but that doesn't help either. I have upgraded to the latest stable version of Xamarin in Visual Studio and on my Mac. Why is it working in the other OSs but not iOS?
private async void btnTest_Clicked(object sender, EventArgs e)
{
await GetEmployeeRecord();
}
private async Task GetEmployeeRecord()
{
try
{
var loUri = new Uri("https://my.website.com/mobile.webapp/api/employees?key=6c6f2c06-a444-4e54-bd77-b5f594c29910");
var loResponse = await moHttpClient.GetAsync(loUri);
if (loResponse.IsSuccessStatusCode)
{
var lcJson = await loResponse.Content.ReadAsStringAsync();
await DisplayAlert("Employee", lcJson, "OK");
}
}
catch (Exception ex)
{
Device.BeginInvokeOnMainThread(() =>
{
DisplayAlert("Get Employee Record", ex.Message, "OK");
});
}
}
Using a breakpoint at the GetAsync line, both moHttpClient and loUri are instantiated. However, mousing over GetAsync gives a message that GetAsync is an unknown member. How can that be?
I just checked and it seems this Unknown member occurs with Android too. But with Android it actually executes.

In order to get the http query to work for iOS I had to install the NuGet package Microsoft.Net.Http in the PCL project, which is where the code is running.

Related

How to open microsoft powerpoint app using launcher class(xamarin.essentials)?

private async void SlidesCommandTapped(object obj)
{
if (!await Launcher.TryOpenAsync("com.microsoft.office.powerpoint://"))
{
await Launcher.OpenAsync(new Uri("market://details?id=com.microsoft.office.powerpoint"));
}
}
tryopenasync now working
if microsoft powerpoint app not present it opens playstore and tells you to install powerpoint app but right now if the app is installed too its going to playstore
Well your code should look something like below:
var isPowerPointAvailable = await Launcher.TryOpenAsync("com.microsoft.office.powerpoint://");
if (isPowerPointAvailable)
{
// this would change based on what file you want to open
await Launcher.OpenAsync("com.microsoft.office.powerpoint://");
}
else
{
await Launcher.OpenAsync(new Uri("market://details?id=com.microsoft.office.powerpoint"));
}
Goodluck,
Feel free to get back if you have queries

Connecting to localhost with Restsharp on Android

I created a Web API and would like to access it in my Android XAMARIN App. It's a XAMARIN Forms App, which references a .NET Standard 2.0 library with the newest RestSharp nuget package installed.
Unfortunately I get the error:
Error: ConnectFailure (No route to host)
whenever I do the following:
public async Task<List<ETFPortfolio>> GetPortfolios()
{
var client = new RestClient("http://10.0.2.2:51262/api/");
var request = new RestRequest("portfolio", Method.GET);
request.AddHeader("Accept", "application/json");
var response = client.Execute(request); // Result with the error stated above
throw new Exception();
}
My WebAPI controller is set up like this:
[Route("api/[controller]")]
public class PortfolioController : Controller
{
// GET api/portfolio
[HttpGet]
public async Task<IActionResult> Get()
{
try
{
var handler = new MyHandler();
var portfolioList = await handler.Handle();
return Ok(portfolioList);
}
catch (Exception ex)
{
return BadRequest(ex.Message);
}
}
I found a similar question, unfortunately there were no answers yet.
Error: ConnectFailure (No route to host)
Is there anything I'm missing here or could check out to make this work?
Since you are using a real device, your API url should not be a localhost but an IP address of the computer on which you have the API running.
localhost will work only on the emulator running on the same machine with your API.
P.S.: I wrote a blogpost on this topic, you might be interested in checking it as well.

System.MissingMethodException Method 'System.Net.Http.HttpClientHandler.set_Proxy' not found

This is a Xamarin solution and I am getting the error found in this message's title. Of course, I can easily confirm that there is a Proxy property on HttpClientHandler in the PCL project. And the solution builds without error. Only when I run does it produce this error (on either Droid or iOS) and does so at the point where it invokes the method in the PCL which instantiates the HttpClient. Note that it doesn't even get to that method. The error appears on the application start-up method; e.g., UIApplication.Main()
If I comment out the handler and instantiate HttpClient without a handler, it works fine as long as I'm on the open internet. But I'm trying to get this to work from behind a proxy.
Further investigation showed that the device projects had no references to System.Net.Http. So I added these -- and it indicates Xamarin.iOS and Xamarin.Android as the packages -- but it still produces the error.
I'm not clear what the error is telling me but I believe it means that the device project can't see System.Net.Http.HttpClientHandler?
private HttpClient GetHttpClient()
{
WebProxy proxy = new WebProxy(ProxyConfig.Url)
{
Credentials = new NetworkCredential(ProxyConfig.Username, ProxyConfig.Password)
};
// At runtime, when GetHttpClient is invoked, it says it cannot find the Proxy setter
HttpClientHandler handler = new HttpClientHandler
{
Proxy = proxy,
UseProxy = true,
PreAuthenticate = true,
UseDefaultCredentials = false,
};
HttpClient client = new HttpClient(handler);
// This works when not behind a proxy
//HttpClient client = new HttpClient();
return client;
}
public async Task GetWeatherAsync(double longitude, double latitude, string username)
{
// MissingMethodException is thrown at this point
var client = GetHttpClient();
client.BaseAddress = new Uri(string.Format("http://api.geonames.org/findNearByWeatherJSON?lat={0}&lng={1}&username={2}", latitude, longitude, username));
try
{
var response = await client.GetAsync(client.BaseAddress);
if (response.IsSuccessStatusCode)
{
var JsonResult = response.Content.ReadAsStringAsync().Result;
var weather = JsonConvert.DeserializeObject<WeatherResult>(JsonResult);
SetValues(weather);
}
else
{
Debug.WriteLine(response.RequestMessage);
}
}
catch (HttpRequestException ex)
{
Debug.WriteLine(ex.Message);
}
catch (System.Net.WebException ex)
{
Debug.WriteLine(ex.Message);
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
Add the Microsoft.Net.Http NuGet package to your platform project too. If you run into an issue adding this, try installing the latest Microsoft.Bcl.Build package first. Then, after that is installed, add the HTTP package.

App.OnResume error in Xamarin forms on Android and IOS devices

We are using xamarin forms. After an Android or IOS device resumes from background, we are making a REST call in .net that is being triggered by a timer. The first attempt on IOS returns a "The Descriptor is not a socket" error and the Android returns a "Connection refused" error. The same code works fine in Windows. Future attempts (every few seconds) in all 3 platforms work fine. Has anyone seen this and have a fix?
Code
//app on resume event
protected async override void OnResume()
{
// Handle when your app resumes
if (MainPage is RootPage)
{
RootPage mainPage = MainPage as RootPage;
if (mainPage.Detail is NavigationPage)
{
NavigationPage nvPage = mainPage.Detail as NavigationPage;
if(nvPage.CurrentPage is ThingsPage)
{
ThingsPage thPage = nvPage.CurrentPage as ThingsPage;
thPage.TurnOnTimer();
}
}
}
}
//code on the page
public void TurnOnTimer()
{
if (viewModel != null)
{
viewModel.ContinueTimer = true;
viewModel.StartAnotherTimer();
}
}
//code in view model
public async void StartAnotherTimer()
{
while (ContinueTimer)
{
try
{
DevicesUpdate devicesUpdate = await DataSource.GetDevices(LocationID, ControllerID, lastDevicesUpdateReceivedAt);
}
catch (Exception ex)
{
}
// Update the UI (because of async/await magic, this is still in the UI thread!)
if (ContinueTimer)
{
await Task.Delay(TimeSpan.FromSeconds(3));
}
}
}
public static async Task<DevicesUpdate> GetDevices(Guid locationID, Guid controllerID, DateTime lastUpdateReceivedAt)
{
DevicesUpdate devicesUpdate = await GetLastUpdatedDevices(controllerID, lastUpdateReceivedAt);
}
//code in view model
public static async Task<DevicesUpdate> GetLastUpdatedDevices(Guid controllerID,
DateTime lastUpdate)
{
System.Net.Http.HttpClient client = new System.Net.Http.HttpClient();
string url = string.Format("http://appname.azurewebsites.net/api/devices?controllerid={1}&lastUpdate={2}"
, Constants.WebServerURL, controllerID, lastUpdate);
System.Net.Http.HttpResponseMessage response = await client.GetAsync(new Uri(url));
string result = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
{
DevicesUpdate devices = JSONHelper.Deserialize<DevicesUpdate>(result);
return devices;
}
else
{
if (response.ReasonPhrase == "UserException")
{
throw new UserException(result);
}
else
{
//throw error because the response from rest api is not a success
throw new System.Net.Http.HttpRequestException(result);
}
}
}
You might have a few things happening here that's causing problems.
GetDevices doesn't return anything. (I hope you just left out the return for brevity sake)
You are never setting ContinueTimer to false.
What iOS version are you on? In later versions, you HAVE to use HTTPS or explicitly allow non-secure connections. This shouldn't be a problem because Azure has ssl.
If you plan on running this in the background, you need to register your app as a background process.
If you don't plan on running this in the background, you might have issues with previous attempts being ran (or still trying to execute, or just have failed) and then calling more.
What is the reason for calling the 3 second timer for the network calls? What if the call takes more than 3 seconds (then you are making duplicate calls even though the first might succeed).
If you want to make your network calls more robust, check out this Blog Post by Rob Gibbons about resilient network calls.
First thing I would do is remove it from the timer because it seems like the underlying sockets are having issues cross-thread.

Trying to run websocket server from my local PC

I am trying to develop a web-socket server app for my UWP Windows 10 App.
This is my code:
class Server
{
public async void Start()
{
MessageWebSocket webSock = new MessageWebSocket();
//In this case we will be sending/receiving a string so we need to set the MessageType to Utf8.
webSock.Control.MessageType = SocketMessageType.Utf8;
//Add the MessageReceived event handler.
webSock.MessageReceived += WebSock_MessageReceived;
//Add the Closed event handler.
webSock.Closed += WebSock_Closed;
Uri serverUri = new Uri("ws://127.0.0.1/motion");
try
{
//Connect to the server.
await webSock.ConnectAsync(serverUri);
//Send a message to the server.
await WebSock_SendMessage(webSock, "Hello, world!");
}
catch (Exception ex)
{
//Add code here to handle any exceptions
}
}
//The MessageReceived event handler.
private void WebSock_MessageReceived(MessageWebSocket sender, MessageWebSocketMessageReceivedEventArgs args)
{
DataReader messageReader = args.GetDataReader();
messageReader.UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf8;
string messageString = messageReader.ReadString(messageReader.UnconsumedBufferLength);
//Add code here to do something with the string that is received.
}
//The Closed event handler
private void WebSock_Closed(IWebSocket sender, WebSocketClosedEventArgs args)
{
//Add code here to do something when the connection is closed locally or by the server
}
//Send a message to the server.
private async Task WebSock_SendMessage(MessageWebSocket webSock, string message)
{
DataWriter messageWriter = new DataWriter(webSock.OutputStream);
messageWriter.WriteString(message);
await messageWriter.StoreAsync();
}
}
It errors here:
await webSock.ConnectAsync(serverUri);
with this error:
Not found (404). (Exception from HRESULT: 0x80190194)
I don't have any personal experience with it, but you might want to give IotWeb HTTP Server a try. It seems to be a portable embedded HTTP and web socket server that also supports UWP and can be run inside Windows Store and Windows 10 IoT Core applications.
Judging from its repository, it's rather new and not exactly mature, nor does it have a lot of documentations or samples available. There's a NuGet package available, though.
Unfortunately I didn't manage to find any other alternative yet.
The code
await webSock.ConnectAsync(serverUri);
Is try to connect to existing server at ws://127.0.0.1/motion, Not to deploy a server on this address.
You can look for ways to build a c# WebSocket server at the follwing links:
https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_server
http://www.codeproject.com/Articles/57060/Web-Socket-Server

Resources