4
votes

I am trying to use PortableRest to make an Async call to a Web API 2.2 Rest service from Xamarin Forms.

I think I have some kind of deadlock / synchronisationcontext issue but I cannot work it out (newbie to async etc).

Can anyone please help?

My controller test method (removed any call to database) -

public IEnumerable<ContentModel> GetTestRest()
{
    return new List<ContentModel> {
        new ContentModel() {Categoryid = 1, Title = "Title"}};
}

My Unit Test Passes -

[TestMethod]
public async Task TestRest()
{
    MyNewsApiClient MyNewsApiClient = new MyNewsApiClient();

    var models = await MyNewsApiClient.TestRest();
    int count = models.Count;
    Assert.AreEqual(1, count);
}

My PortableRest Proxy (PCL) Method -

public async Task<List<ContentModel>> TestRest()
{
    var request = new RestRequest();
    request.Resource = "Content/GetTestRest";

    return await ExecuteAsync<List<ContentModel>>(request);
}

Xamarin Forms ContentPage (PCL) -

public partial class NewsType1CP : ContentPage
{
    public NewsType1CP ()
    {
        InitializeComponent ();
    }

    protected override void OnAppearing ()
    {
        LoadData ();  // this is a sync call of an async method, not sure how else to  approach, make OnAppearing async?
    }

    public async Task LoadData ()
    {
        Debug.WriteLine ("LoadData");

        HeaderLabel.Text = "Load Data!";

        MyNewsApiClient api = new MyNewsApiClient ();

        var cm = await api.TestRest ();
        // this will work on its own, control returns to this method - await api.GetDelay ();

        HeaderLabel.Text = "After! - ";

        NewsListView.ItemsSource = cm;
    }
}

The await to api.TestRest() never results in HeaderLabel.After or ListView being set.

If I just add a test Proxy Method GetDelay() which does not call PortableRest via return await ExecuteAsync>(request);

public async Task<bool> GetDelay ()
{
    await Task.Delay (1000);
    return true;
}

Then all "works".

Thanks for your help, I will download the source code for PortableRest if required (using Nuget dll at present), just was not sure if missing something basic at this top level.

1
Have you checked the acutal network traffic? it's possible an error occurs while connecting. You can also try using HttpClient.GetAsync<> to troubleshoot the connectivity issuesSten Petrov
Thanks @StenPetrov, I checked traffic and you are correct there is not a call made outwards, I have now surrounded the call in a try block and looking furtherWickedW

1 Answers

8
votes

Right, this eventually has nothing to do with Async (or any Issue with PortableRest), but thought I would share in case it can help others.

I eventually put a try block (obvious next step now!) and caught this exception -

Method not found: 'System.Net.Http.HttpClientHandler.set_AutomaticDecompression'.

So, looking at this -

http://davidburela.wordpress.com/2013/07/12/error-when-using-http-portable-class-library-compression/

PortableRest was already in my Forms PCL, but I needed to add Microsoft Http Client Libraries Nuget to my Android Application.

I then got -

Error: ConnectFailure (The requested address is not valid in this context)

I thought it may be something to do with Android Permissions, but it was not in this case (although I now realise I need to add Internet permission anyway for future calls).

Because I am running my App in a VM (from GenyMotion / Virtual Box) then the Android App cannot access LocalHost (where my Web Api resides)

So, from this -

http://bbowden.tumblr.com/post/58650831283/accessing-a-localhost-server-from-the-genymotion

I can confirm that using the address shown in VirtualBox > File > Preferences > Network > VirtualBox Host-Only Network Adapter > Modify does the job beautifully.

Thanks for your help.