Restful service always returns null value in Xamarin Forms - visual-studio-2013

i am developing an app using "Xamarin Forms", and i'm using Visual Studio 2013 to develop the app.
Here my problem is,
in my app i'm using restful services to Post/Get the data.
The entire code wrote in "Xamarin Shared Project"
Here is my code:
using System.Threading.Tasks;
using System.Net.Http;
namespace Sher.Services
{
public class CustomerService : ICustomerService
{
public async Task<string> TopEntries(String uri)
{
var client = new HttpClient();
var result = await client.GetStringAsync(uri); //"http://api.ihackernews.com/page"
return result;
}
}
public interface ICustomerService
{
Task<string> TopEntries();
}
}
Here i'm facing small problem.
i am able to call the service method and the service method execute in my server.
But the return result is gives always "NULL". i don't know why.
can any one help me to solve this problem.
Thanks in advance.

Yup, this is how async methods work. When an async call (await keyword) is made they exit and continue from that point when async calls is completed.
Try putting a breakpoint in "return result;" line.

Related

PostAsync hanging in Xamarin Forms works on emulator but hangs on actual Mobile phone

I have Xamarin Forms project where I'm trying to POST and GET data to/from a Web API but when I'm making an async/await call, it works on the emulator (not without its original problems!) but when I try it on my actual phone mobile (Samsung S8+), it just hangs indefinitely.
Note that I'm only concentrating on the Android part right now, not iOS, not that the problem should make any difference in either.
This is the code I'm using:
IDataService.cs
Task<TResponse> PostDataAsync<TRequest, TResponse>(string uri, TRequest data)
where TRequest : class
where TResponse : class;
DataService.cs:
public async Task<TResponse> PostDataAsync<TRequest, TResponse>(string
additionalUri, TRequest data)
where TRequest : class
where TResponse : class
{
return await WebClient
.PostData<TRequest, TResponse>
(string.Concat(this.Uri, additionalUri), data);
}
WebClient.cs
using (var client = new HttpClient())
{
var jsonData = JsonConvert.SerializeObject(data);
using (var response = await client.PostAsync(
uri,
new StringContent(jsonData,
Encoding.UTF8,
"application/json" )))
{
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<TResponse>(content);
}
}
}
Method 1:
LoginPageViewModel.cs
public DelegateCommand SignInCommand => _signInCommand ??
(this._signInCommand = new DelegateCommand(SignInCommandAction));
private async void SignInCommandAction()
{
try
{
....
var user = await this._dataService
.PostDataAsync<LoginRequestDto,
LoginResponseDto>(#"Accounts/Login", loginRequestDto);
....
}
...
}
Method2:
LoginPageViewModel.cs
public DelegateCommand SignInCommand => _signInCommand ??
(this._signInCommand =
new DelegateCommand(async () => await SignInCommandAction()));
private async Task SignInCommandAction()
{
try
{
....
var user = await this._dataService
.PostDataAsync<LoginRequestDto,
LoginResponseDto>(#"Accounts/Login", loginRequestDto);
....
}
...
}
The PostDataAsync works with both methods when I call my local web API i.e. http://10.0.2.2/MyApp/api/ but both methods still hangs when calling external my web service from web provider i.e. http://myapp-123-site.atempurl.com/api/ which is a temp url for testing purpose.
The same apply to my GetDataAsync which is not demonstrated in question but I just thought I'd mention it.
Based on the above, you would think that my async/await code is correct since it works when calling the local web api but then what's causing it to hang when calling the remote web api.
As mentioned, I did enable my INTERNET permission in the manifest.
Any suggestions welcomed?
Thanks.
UPDATE-1:
Note that I've just tried to call a GET opertation within the same function and this is working in the emulator but hanging with the actual mobile.
using (var client = new HttpClient())
{
using (var response = await client.GetAsync(uri))
{
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync();
return Newtonsoft.Json.JsonConvert
.DeserializeObject<TResponse>(content);
}
}
}
UPDATE-2:
This is somehow working and I have no idea why! The only thing that comes to mind is that I upgraded my libraries. This included PRISM which may have been at the source of the problem but I have no idea.
Sorry I can't provide more details. I could role back my code and try to see if it's hanging again but I just don't have the time to go and experiment some more considering the amount of time I've already spent on this. Sorry.
The requested url is an IP or a domain name.
If it is ip, only the IP of the public network can be accessed by devices on multiple network segments.
If it is a domain name, it needs to support the domain name resolution service.
If you do not have these environments for a while, you need the IP of the device and the IP of the server on the same network segment.
The PostDataAsync works with both methods when I call my local web API i.e. http://10.0.2.2/MyApp/api/ but both methods still hangs when calling external my web service from web provider i.e. http://myapp-123-site.atempurl.com/api/ which is a temp url for testing purpose.
From this phenomenon , the reason should be the temp url. From this domain name (myapp-123-site.atempurl.com) can not find the right local IP (10.0.2.2).And when you test in local network , I guess this will work.However the network of actual mobile can be not the same with local network , such as using 3G/4G network , then this will not working.

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.

CosmosDB Project Layout

Asking for advice and references.
Using Visual Studio, I have an Azure Web Apps project in my solution. Now, I'm programming my Stored Procedures for CosmosDB. Using the CosmosDB Emulator, I can simply insert the Stored Procedure code directly into the browser editor window. All good and fine, and everything is working beautifully.
I also have a NodeJS project sitting alongside my Web App project. This allows me to store the Stored Procedures as files. The associated Console App is able to connect and modify the CosmosDB Emulator as expected.
My question is, using Visual Studio, what is the best way to lay out my project, so that it's not done on napkins and prayers?
I'm wondering how I should be structuring my project layout and assets to align with current "best practices". Is there any information, articles or posts that you guys/gals have found that talk about this specifically? Would I be running all of these procedures against CosmosDB manually, or are there automated procedures people have devised? I would like to be able to test these stored procedures first, against the Emulator, and with little-to-no source code change, update staging.
Thanks!
I have just recently asked myself the same question regarding stored procedure migrations.. I am currently running a basic Migrate Method that will get stored procedure content from a js file and replace/create the stored procedure, this runs on startup (in startup.cs)
The main gist of the code below, you will need to create the very basic internal methods (comments welcome):
using System;
using System.IO;
using System.Threading.Tasks;
using App.Data.Access;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Azure.Documents;
namespace App.Data.StoredProcedures
{
public class Migrations : IMigrations
{
private readonly IHostingEnvironment _hostingEnvironment;
private readonly IDocumentDbContext _documentDbContext;
public Migrations(IHostingEnvironment hostingEnvironment,IDocumentDbContext documentDbContext)
{
_hostingEnvironment = hostingEnvironment;
_documentDbContext = documentDbContext;
}
public async Task<bool> Migrate()
{
try
{
await AddUpdateBulkDeleteStoredProcedure();
return true;
}
catch (Exception exception)
{
throw new Exception("Error running CosmosDb stored procedure migrations,error" + exception.Message);
}
}
public string GetStoredProcedureScript(string filename)
{
var script = Path.Combine(_hostingEnvironment.WebRootPath, "App_Data", "CosmosDbStoredProcedures", filename);
return IO.File.ToString(script);
}
public async Task<bool> AddUpdateBulkDeleteStoredProcedure()
{
const string storedProcedureId = "BulkDeleteStoredProcedure";
var function = GetStoredProcedureScript($"{storedProcedureId}.js");
if (string.IsNullOrWhiteSpace(function))
{
throw new Exception($"Error running DocumentDb Stored procedure migrations, {storedProcedureId} content is empty");
}
try
{
await _documentDbContext.Client.ReplaceStoredProcedureAsync(_documentDbContext.GetStoredProcedureUri(storedProcedureId), new StoredProcedure {Id = storedProcedureId, Body = function});
return true;
}
catch
{
// ignore
}
await _documentDbContext.Client.CreateStoredProcedureAsync(_documentDbContext.DocumentCollectionUri, new StoredProcedure {Id = storedProcedureId, Body = function});
return true;
}
}
}

how to call comon web service for both ios and android in xamarin?

Iam new to Xamarin, how to call webservice for both ios and android
with single code snippet.
before you post a new question , search for existing ,
consuming a php webservice in Xamarin PCL
duplicated !
BTW you can use httpClient
//Use this class as a singleton in an IoC container
class MyAppClient
{
readonly HttpClient _httpClient = new HttpClient();
public async Task<string> GetChuck()
{
return await _httpClient.Get("http://chucknorris.com");
}
}
//Although "using" is good in general, don't do this
using (var httpClient = new HttpClient())
{
return await _httpClient.Get("http://chucknorris.com");
}
code example taken from http://jonathanpeppers.com/Blog/improving-http-performance-in-xamarin-applications

WebApi Odata Windows Store App EndSaveChanges exception

I am trying to create a Windows Store App using a WebApi Odata controller. After some effort I have all the Get requests working, I am now moving onto the CRUD methods, and am getting the following Exception on the EndSaveChanges of the Data Service Context.
<?xml version="1.0" encoding="utf-8"?>
<m:error xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
<m:code />
<m:message xml:lang="en-US">No HTTP resource was found that matches the request URI 'http://localhost:56317/odata/ESFClients(guid'f04ad636-f896-4de4-816c-388106cd39ce')'.</m:message>
<m:innererror>
<m:message>No routing convention was found to select an action for the OData path with template '~/entityset/key'.</m:message>
<m:type></m:type>
<m:stacktrace></m:stacktrace>
</m:innererror>
</m:error>
Now I think this is a bug in WebApi from this http://aspnetwebstack.codeplex.com/workitem/822 and its hiding the actual error. To make sure it wasn't my Odata Endpoint I created a quick console app to get an entry, update it and Patch it back, which worked all ok. My WebApi Odata Controller derives from ODataController with
public HttpResponseMessage Patch([FromODataUri] Guid key, Delta<ESFClient> patch)
As the method.
In my windows application I have a extension method on the DataServiceContext for the Save Changes.
public static async Task<DataServiceResponse> SaveChangesAsync(this DataServiceContext context, SaveChangesOptions options)
{
var queryTask = Task.Factory.FromAsync<DataServiceResponse>(context.BeginSaveChanges(options, null, null),
queryAsyncResult =>
{
var results = context.EndSaveChanges(queryAsyncResult);
return results;
});
return await queryTask;
}
And calling the update like so from a blank Windows Store XAML page.
public async Task UpdateWeekNo()
{
var container = new ESFOdataService.Container(new Uri("http://localhost:56317/odata/"));
var clients = (DataServiceQuery<ESFClient>)from p in container.ESFClients where p.UserID == new Guid("f04ad636-f896-4de4-816c-388106cd39ce") select p;
var result = await clients.ExecuteAsync();
var updatedClient = result.Single();
if (updatedClient != null)
{
updatedClient.WeekNo = 19;
container.UpdateObject(updatedClient);
await container.SaveChangesAsync(SaveChangesOptions.PatchOnUpdate); // Use PATCH not MERGE.
}
}
So does anyone come across the same issue, or know how I can find out the actual error. One interesting point is that if I debug the controller while running the Windows App, the patch method does not get called.
Ok, so I have finally solved this. Just a recap for those who could experience the same issue. I have an Odata WebApi controller, Windows 8 Store Application using WCF Client Library, with the reference created from Add Service Reference. When trying to update (patch) a record an exception was being thrown at the EndSaveChanges. This is because for some reason Post Tunneling is enabled by default on my context. Setting this to false allowed everything to work.
Context.UsePostTunneling = false;
Context.IgnoreResourceNotFoundException = true;

Resources