Mobiele apps programmeren met Xamarin – Web services integreren

print

Inhoud


Wat vooraf ging

Ik herneem hier even een vorige post over het installeren van NuGet Packages (plug-ins).

NuGet is een package manager voor Microsoft development platforms zoals .NET. U kunt deze pakketten installeren om zo de mogelijkheden van uw project uit te breiden.

  • Om een NuGet package te installeren klikt u rechts op het project waar u het NuGet package wilt voor installeren of u klikt rechts op de Solution om het NuGet package meteen te installeren voor alle projecten.
  • Vervolgens klikt u op Manage NuGet packages for Solution….

  • Selecteer het NuGet package dat u wil installeren.
  • Vink alle projecten aan waarvoor u het wilt installeren.
  • Klik op Install.

Onderstaande video toont een volledige installatie (zij het in Visual Studio 2015 en voor een ASP.NET project maar in weze verschilt dit niet).


Inleiding

Sommige instellingen stellen hun data ter beschikking via een webservice. U kunt dan via een website (http) een Request doen op deze databank. Dit levert u informatie op die in XML of JSON wordt aangeboden.

Een webservice kan omschreven worden als een interface van een applicatiecomponent (application programming interface (API)) die toegankelijk is via standaard webprotocollen en waarbij meestal wordt gecommuniceerd via XML (of JSON) zonder menselijke tussenkomst. Een webservice maakt het mogelijk om op afstand (meestal over het Internet) vanaf een client (een (web)applicatie of component) een dienst op te vragen aan een server, bijvoorbeeld het maken van een berekening, het leveren van gegevens of het uitvoeren van een taak.

Een bekende webservice architectuur is REST (Representational State Transfer).

Kort samengevat werkt REST als volgt:

  • U gaat naar een basiswebadres (URL).
  • Via parameters, die u meegeeft aan deze URL, geeft u aan wat u wilt opvragen.
  • Het opgevraagde wordt teruggeven als een JSON-bestand.

OpenWeatherMap.org biedt zo’n webservice aan om weer-informatie op te vragen.

  • U gaat naar een basiswebadres (URL): api.openweathermap.org/data/2.5/weather .
  • Via parameters, die u meegeeft aan deze URL, geeft u aan wat u wilt opvragen. Hier zoeken we naar de stad Ninove in België q=ninove,be, als appid moet u uw opgevraagde sleutel meegeven appid=UWKEY en we wensen het metrische stelsel (Celsius) te gebruiken units=metric:
    http://api.openweathermap.org/data/2.5/weather?q=ninove,be&appid=UWKEY&units=metric.
  • Het opgevraagde wordt teruggeven als een JSON-bestand.
{"coord":{"lon":4.02,"lat":50.84},"weather":[{"id":802,"main":"Clouds","description":"scattered clouds","icon":"03d"}],"base":"stations","main":{"temp":6.4,"pressure":1015,"humidity":75,"temp_min":5,"temp_max":7},"visibility":10000,"wind":{"speed":6.2,"deg":310},"clouds":{"all":40},"dt":1522925400,"sys":{"type":1,"id":4842,"message":0.0035,"country":"BE","sunrise":1522905021,"sunset":1522952618},"id":2790115,"name":"Ninove","cod":200}

Om gebruik te kunnen maken van de webservice van OpenWeatherMap.org gaan we dus eerst de sleutel moeten opvragen en nadien een applicatie bouwen die het adres opvraagt en de ontvangen JSON-code verwerkt.

  • Om een gratis sleutel te ontvangen moet u zich gewoon registeren op OpenWeatherMap.org.
  • Bekijk ook al eens de documentatie om de huidige weer-informatie op te vragen (het is ook mogelijk het weer voor de komende 14 dagen, of historische informatie op te vragen maar dit is betalend).
  • Wie meer wilt weten over JSON kan hier en hier terecht.


JSON integreren

Om JSON te kunnen gebruiken dienen we het eerst te integreren via een NuGet package.

  • Klik rechts op de Solution en klik op Manage NuGet Packages for solution.
  • Klik op Browse en u vindt Newtonsoft.JSON helemaal bovenaan (indien niet, zoekt u er achter).
  • Selecteer het volledige project en klik op Install.

Het JSON-bestand dat we gaan inladen ziet er als volgt uit:

{"coord":{"lon":4.02,"lat":50.84},"weather":[{"id":802,"main":"Clouds","description":"scattered clouds","icon":"03d"}],"base":"stations","main":{"temp":6.4,"pressure":1015,"humidity":75,"temp_min":5,"temp_max":7},"visibility":10000,"wind":{"speed":6.2,"deg":310},"clouds":{"all":40},"dt":1522925400,"sys":{"type":1,"id":4842,"message":0.0035,"country":"BE","sunrise":1522905021,"sunset":1522952618},"id":2790115,"name":"Ninove","cod":200}

De ondersteunende klassen

Het voorbeeld-project maakt volgende 3 klassen aan:

  • Weather.cs – de klasse die de opgevraagde JSON-informatie bevat.
  • DataService.cs – een herbruikbare klasse die op basis van een queryString de JSON-informatie ophaalt.
  • Core.cs – deze klasse bevat de zogenaamde shared business logic. De queryString wordt opgebouwd en via de DataService-klasse opgeroepen. Vervolgens wordt de opgehaalde data toegekend aan een instantie van de Weather-klasse.

Wheater.cs

  • Klik rechts op het project en klik op AddNew Item…..
  • In Code selecteert u Class en u geeft het de naam Weather.cs.

Maak onderstaande klasse aan:

namespace WeerApp
{
    public class Weather
    {
        public string Title { get; set; } = " ";
        public string Temperature { get; set; } = "";
        public string Wind { get; set; } = "";
        public string Humidity { get; set; } = "";
        public string Visibility { get; set; } = "";
        public string Sunrise { get; set; } = "";
        public string Sunset { get; set; } = "";
    }
}

Omdat deze eigenschappen allemaal verbonden zullen worden met Labels via Binding krijgen ze allemaal een beginwaarde, een lege string, zodat deze Binding zonder problemen kan plaatsvinden, ook bij het starten van de app.

DataService.cs

  • Klik rechts op het project en klik op AddNew Item…..
  • In Code selecteert u Class en u geeft het de naam DataService.cs.

Maak onderstaande klasse aan:

using System.Net.Http;
using System.Threading.Tasks;
using Newtonsoft.Json;

namespace WeerApp
{
    public class DataService
    {
        public static async Task<dynamic> getDataFromService(string queryString)
        {
            HttpClient client = new HttpClient();
            var response = await client.GetAsync(queryString);

            dynamic data = null;
            if (response != null)
            {
                string json = response.Content.ReadAsStringAsync().Result;
                data = JsonConvert.DeserializeObject(json);
            }

            return data;
        }
    }
}

De event getDataFromService(string queryString) is een asynchrone taak. Het opvragen van gegevens van een website kan immers een tijdje duren en we willen niet dat hierdoor alles geblokkeerd wordt.

Om de verbinding te maken wordt een object van het type HttpClient gedeclareerd. Via GetAsync(queryString) wordt een URL geopend. Indien er een URL gevonden is wordt deze als JSON-formaat ingelezen via deserialisatie JsonConvert.DeserializeObject(json).

dynamic data = null;
if (response != null)
{
    string json = response.Content.ReadAsStringAsync().Result;
    data = JsonConvert.DeserializeObject(json);
}

De ingelezen data wordt tenslotte teruggegeven.

Een referentie naar System.Net.Http toevoegen

Even opmerken dat, toen ik dit uittestte in een nieuw project, HttpClient niet gevonden werd. Ik heb het “handmatig” moeten toevoegen.

  • Klik rechts op References onder het project (portable)/strong> en klik op Add Reference ….

  • Zoek naar System.Net.Http, dat normaal wel ergens op uw harde schijf staat en voeg het toe via OK.

Hier ziet u de toegevoegde referentie.

Core.cs

Deze klasse bevat de zogenaamde shared business logic. De queryString wordt opgebouwd en via de DataService-klasse opgeroepen. Vervolgens wordt de opgehaalde data toegekend aan een instantie van de Weather-klasse.

  • Klik rechts op het project en klik op AddNew Item…..
  • In Code selecteert u Class en u geeft het de naam Core.cs.
using System;
using System.Globalization;
using System.Threading.Tasks;

namespace WeerApp
{
    public class Core
    {
        public static async Task<Weather> GetWeather(string Stad)
        {
            string key = "UWKEY";
            string queryString = "http://api.openweathermap.org/data/2.5/weather?q=" + Stad + ",be&appid=" + key + "&units=metric";

            dynamic results = await DataService.getDataFromService(queryString);

            if (results["weather"] != null)
            {
                CultureInfo nlBEFormaat = new CultureInfo("nl-BE");
                Weather weather = new Weather();
                weather.Title = (string)results["name"];
                weather.Temperature = (string)results["main"]["temp"] + "°";
                weather.Wind = (string)results["wind"]["speed"] + " km/u";
                weather.Humidity = (string)results["main"]["humidity"] + " %";
                weather.Visibility = (string)results["weather"][0]["main"];

                DateTime time = new System.DateTime(1970, 1, 1, 0, 0, 0, 0);
                DateTime sunrise = time.AddSeconds((double)results["sys"]["sunrise"]);
                DateTime sunset = time.AddSeconds((double)results["sys"]["sunset"]);
                weather.Sunrise = sunrise.ToString("g", nlBEFormaat);
                weather.Sunset = sunset.ToString("g", nlBEFormaat);
                return weather;
            }
            else
            {
                return null;
            }
        }

    }
}

Voeg eerst de nodige namespaces toe.

using System;
using System.Globalization;
using System.Threading.Tasks;

De event GetWeather(string Stad) is eveneens een asynchrone taak die een Weather-type teruggeeft.

  • U moet uw opgevraagde apikey van de website OpenWeatherMap.org meegeven string key = "UWKEY";.
  • U bepaalt de op te zoeken queryString string queryString = "http://api.openweathermap.org/data/2.5/weather?q=" + Stad + ",be&appid=" + key + "&units=metric";. Het resultaat kan bv. dit zijn http://api.openweathermap.org/data/2.5/weather?q=ninove,be&appid=UWKEY&units=metric.
  • U geeft de gebouwde queryString mee aan de aangemaakte DataService dynamic results = await DataService.getDataFromService(queryString);.

Indien er een resultaat gevonden is:

if (results["weather"] != null)
{

}
else
{
     return null;
}

Omdat we de datums op onze vertrouwde wijze willen weergeven stellen we eerst de correcte culture in CultureInfo nlBEFormaat = new CultureInfo("nl-BE");.

Vervolgens wordt een nieuw Weather-object aangemaakt en de opgehaalde waarden aan de hiervoor voorziene eigenschappen toegekend.

Weather weather = new Weather();
weather.Title = (string)results["name"];
weather.Temperature = (string)results["main"]["temp"] + "°";
weather.Wind = (string)results["wind"]["speed"] + " km/u";
weather.Humidity = (string)results["main"]["humidity"] + " %";
weather.Visibility = (string)results["weather"][0]["main"];

DateTime time = new System.DateTime(1970, 1, 1, 0, 0, 0, 0);
DateTime sunrise = time.AddSeconds((double)results["sys"]["sunrise"]);
DateTime sunset = time.AddSeconds((double)results["sys"]["sunset"]);
weather.Sunrise = sunrise.ToString("g", nlBEFormaat);
weather.Sunset = sunset.ToString("g", nlBEFormaat);
return weather;

Merk op hoe de zonsopgang en de zonsondergang toegekend worden en de specifieke opmaak.


Een voorbeeldprogramma

  • Voeg de onderstaande XAML toe aan MainPage.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:WeerApp" x:Class="WeerApp.MainPage">

    <ContentPage.Resources>
        <ResourceDictionary>
            

<Style x:Key="labelStyle" TargetType="Label">
                <Setter Property="FontSize" Value="Small" />
                <Setter Property="TextColor" Value="#404040" />
            </Style>



            

<Style x:Key="fieldStyle" TargetType="Label">
                <Setter Property="FontSize" Value="Medium" />
                <Setter Property="Margin" Value="10,0,0,0" />
            </Style>



        </ResourceDictionary>
    </ContentPage.Resources>

    <StackLayout>
        <Grid BackgroundColor="#545454" Padding="10, 10, 10, 10">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>

            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto" />
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="Auto" />
            </Grid.ColumnDefinitions>

            <Label Text="Zoek het weer van een Belgische stad" Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3" HorizontalOptions="Center" TextColor="White" FontAttributes="Bold" FontSize="Medium" />
            <Label x:Name="LblNaam" Text="Naam:" Grid.Row="1" Grid.Column="0" VerticalOptions="Center" Style="{StaticResource labelStyle}" TextColor="#C0C0C0" />
            <Entry x:Name="EntryNaam" Grid.Row="1" Grid.Column="1" VerticalOptions="Center" Margin="5,0" BackgroundColor="Gray" TextColor="White" />
            <Button x:Name="BtnWeer" Text="Weer" Grid.Row="1" Grid.Column="2" HorizontalOptions="Center" VerticalOptions="Center" BorderWidth="1" BorderColor="White" BackgroundColor="Gray" TextColor="White" Clicked="BtnWeer_Clicked"/>
        </Grid>

        <ScrollView VerticalOptions="FillAndExpand">
            <StackLayout Padding="10,10,10,10" HorizontalOptions="Start">
                <Label Text="Locatie" Style="{StaticResource labelStyle}" />
                <Label Text="{Binding Title}" Style="{StaticResource fieldStyle}" />

                <Label Text="Temperatuur" Style="{StaticResource labelStyle}" />
                <Label Text="{Binding Temperature}" Style="{StaticResource fieldStyle}" />

                <Label Text="Windsnelheid" Style="{StaticResource labelStyle}" />
                <Label Text="{Binding Wind}" Style="{StaticResource fieldStyle}" />

                <Label Text="Vochtigheid" Style="{StaticResource labelStyle}" />
                <Label Text="{Binding Humidity}" Style="{StaticResource fieldStyle}" />

                <Label Text="Zichtbaarheid" Style="{StaticResource labelStyle}" />
                <Label Text="{Binding Visibility}" Style="{StaticResource fieldStyle}" />

                <Label Text="Zonsopkomst" Style="{StaticResource labelStyle}" />
                <Label Text="{Binding Sunrise}" Style="{StaticResource fieldStyle}" />

                <Label Text="Zonsondergang" Style="{StaticResource labelStyle}" />
                <Label Text="{Binding Sunset}" Style="{StaticResource fieldStyle}" />
            </StackLayout>
        </ScrollView>
    </StackLayout>
</ContentPage>

Merk alle Bindings die gelegd zijn om de specifieke weer-informatie weer te geven.

  • Voeg de onderstaande code-behind toe aan MainPage.xaml.cs.
using System;
using Xamarin.Forms;

namespace WeerApp
{
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();
        }

        private async void BtnWeer_Clicked(object sender, EventArgs e)
        {
            Weather weather = await Core.GetWeather(EntryNaam.Text);
            BindingContext = weather;
        }
    }
}

Bij het klikken op de knop wordt het weer opgevraagd gebruikmakend van de functie Core.GetWeather(EntryNaam.Text)die geprogrammeerd is Core.cs en een Weather-type teruggeeft Weather weather = await Core.GetWeather(EntryNaam.Text);.

Het opgevraagde Weather-type wordt vervolgend verbonden met de pagina zelf, zodat alle Bindings van de XAML hun respectievelijke waarde krijgen BindingContext = weather;.

Dit is een mooi voorbeeld van asynchroon programmeren.


Behandelde Basiscompetenties uit de module ICT Programmeren – Integratie externe functionaliteiten

  • IC BC024 – * kan zijn eigen deskundigheid inzake ICT opbouwen
  • IC BC232 – kan digitale tools gebruiken om modellen, simulaties en visualisaties van de realiteit te maken
  • IC BC254 – kan externe content integreren en structureren
  • IC BC258 – houdt rekening met regelgeving m.b.t. licenties voor het gebruik en de publicatie van broncode
  • IC BC288 – kan ICT-problemen oplossen

Geef een reactie

  • Abonneer je op deze website d.m.v. e-mail

    Voer je e-mailadres in om je in te schrijven op deze website en e-mailmeldingen te ontvangen van nieuwe berichten.