Jaycee Evangelista Jaycee Evangelista - 4 months ago 116
ASP.NET (C#) Question

Xamarin.Forms: Web API Access To Mobile

Good Day Everyone. I am creating a Xamarin.Forms Portable Application.

In my solution, I have created a Xamarin Portable project and a WebForms project that will handle my Web Services and Database.
I've configured my applicationhost.config in the root folder of my VS2015 and set the binding to this :

<bindings>
<binding protocol="http" bindingInformation="*:50857:localhost" />
<binding protocol="http" bindingInformation="*:50857:192.168.1.11" />
</bindings>


By doing that, I was able to access my WEB API even by changing the URL from localhost to 192.168.1.11 which is my IP ADDRESS.

enter image description here

I also tried to access it using my phone's INTERNET BROWSER by using my http://192.168.1.11:50857/api/Customer/ (laptop and mobile connected to the same network) and have a success in doing so.

But the real problem is, the LIST of CLIENTS from my WebForms project are not being displayed to my Xamarin Portable project.

My Mobile Application should access my WebForms project by getting its WEB API and use it in my RestClient WebServiceUrl.

What do you think is the reason behind this?

Here's my code for the WebForms project which handles the getting of data from my DB :

WebFormsDemo project

CustomerController.cs

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using System.Web.Http.Description;
using WebFormsDemo;
using WebFormsDemo.ViewModel;

namespace WebFormsDemo.Controllers
{
public class CustomerController : ApiController
{
private EBMSEntities db = new EBMSEntities();

// GET: api/Customer
public IQueryable<CustomerViewModel> GetCustomerViewModels()

{
var displaycustomerInfo = from cust in db.CUSTOMERs
select new CustomerViewModel
{
Id = cust.CUSTOMER_ID,
CUSTOMER_CODE = cust.CUSTOMER_CODE,
CUSTOMER_NAME = cust.CUSTOMER_NAME,
CUSTOMER_MOBILE_NUMBER = cust.CUSTOMER_MOBILE_NUMBER,
CUSTOMER_EMAIL_ADDRESS = cust.CUSTOMER_EMAIL_ADDRESS,
CUSTOMER_CONTACT = cust.CUSTOMER_EMAIL_ADDRESS + "," + " " + cust.CUSTOMER_MOBILE_NUMBER
};




return displaycustomerInfo;
}

}
}


CustomerViewModel.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace WebFormsDemo.ViewModel
{
public class CustomerViewModel
{

public int Id { get; set; }
public string CUSTOMER_CODE { get; set; }
public string CUSTOMER_NAME { get; set; }
public string CUSTOMER_EMAIL_ADDRESS { get; set; }
public string CUSTOMER_MOBILE_NUMBER { get; set; }
public string CUSTOMER_CONTACT { get; set; }
public string CUSTOMER_LANDLINE { get; set; }
public string CUSTOMER_FAX_NUMBER { get; set; }
public string ADDRESS { get; set; }
public int LOCATION_TYPE_ID { get; set; }
public int INDUSTRY_TYPE_ID { get; set; }
public int CUSTOMER_TYPE_ID { get; set; }
public int IS_DELETED { get; set; }
public DateTime DATE_CREATED { get; set; }
}
}


.

XamarinForms Portable

Here's my code for getting the WEB API of WebForms project:

RestClient.cs

public class RestClient_Customer<T>
{


private const string WebServiceUrl = "http://localhost:50857/api/Customer/";

public async Task<List<T>> GetCustomerAsync()
{

var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

var json = await httpClient.GetStringAsync(WebServiceUrl);

var taskModels = JsonConvert.DeserializeObject<List<T>>(json);

return taskModels;
}
}


CustomerServices.cs

using Plugin.RestClient;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using XamarinFormsDemo.Models;

namespace XamarinFormsDemo.Services
{
public class CustomerServices
{


public async Task<List<Customer>> GetCustomerAsync()
{
RestClient_Customer<Customer> restClient = new RestClient_Customer<Customer>();

var customerList = await restClient.GetCustomerAsync(); //yung getasync ay pantawag as restclient

return customerList;
}


}
}


CustomerVM.cs

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Net.Http;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using Xamarin.Forms;
using XamarinFormsDemo.Models;
using XamarinFormsDemo.Services;
using XamarinFormsDemo.Views;

namespace XamarinFormsDemo.ViewModels
{
public class CustomerVM : INotifyPropertyChanged
{


private List<Customer> _customerList; // keep all customers
private List<Customer> _searchedCustomerList; // keep a copy for searching
private Customer _selectedCustomer = new Customer();

private string _keyword = "";
public string Keyword
{
get
{
return _keyword;
}
set
{
this._keyword = value;

// while keyword changed we filter Employees
//Filter();
}
}



private void Filter()
{
if (string.IsNullOrWhiteSpace(_keyword))
{
CustomerList = _searchedCustomerList;

}
else
{
// var lowerKeyword = _keyword.ToLower();
CustomerList = _searchedCustomerList.Where(r => r.CUSTOMER_NAME.ToLower().Contains(_keyword.ToLower())).ToList();
// EmployeesList = _searchedEmployeesList.Where(r => r.EMPLOYEE_NAME.Contains(_keyword)).ToList();


}
}




public List<Customer> CustomerList
{
get
{
return _customerList;
}
set
{
_customerList = value;
OnPropertyChanged();
}
}



public CustomerVM()
{
InitializeDataAsync();

}

private async Task InitializeDataAsync()
{
var customerServices = new CustomerServices();
_searchedCustomerList = await customerServices.GetCustomerAsync();
CustomerList = await customerServices.GetCustomerAsync();

}




public event PropertyChangedEventHandler PropertyChanged;

protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}

}
}


ClientListPage.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamarinFormsDemo.Views.ClientListPage"
xmlns:ViewModels="clr-namespace:XamarinFormsDemo.ViewModels;assembly=XamarinFormsDemo"
xmlns:controls="clr-namespace:ImageCircle.Forms.Plugin.Abstractions;assembly=ImageCircle.Forms.Plugin.Abstractions"
BackgroundImage="bg3.jpg"
Title="Client List">


<ContentPage.BindingContext>
<ViewModels:CustomerVM/>
</ContentPage.BindingContext>


<SearchBar Placeholder="Search" Text="{Binding Keyword}" SearchCommand="{Binding SearchCommand}" x:Name="txtSearch" />

<ListView ItemsSource="{Binding CustomerList, Mode=TwoWay}"
HasUnevenRows="True"
IsPullToRefreshEnabled="True"
x:Name="listView">


<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid Padding="10" RowSpacing="10" ColumnSpacing="5">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>

<controls:CircleImage Source="icon.png"
HeightRequest="66"
HorizontalOptions="CenterAndExpand"
Aspect="AspectFill"
WidthRequest="66"
Grid.RowSpan="2"
/>


<Label Grid.Column="1"
Text="{Binding CUSTOMER_NAME}"
TextColor="#24e97d"
FontSize="24"/>



<Label Grid.Column="1"
Grid.Row="1"
Text="{Binding CUSTOMER_CODE}"
TextColor="White"
FontSize="18"
Opacity="0.6"/>


<Label Grid.Column="1"
Grid.Row="2"
Text="{Binding CUSTOMER_CONTACT}"
TextColor="White"
FontSize="18"
Opacity="0.6"/>



</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>

</ListView>


<StackLayout Orientation="Vertical"
Padding="30,10,30,10"
HeightRequest="20"
BackgroundColor="#24e97d"
VerticalOptions="Center"
Opacity="0.5">
<Label Text="© Copyright 2016 SMESOFT.COM.PH All Rights Reserved "
HorizontalTextAlignment="Center"
VerticalOptions="Center"
HorizontalOptions="Center" />
</StackLayout>

</ContentPage>


ClientListPage.xaml.cs

using Newtonsoft.Json;
using OxyPlot;
using OxyPlot.Series;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using Xamarin.Forms;
using XamarinFormsDemo.Models;
using XamarinFormsDemo.ViewModels;

namespace XamarinFormsDemo.Views
{
public partial class ClientListPage : ContentPage
{
//CustomerListView listcustomer;
//SearchBar searchbarcustomer;

public ClientListPage()
{
NavigationPage.SetHasNavigationBar(this, true);
InitializeComponent();

}


}
}


Please help me. Thanks a lot.

This is my Current code for the XamarinForms project:

ClientListPage.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamarinFormsDemo.Views.ClientListPage"
xmlns:ViewModels="clr-namespace:XamarinFormsDemo.ViewModels;assembly=XamarinFormsDemo"
xmlns:controls="clr-namespace:ImageCircle.Forms.Plugin.Abstractions;assembly=ImageCircle.Forms.Plugin.Abstractions"
BackgroundImage="bg3.jpg"
Title="Client List">


<ContentPage.BindingContext>
<ViewModels:CustomerVM/>
</ContentPage.BindingContext>


<SearchBar Placeholder="Search" Text="{Binding Keyword}" SearchCommand="{Binding SearchCommand}" x:Name="txtSearch" />

<ListView ItemsSource="{Binding CustomerList, Mode=TwoWay}"
HasUnevenRows="True"
IsPullToRefreshEnabled="True"
x:Name="listView">


<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid Padding="10" RowSpacing="10" ColumnSpacing="5">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>

<controls:CircleImage Source="icon.png"
HeightRequest="66"
HorizontalOptions="CenterAndExpand"
Aspect="AspectFill"
WidthRequest="66"
Grid.RowSpan="2"
/>


<Label Grid.Column="1"
Text="{Binding CUSTOMER_NAME}"
TextColor="#24e97d"
FontSize="24"/>



<Label Grid.Column="1"
Grid.Row="1"
Text="{Binding CUSTOMER_CODE}"
TextColor="White"
FontSize="18"
Opacity="0.6"/>


<Label Grid.Column="1"
Grid.Row="2"
Text="{Binding CUSTOMER_CONTACT}"
TextColor="White"
FontSize="18"
Opacity="0.6"/>



</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>

</ListView>


<StackLayout Orientation="Vertical"
Padding="30,10,30,10"
HeightRequest="20"
BackgroundColor="#24e97d"
VerticalOptions="Center"
Opacity="0.5">
<Label Text="© Copyright 2016 SMESOFT.COM.PH All Rights Reserved "
HorizontalTextAlignment="Center"
VerticalOptions="Center"
HorizontalOptions="Center" />
</StackLayout>




</ContentPage>


ClientListPage.xaml.cs

using Newtonsoft.Json;
using OxyPlot;
using OxyPlot.Series;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using Xamarin.Forms;
using XamarinFormsDemo.Models;
using XamarinFormsDemo.ViewModels;



namespace XamarinFormsDemo.Views
{
public partial class ClientListPage : ContentPage
{

CustomerVM viewModel;
public ClientListPage()
{
NavigationPage.SetHasNavigationBar(this, true);


InitializeComponent();
viewModel = new CustomerVM();
BindingContext = viewModel;
}

async override protected void OnAppearing()
{
base.OnAppearing();

var json = await GetCustomerAsync();

var customers = JsonConvert.DeserializeObject<Customer[]>(json);

foreach (Customer c in customers)
viewModel.CustomerList.Add(c);
}

async Task<string> GetCustomerAsync()
{
var client = new HttpClient();

client.BaseAddress = new Uri("http://192.168.1.11:50857/");

client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

HttpResponseMessage response = await client.GetAsync("api/Customer");
if (response.IsSuccessStatusCode)
{
return await response.Content.ReadAsStringAsync();
}
else return response.ReasonPhrase;
}


}
}


CustomerVM.cs

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Net.Http;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using Xamarin.Forms;
using XamarinFormsDemo.Models;
using XamarinFormsDemo.Services;
using XamarinFormsDemo.Views;


namespace XamarinFormsDemo.ViewModels
{
public class CustomerVM : INotifyPropertyChanged
{


private ObservableCollection<Customer> _customerList; // keep all customers
private ObservableCollection<Customer> _searchedCustomerList; // keep a copy for searching
private Customer _selectedCustomer = new Customer();

private string _keyword = "";
public string Keyword
{
get
{
return _keyword;
}
set
{
this._keyword = value;

// while keyword changed we filter Employees
//Filter();
}
}





public ObservableCollection<Customer> CustomerList
{
get
{
return _customerList;
}
set
{
_customerList = value;
OnPropertyChanged();
}
}



public CustomerVM()
{
// InitializeDataAsync();
CustomerList = new ObservableCollection<Customer>();
}



public event PropertyChangedEventHandler PropertyChanged;

protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}

}
}


Customer.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace XamarinFormsDemo.Models
{
public class Customer
{

public int Id { get; set; }
public string CUSTOMER_CODE { get; set; }
public string CUSTOMER_NAME { get; set; }
public string CUSTOMER_EMAIL_ADDRESS { get; set; }
public string CUSTOMER_MOBILE_NUMBER { get; set; }
public string CUSTOMER_CONTACT { get; set; }
public string CUSTOMER_LANDLINE { get; set; }
public string CUSTOMER_FAX_NUMBER { get; set; }
public string ADDRESS { get; set; }
public int LOCATION_TYPE_ID { get; set; }
public int INDUSTRY_TYPE_ID { get; set; }
public int CUSTOMER_TYPE_ID { get; set; }
public int IS_DELETED { get; set; }
public DateTime DATE_CREATED { get; set; }
}
}

Answer

There seems to be a bit of a MVVM Pattern conceptual mix up in your code, just because your Web API returns a collection of CustomerViewModel. I'd much rather have the API to return a collection of Customer and have it stored in my CustomerViewModel. But perhaps you're just giving bad names to things... impossible to say because you did not post a MCVE. So, I'll post a working one for you and perhaps it will help you sort things out:

ClientListPage.xaml:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:App1"
             x:Class="App1.ClientListPage">

  <ListView ItemsSource="{Binding CustomerList}">
    <ListView.ItemTemplate>
      <DataTemplate>
        <ViewCell>
          <ViewCell.View>
            <StackLayout Orientation="Horizontal">
              <Label Text="{Binding ID}" FontSize="36"/>
              <Label Text="{Binding Name}" FontSize="36"/>
            </StackLayout>
          </ViewCell.View>
        </ViewCell>
      </DataTemplate>
    </ListView.ItemTemplate>
  </ListView>

</ContentPage>

ClientListPage.cs:

public partial class ClientListPage : ContentPage
{
    CustomerVM viewModel;

    public ClientListPage()
    {
        InitializeComponent();

        viewModel = new CustomerVM();
        BindingContext = viewModel;
    }

    async override protected void OnAppearing()
    {
        base.OnAppearing();

        var json = await GetCustomersAsync();

        var customers = JsonConvert.DeserializeObject<CustomerViewModel[]>(json);

        foreach (CustomerViewModel c in customers)
            viewModel.CustomerList.Add(c);
    }

    async Task<string> GetCustomersAsync()
    {
        var client = new HttpClient();

        client.BaseAddress = new Uri("http://10.0.0.17:55365/");

        client.DefaultRequestHeaders.Accept.Clear();
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

        HttpResponseMessage response = await client.GetAsync("api/Customers");
        if (response.IsSuccessStatusCode)
        {
            return await response.Content.ReadAsStringAsync();
        }
        else return response.ReasonPhrase;
    }
}

ViewModel:

public class CustomerVM
{
    public ObservableCollection<CustomerViewModel> CustomerList { get; set; }

    public CustomerVM()
    {
        CustomerList = new ObservableCollection<CustomerViewModel>();
    }
}

Model:

public class CustomerViewModel
{
    public int ID { get; set; }
    public string Name { get; set; }
}

enter image description here

EDIT: In case that doesn't help, i suggest you to test your Web API using a Console client as below, and verify you get a valid JSON string (or error code, or exception):

[{"ID":1,"Name":"Customer 1"},{"ID":2,"Name":"Customer 2"},{"ID":3,"Name":"Customer 3"}]

class Program
{
    static string customers = "No customers";

    static void Main(string[] args)
    {
        try
        {
            GetCustomersAsync().Wait();

            Console.WriteLine(customers);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.ToString());
        }

        Console.ReadLine();
    }

    static async Task GetCustomersAsync()
    {
        var client = new HttpClient();

        client.BaseAddress = new Uri("http://10.0.0.17:55365/");

        client.DefaultRequestHeaders.Accept.Clear();
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

        HttpResponseMessage response = await client.GetAsync("api/Customers");
        if (response.IsSuccessStatusCode)
        {
            customers = await response.Content.ReadAsStringAsync();
        }
        else customers = response.ReasonPhrase;
    }
}