Prism for Xamarin Forms – Handling platform specific code (Part 4)

Xamarin Forms is cool because it allows to share not just the business logic but also the user interface, unlike the traditional Xamarin approach, which requires to create multiple projects with its own user experience and features. However, at some point, even with Xamarin Forms you have to deal with platform specific code: unless your application leverages only plain and simple features that can be embedded into a PCL (like in the sample project we’ve created in the previous posts, where we simply downloaded some data from a REST API and we displayed it to the user), sooner or later you will have to use a feature that requires to write code which is different based on the target platform. There are many samples of this scenario: one of the most common is geo localization. Android, iOS and Windows offer a way to geo localize the user, but every platform uses its own approach and APIs, so you can’t include them in the Portable Class Library, since these APIs aren’t shared among the platform.

Luckily, to make the developer’s life easier, Xamarin has created many plugins for the most common scenarios, like geo localization, file system access, network, etc. which are available on NuGet or GitHub (https://github.com/xamarin/XamarinComponents)

However, not all the scenarios are covered, so it may easily happen that you are required to implement your own plugin. Xamarin Forms includes an infrastructure to handle this requirement in an easy way, based on a class called DependencyService. From a high level, here is how it works:

  1. In your PCL you create an interface, which describes the methods you want to use in your shared code (for example, you could create an interface called IGeolocatorService which offers a GetPosition() method to retrieve the current location of the user). However, since it’s an interface, it describes just the operations you want to perform, without actually implementing them.
  2. In every platform specific project, you create a class that implement this interface, using the actual APIs provided by the platform. This means that, for example, your Android project will contain an AndroidGeolocatorService, which will contain the actual implementation of the GetPosition() method using the Android APIs. These classes have to be decorated with a special attribute provided by Xamarin Forms called Dependency with, as parameter, a reference to the type of the class itself:
[assembly: Dependency(typeof(AndroidGeolocatorService))]
namespace InfoSeries.Droid.Services
{
    public class AndroidGeolocatorService: IGeolocatorService
    {
        public async Coordinates GetPosition()
        {
            //implementation using Android APIs
        }
    }
}

Thanks to this attribute, you are now able to use the DependencyService class and the Get<T>() method (where T is the interface type) in your PCL to get the proper implementation of the service, based on the platform where the app is running. Consequently, let’s say that in your PCL you have, at some point, the following code:

IGeolocatorService service = DependencyService.Get<IGeolocatorService>();
var result = service.GetPosition();

When the Xamarin Forms app is launched on an Android device, the Get<IGeolocatorService>() method will return an instance of the AndroidGeolocationService class; vice versa, if the app is launched on a Windows 10 device, the method will return an instance of the UwpGeolocationService class, which would have been created into the specific UWP project of the solution.

So far, so good. However, to reach this goal in our MVVM application, we would need to use the DependencyService class in a ViewModel, which isn’t a great approach: using a static property in a ViewModel makes things harder to test. Additionally, this approach would require us to use two different approaches based on the service type:

  1. If it’s a non platform specific service (like the TsApiService class we created in the previous posts to interact with the TrackSeries APIs), we register it into the Prism container and we let it automatically be injected into the ViewModel’s constructor.
  2. If it’s a platform specific service (like the previous AndroidGeolocatorService class), we have to access to it through the DependencyService class and not through the standard Prims container.

With other MVVM frameworks, a typical workaround is to use the DependencyService in the framework’s bootstrapper to get the platform specific instance and then register it into the dependency container we’re using. This way, we can continue to leverage the usual approach to simply add a parameter in the ViewModel’s constructor and to have its implementation automatically injected. This is made possible by the fact that basically all the dependency containers allow to register not only a generic type (which means that, in this case, the container will create a new instance of the class when it’s requested) but also to assign a specific implementation to an interface.

Here is a sample code of how it would work:

protected override void RegisterTypes()
{
    Container.RegisterTypeForNavigation<NavigationPage>();
    Container.RegisterTypeForNavigation<MainPage>();
    Container.RegisterTypeForNavigation<DetailPage>();
    Container.RegisterType<ITsApiService, TsApiService>();

    var geoService = DependencyService.Get<IGeolocationService>();
    Container.RegisterInstance<IGeolocationService>(geoService);

}

However, Prism is smarter than that and it’s automatically able to register into its container every class he finds in each platform specific project decorated with the Dependency attribute. You can find a real example in the InfoSeries app on my GitHub repository: https://github.com/qmatteoq/XamarinForms-Prism/tree/master/InfoSeries

I’ve decided to implement a feature that allows a user to share, from within the detail page of a TV Show, the poster image of the show. This is something that needs to be implemented in a different way for each platform (since each of them has its own unique APIs to share content) and we can’t leverage an existing plugin (since the one available in the Xamarin repository supports only text sharing). As such, I’ve created in the Xamarin Forms Portable Class Library the following interface:

public interface IShareService
{
    Task SharePoster(string title, string image);
}

The interface simply describes an asynchronous method, called ShareShirt(), which accepts as parameter the title of the show and the path of the image to share. The next step is to implement this interface in every platform specific project. I won’t go into the details, because it would be out of scope for the post but, for example, here is how it looks the implementation in the Android project:

using System;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
using Android.App;
using Android.Content;
using InfoSeries.Droid.Services;
using InfoSeries.Services;
using Xamarin.Forms;
using Environment = Android.OS.Environment;

[assembly: Dependency(typeof(AndroidShareService))]
namespace InfoSeries.Droid.Services
{
    public class AndroidShareService: IShareService
    {
        public async Task SharePoster(string title, string image)
        {
            var intent = new Intent(Intent.ActionSend);
            intent.SetType("image/png");
            Guid guid = Guid.NewGuid();
            var path = Environment.GetExternalStoragePublicDirectory(Environment.DataDirectory
                                                                + Java.IO.File.Separator + guid + ".png");

            HttpClient client = new HttpClient();
            var httpResponse = await client.GetAsync(image);
            byte[] imageBuffer = await httpResponse.Content.ReadAsByteArrayAsync();

            if (File.Exists(path.AbsolutePath))
            {
                File.Delete(path.AbsolutePath);
            }

            using (var os = new System.IO.FileStream(path.AbsolutePath, System.IO.FileMode.Create))
            {
                await os.WriteAsync(imageBuffer, 0, imageBuffer.Length);
            }

            intent.PutExtra(Intent.ExtraStream, Android.Net.Uri.FromFile(path));

            var intentChooser = Intent.CreateChooser(intent, "Share via");

            Activity activity = Forms.Context as Activity;
            activity.StartActivityForResult(intentChooser, 100);
        }
    }
}

As you can see, the class implements the ShareShirt() method by downloading the poster image in the local storage of the app and then, by using specific Android APIs (like Activity or Intent), it starts the sharing operation. As you can see, the class is decorated with the Dependency attribute with, as parameter, the type of the class itself.

Thanks to Prism, that’s all we need to do. Now simply add, in the DetailPageViewModel, a parameter of type IShareService in the class constructor, so that you can use it the command that will be invoked when the user will press the button to share the image. Here is how our updated DetailPageViewModel looks like:

public class DetailPageViewModel : BindableBase, INavigationAware
{
    private readonly IShareService _shareService;
    private SerieFollowersVM _selectedShow;

    public SerieFollowersVM SelectedShow
    {
        get { return _selectedShow; }
        set { SetProperty(ref _selectedShow, value); }
    }

    public DetailPageViewModel(IShareService shareService)
    {
        _shareService = shareService;
    }

    public void OnNavigatedFrom(NavigationParameters parameters)
    {

    }

    public void OnNavigatedTo(NavigationParameters parameters)
    {
        SelectedShow = parameters["show"] as SerieFollowersVM;
    }

    private DelegateCommand _shareItemCommand;

    public DelegateCommand ShareItemCommand
    {
        get
        {
            if (_shareItemCommand == null)
            {
                _shareItemCommand = new DelegateCommand(async () =>
                {
                    string image = SelectedShow.Images.Poster;
                    await _shareService.SharePoster(SelectedShow.Name, image);
                });
            }

            return _shareItemCommand;
        }
    }
}

We have added an IShareService parameter in the constructor and we have defined a DelegateCommand called ShareItemCommand: when it’s invoked, it will simply call the ShareShirt() method exposed by the IShareService interface, passing as parameter the name of the show and the URL of the poster image (which can be both retrieved from the SelectedShow property).

In the end, in the DetailPage.xaml we have added a ToolbarItem control, which adds a new button in the UI’s toolbar (which is rendered in a different way based on the platform, for example on UWP it’s rendered as a button in the CommandBar):

<ContentPage.ToolbarItems>
  <ToolbarItem Text="Share" Command="{Binding Path=ShareItemCommand}" Order="Secondary"/>
</ContentPage.ToolbarItems>
Screenshot_2016-08-22-14-46-47 Screenshot_2016-08-22-14-46-38

 

Nothing special here: the control has a text and it’s connected through binding to the ShareItemCommand we have previously defined in the ViewModel. Now launch the application on an Android device or emulator, choose one TV Show and use the new share option we’ve just added: automagically, Android will show us the share chooser, which will allow the user to choose which target application will receive the image. As you can see, we didn’t have to register anything related to the IShareService in the App class: Prism did everything on its own. Of course, if we want to achieve the same result also when the app is running on iOS or on Windows 10, we need to create also an implementation of the IShareService interface in the other platform specific projects.

Pretty cool, isn’t it?

Wrapping up

We have concluded our journey in learning how the most recent version of the Prism framework has been greatly improved, specifically when it comes to support Xamarin Forms. Thanks to Prism and Xamarin, it will be much easier to create great cross platform application using the MVVM pattern and leveraging the same skills you have learned as a developer by creating WPF, Silverlight, Windows Store or UWP apps. As a final reminder, don’t forger that all the samples used in this series of posts are available on my GitHub account: https://github.com/qmatteoq/XamarinForms-Prism

Happy coding!

Posted in Xamarin | Tagged , , , | Leave a comment

Prism for Xamarin Forms – Advanced navigation (Part 3)

In the previous post, we’ve expanded a bit our original sample application, by creating a service to interact with the APIs offered by the TrackSeries website, by using it to populate some data in the app and, in the end, by creating a detail page where to see more info about the selected show. This way, we have understood how Prism allows to manage some basic concepts like navigation, page’s lifecycle and dependency injection.

In this post we’re going to see a couple of more advanced concepts which, however, can be fundamental when it comes to develop a real project using Xamarin Forms.

Advanced navigation

If you have tested the previous version of the app, you would have noted some issues with navigation, especially if you have navigated to the detail page of a TV Show. For example, if you test the UWP version on a Windows 10 PC, you will notice that the Back button that is usually available in the top left corner of the chrome of the windows is missing. Or on Android or iOS, the navigation bar which shows the title of the page and the virtual back button is missing, so if your device doesn’t have an actual back button (like an iPhone), you don’t have a way to go back to the home once you are into a show detail page.

Screenshot_2016-08-20-22-51-58

If you have some previous experience with Xamarin Forms you should already have an idea why this problem is happening. Every basic page in a Xamarin Forms app is represented by the ContentPage class, but it can be embedded in other kind of pages to provide more advanced navigation scenarios, like a NavigationPage (to provide a navigation UI) or a TabbedPage (to show multiple pages in different tabs). In the sample we’ve created so far, we’ve just created two basic pages (of type ContentPage) and then we’ve simply navigated to them using the NavigationService. We haven’t specified anywhere that the pages should have been actually embedded into a NavigationPage to get access to the navigation UI.

To achieve this goal in a plain Xamarin Forms app, we would have done something like this:

public partial class App : Application
{
    public App()
    {
        MainPage = new NavigationPage(new MainPage());
    }     
}

An instance of the MainPage of the application is embedded into a new instance of a NavigationPage: from now on, the NavigationPage will be the container of each ContentPage that the user will see, providing a consistent navigation UI across every page of the app. However, with the Prism approach, we can’t recreate the same approach:

public partial class App : PrismApplication
{
    public App(IPlatformInitializer initializer = null) : base(initializer) { }

    protected override void OnInitialized()
    {
        InitializeComponent();

        NavigationService.NavigateAsync("MainPage");
    }

    protected override void RegisterTypes()
    {
        Container.RegisterTypeForNavigation<MainPage>();
        Container.RegisterTypeForNavigation<DetailPage>();
        Container.RegisterType<ITsApiService, TsApiService>();
    }
}

We have just registered, in the Container, the MainPage and then we have called the NavigateAsync() method of the NavigationService, which accepts only the key that identifies the destination page: we can’t specify, in any way, that this page should be embedded into a NavigationPage.

Luckily, Prism has a smart solution for this problem: deep linking. One of the features offered by Prism for Xamarin Forms, in fact, is to support complex queries as parameters of the NavigateAsync() method. For example, we can specify queries like “MainPage/DetailPage?id=1” to navigate directly to the detail page of the app and, at the same time, passing a parameter called id with value 1. This approach is very useful when, for example, you want to link a specific page of your application from another application, a website or a section of your app.

We can leverage this feature also to achieve the goal of embedding our pages into a NavigationPage: first, we need to register the base NavigationPage type included in Xamarin Forms as a type for navigation in the Container. Then, we can use the query “NavigationPage/MainPage” to tell to the NavigationService that we need to navigate first to the page identified by the NavigationPage key and then to the one identified by the MainPage key. Since the NavigationPage isn’t actually a real page, but just a container, the end result will be the same we’ve seen in the first sample code: the MainPage (and every consequent page in the navigation flow) will be embedded into a NavigationPage.

Here is how our new App class looks like:

public partial class App : PrismApplication
{
    public App(IPlatformInitializer initializer = null) : base(initializer) { }

    protected override void OnInitialized()
    {
        InitializeComponent();

        NavigationService.NavigateAsync("NavigationPage/MainPage");
    }

    protected override void RegisterTypes()
    {
        Container.RegisterTypeForNavigation<NavigationPage>();
        Container.RegisterTypeForNavigation<MainPage>();
        Container.RegisterTypeForNavigation<DetailPage>();
        Container.RegisterType<ITsApiService, TsApiService>();
    }
}

 

Thanks to this change, now we have a proper navigation bar, as you can see in the following screenshot taken from the Android version:

Screenshot_2016-08-20-22-53-06

Another example of complex deep linking is using query parameters. You can use a navigation query like the following one:

NavigationService.NavigateAsync("FirstPage?id=1&title=First page");

Automatically, the destination page will receive, in the NavigationParams object of the OnNavigatedTo() method, two items: one with key id and value 1 and one with key title and value First page.

public void OnNavigatedTo(NavigationParameters parameters)
{
    string id = parameters["id"].ToString();
    string title = parameters["title"].ToString();

    Title = $"Page with id {id} and title {title}";
}

Eventually, you can use this feature to leverage even more complex navigation flows, which involves container for multiple pages.

Let’s try to better understand this scenario with a real example. We have already talked about the concept that Xamarin Forms offers some pages which doesn’t display any actual content, but that they act as a container for other pages. We’ve already seen an example of this concept: the NavigationPage type doesn’t display any actual content, but it’s a container to add navigation UI and features to a ContentPage. Another similar container is TabbedPage, where every children page is displayed in a different tab.

Let’s say that we want to improve our TV show application and add two sections to the main page, using a TabbedPage control: the first section will display the list of upcoming shows, so it will be a simple ContentPage; the second section, instead, will display a list of the available TV Shows and, as such, it will be embedded into a NavigationPage, because we want to provide the ability to tap on a show and see more info about the selected show.

This is how our project would look like:

prism4

The application has two main sections (UpcomingShowsPage and ShowsListPage) and a detail page (DetailPage), each of them with its own ViewModel. The main pages are presented to the user as two sections of a tab control, which is defined in the MainTabbedPage.xaml file:

<?xml version="1.0" encoding="utf-8" ?>
<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
            xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
            xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
            xmlns:views="clr-namespace:PrismTest.Views;assembly=PrismTest"
            prism:ViewModelLocator.AutowireViewModel="True"
            Title="Main page"
            x:Class="PrismTest.Views.MainTabbedPage">

  <views:UpcomingShowsPage />
  <NavigationPage Title="Shows list">
    <x:Arguments>
      <views:ShowsListPage />
    </x:Arguments>
  </NavigationPage>

</TabbedPage>

The UpcomingShowsPage is a simple ContentPage, while the ShowsListPsage is embedded into a NavigationPage, since the user has the chance to move to the DetailPage to see more info about the selected TV show. Now let’s say that, as a consequence of an user action, we want to redirect the user to the detail page of a specific TV Show.  With standard Xamarin Forms it wouldn’t a hard task to accomplish, but the real challenge would be to retain the whole navigation stack: we want to bring the user to the detail page, but we also want that, when he presses the back button, he follows the proper backward navigation flow (so DetailPage –> ShowListPage). Additionally, everything should be done by keeping the focus in the second tab, since ShowListPage is part of a TabbedPage.

Sounds complicated, isn’t it? Well, here is how it’s easy to achieve this goal with Prism:

public partial class App : PrismApplication
{
    public App(IPlatformInitializer initializer = null) : base(initializer) { }

    protected override void OnInitialized()
    {
        InitializeComponent();

        NavigationService.NavigateAsync("MainTabbedPage/NavigationPage/ShowsListPage/DetailPage?id=1");
    }

    protected override void RegisterTypes()
    {
        Container.RegisterTypeForNavigation<UpcomingShowsPage>();
        Container.RegisterTypeForNavigation<ShowsListPage>();
        Container.RegisterTypeForNavigation<DetailPage>();
        Container.RegisterTypeForNavigation<MainTabbedPage>();
        Container.RegisterTypeForNavigation<NavigationPage>();
    }
}

As usual, in the RegisterTypes() method, we have registered every page that compose our application. Then, we invoke the NavigateAsync() method of the NavigationService passing the whole path we want to follow: MainTabbedPage/NavigationPage/ShowsListPage/DetailPage with an additional parameter that identifies the selected TV Show, that we can intercept in the OnNavigatedTo() method of the DetailPageViewModel.

public class DetailPageViewModel : BindableBase, INavigationAware
{
    private readonly ITsApiService _tsApiService;
    private SerieInfoVM _selectedShow;

    public SerieInfoVM SelectedShow
    {
        get { return _selectedShow; }
        set { SetProperty(ref _selectedShow, value); }
    }

    public DetailPageViewModel(ITsApiService tsApiService)
    {
        _tsApiService = tsApiService;
    }

    public void OnNavigatedFrom(NavigationParameters parameters)
    {

    }

    public async void OnNavigatedTo(NavigationParameters parameters)
    {
        int id = Convert.ToInt32(parameters["id"]);
        SelectedShow = await _tsApiService.GetSerieById(id);
    }
}

Thanks to Prism, other than achieving the goal of redirecting the user directly to the page we’re interested into, we have also retained the full backward navigation stack. The following images show you what happens when you press the Back button:

Screenshot_2016-08-22-11-40-17 Screenshot_2016-08-22-11-42-41

As you can see, from the detail page of the show (the screenshot on the left) we’ve been properly redirected to the previous page in the stack (the shows list, displayed in the screenshot on the right), even if we didn’t actually visited it during our navigation flow (since the app was directly loaded in the detail page). Additionally, we’ve kept the focus on the second tab (Shows list) so the user has still the chance, at any time, to move to the first one (Upcoming shows). Pretty cool, isn’t it?

Attention: in the current Prism implementation dealing with the TabbedPage control has a downside. In our example, as we’ve seen from the screenshot of the project’s structure, the Upcoming Shows section is represented by a standard page (UpcomingShowsPage) with its own ViewModel (UpcomingShowsPageViewModel), which implements the INavigationAware interface with the goal to leverage the OnNavigatedTo() method to load the data (in our case, the list of upcoming shows). As such, the UpcomingShowsPageViewModel would look like this:

public class UpcomingShowsPageViewModel : BindableBase, INavigationAware
{
    private readonly ITsApiService _tsApiService;

    private ObservableCollection<SerieFollowersVM> _topSeries;

    public ObservableCollection<SerieFollowersVM> TopSeries
    {
        get { return _topSeries; }
        set { SetProperty(ref _topSeries, value); }
    }

    public UpcomingShowsPageViewModel(ITsApiService tsApiService)
    {
        _tsApiService = tsApiService;
    }

    public void OnNavigatedFrom(NavigationParameters parameters)
    {

    }

    public async void OnNavigatedTo(NavigationParameters parameters)
    {
        var series = await _tsApiService.GetStatsTopSeries();
        TopSeries = new ObservableCollection<SerieFollowersVM>(series);
    }
}

However, if you tap on the Upcoming Shows tab you’ll notice that nothing won’t happen and the OnNavigatedTo() method won’t be triggered. The reason is that the navigation methods implemented by the INavigationAware interface are raised only when you navigate using the Prism NavigationService. If the navigation happens without leveraging it (like, in this case, where the navigation to the other tab is handled directly by the Xamarin Forms infrastructure), the OnNavigatedTo() method in the ViewModel will never be invoked and, as such, our data will never be loaded. There’s a solution in the works, which involves using a behavior, but it hasn’t been included yet in the current Prism version. You can follow the discussion and the proposed solution on GitHub: https://github.com/PrismLibrary/Prism/issues/650

Wrapping up

In this post we’ve learned how to leverage the deep linking featured offered by Prism, which allows to handle complex navigation patterns in an easy way, keeping at the same time the proper backward navigation path. In the next post (which will be the last one), we’ll see instead how to use platform specific code in a Xamarin Forms application created with Prism. You can find all the samples on my GitHub repository: the InfoSeries one (https://github.com/qmatteoq/XamarinForms-Prism/tree/master/InfoSeries) shows you the first approach (simple navigation using a NavigationPage), the DeepNavigation one (https://github.com/qmatteoq/XamarinForms-Prism/tree/master/DeepNavigation) instead shows you the advanced deep link feature we’ve seen in the second part of the post. Happy coding!

Posted in Xamarin | Tagged , , , | Leave a comment

Prism for Xamarin Forms – Basic navigation and dependency injection (Part 2)

In the previous post we’ve started to see the basic concepts on how to leverage the new version of Prism (6.2) to implement the MVVM pattern in a Xamarin Forms app. So far, we haven’t seen nothing special that we couldn’t do also with another framework: we have just created a View, a ViewModel and we connected them through binding. In this post, we’re going to see how Prism can be helpful to handle a very common scenario which can be hard to handle in a MVVM app: navigation and page’s lifecycle.

As we’ve mentioned in the previous post, we’re going to create a simple client for TrackSeries, a website which offers many information about TV Shows. The app will display the current top series and will allow the user to discover more about them. To achieve this goal, we can use a set of REST services provided by the website, which are very simple to use and which follow the standard best practices of dealing with REST services: you invoke a URL using a HTTP command and you receive back a JSON response with the result.

For example, if you want to know which are the top series at the moment, you can just perform a HTTP GET request to the following URL: https://api.trackseries.tv/v1/Stats/TopSeries The service will return you a JSON response with all the details about the top series:

[
   {
      "id":121361,
      "name":"Game of Thrones",
      "followers":10230,
      "firstAired":"2011-04-17T21:00:00-04:00",
      "country":"us",
      "overview":"Seven noble families fight for control of the mythical land of Westeros. Friction between the houses leads to full-scale war. All while a very ancient evil awakens in the farthest north. Amidst the war, a neglected military order of misfits, the Night's Watch, is all that stands between the realms of men and the icy horrors beyond.",
      "runtime":55,
      "status":"Continuing",
      "network":"HBO",
      "airDay":"Sunday",
      "airTime":"9:00 PM",
      "contentRating":"TV-MA",
      "imdbId":"tt0944947",
      "tvdbId":121361,
      "tmdbId":1399,
      "language":"en",
      "images":{
         "poster":"http://static.trackseries.tv/banners/posters/121361-49.jpg",
         "fanart":"http://static.trackseries.tv/banners/fanart/original/121361-15.jpg",
         "banner":"http://static.trackseries.tv/banners/graphical/121361-g22.jpg"
      },
      "genres":[
         {
            "id":2,
            "name":"Adventure"
         },
         {
            "id":4,
            "name":"Drama"
         },
         {
            "id":5,
            "name":"Fantasy"
         }
      ],
      "added":"2014-08-08T13:30:46.227",
      "lastUpdated":"2016-08-18T03:03:50.05",
      "followedByUser":false,
      "slugName":"game-of-thrones"
   },
   {
      "id":257655,
      "name":"Arrow",
      "followers":7517,
      "firstAired":"2012-10-10T20:00:00-04:00",
      "country":"us",
      "overview":"Oliver Queen and his father are lost at sea when their luxury yacht sinks. His father doesn't survive. Oliver survives on an uncharted island for five years learning to fight, but also learning about his father's corruption and unscrupulous business dealings. He returns to civilization a changed man, determined to put things right. He disguises himself with the hood of one of his mysterious island mentors, arms himself with a bow and sets about hunting down the men and women who have corrupted his city.",
      "runtime":45,
      "status":"Continuing",
      "network":"The CW",
      "airDay":"Wednesday",
      "airTime":"8:00 PM",
      "contentRating":"TV-14",
      "imdbId":"tt2193021",
      "tvdbId":257655,
      "tmdbId":1412,
      "language":"en",
      "images":{
         "poster":"http://static.trackseries.tv/banners/posters/257655-8.jpg",
         "fanart":"http://static.trackseries.tv/banners/fanart/original/257655-47.jpg",
         "banner":"http://static.trackseries.tv/banners/graphical/257655-g9.jpg"
      },
      "genres":[
         {
            "id":1,
            "name":"Action"
         },
         {
            "id":2,
            "name":"Adventure"
         },
         {
            "id":4,
            "name":"Drama"
         }
      ],
      "added":"2014-08-08T13:37:00.133",
      "lastUpdated":"2016-08-15T03:11:32.013",
      "followedByUser":false,
      "slugName":"arrow"
   },
   {
      "id":153021,
      "name":"The Walking Dead",
      "followers":7185,
      "firstAired":"2010-10-31T21:00:00-04:00",
      "country":"us",
      "overview":"The world we knew is gone. An epidemic of apocalyptic proportions has swept the globe causing the dead to rise and feed on the living. In a matter of months society has crumbled. In a world ruled by the dead, we are forced to finally start living. Based on a comic book series of the same name by Robert Kirkman, this AMC project focuses on the world after a zombie apocalypse. The series follows a police officer, Rick Grimes, who wakes up from a coma to find the world ravaged with zombies. Looking for his family, he and a group of survivors attempt to battle against the zombies in order to stay alive.\n",
      "runtime":50,
      "status":"Continuing",
      "network":"AMC",
      "airDay":"Sunday",
      "airTime":"9:00 PM",
      "contentRating":"TV-MA",
      "imdbId":"tt1520211",
      "tvdbId":153021,
      "tmdbId":1402,
      "language":"en",
      "images":{
         "poster":"http://static.trackseries.tv/banners/posters/153021-38.jpg",
         "fanart":"http://static.trackseries.tv/banners/fanart/original/153021-77.jpg",
         "banner":"http://static.trackseries.tv/banners/graphical/153021-g44.jpg"
      },
      "genres":[
         {
            "id":1,
            "name":"Action"
         },
         {
            "id":4,
            "name":"Drama"
         },
         {
            "id":6,
            "name":"Horror"
         },
         {
            "id":20,
            "name":"Suspense"
         }
      ],
      "added":"2014-08-08T13:31:18.617",
      "lastUpdated":"2016-08-18T03:04:00.28",
      "followedByUser":false,
      "slugName":"the-walking-dead"
   },
   {
      "id":279121,
      "name":"The Flash (2014)",
      "followers":7069,
      "firstAired":"2014-10-07T20:00:00-04:00",
      "country":"us",
      "overview":"After a particle accelerator causes a freak storm, CSI Investigator Barry Allen is struck by lightning and falls into a coma. Months later he awakens with the power of super speed, granting him the ability to move through Central City like an unseen guardian angel. Though initially excited by his newfound powers, Barry is shocked to discover he is not the only \"meta-human\" who was created in the wake of the accelerator explosion – and not everyone is using their new powers for good. Barry partners with S.T.A.R. Labs and dedicates his life to protect the innocent. For now, only a few close friends and associates know that Barry is literally the fastest man alive, but it won't be long before the world learns what Barry Allen has become... The Flash.",
      "runtime":45,
      "status":"Continuing",
      "network":"The CW",
      "airDay":"Tuesday",
      "airTime":"8:00 PM",
      "contentRating":"TV-14",
      "imdbId":"tt3107288",
      "tvdbId":279121,
      "tmdbId":60735,
      "language":"en",
      "images":{
         "poster":"http://static.trackseries.tv/banners/posters/279121-37.jpg",
         "fanart":"http://static.trackseries.tv/banners/fanart/original/279121-23.jpg",
         "banner":"http://static.trackseries.tv/banners/graphical/279121-g7.jpg"
      },
      "genres":[
         {
            "id":1,
            "name":"Action"
         },
         {
            "id":2,
            "name":"Adventure"
         },
         {
            "id":4,
            "name":"Drama"
         },
         {
            "id":8,
            "name":"Science-Fiction"
         }
      ],
      "added":"2014-08-08T13:45:59.087",
      "lastUpdated":"2016-08-17T03:09:18.7",
      "followedByUser":false,
      "slugName":"the-flash-2014"
   },
   {
      "id":80379,
      "name":"The Big Bang Theory",
      "followers":6922,
      "firstAired":"2007-09-25T20:00:00-04:00",
      "country":"us",
      "overview":"What happens when hyperintelligent roommates Sheldon and Leonard meet Penny, a free-spirited beauty moving in next door, and realize they know next to nothing about life outside of the lab. Rounding out the crew are the smarmy Wolowitz, who thinks he's as sexy as he is brainy, and Koothrappali, who suffers from an inability to speak in the presence of a woman.",
      "runtime":25,
      "status":"Continuing",
      "network":"CBS",
      "airDay":"Monday",
      "airTime":"8:00 PM",
      "contentRating":"TV-PG",
      "imdbId":"tt0898266",
      "tvdbId":80379,
      "tmdbId":1418,
      "language":"en",
      "images":{
         "poster":"http://static.trackseries.tv/banners/posters/80379-43.jpg",
         "fanart":"http://static.trackseries.tv/banners/fanart/original/80379-38.jpg",
         "banner":"http://static.trackseries.tv/banners/graphical/80379-g28.jpg"
      },
      "genres":[
         {
            "id":3,
            "name":"Comedy"
         }
      ],
      "added":"2014-08-08T13:27:13.18",
      "lastUpdated":"2016-08-18T03:03:10.947",
      "followedByUser":false,
      "slugName":"the-big-bang-theory"
   },
   {
      "id":176941,
      "name":"Sherlock",
      "followers":6387,
      "firstAired":"2010-07-25T20:30:00+01:00",
      "country":"gb",
      "overview":"Sherlock is a British television crime drama that presents a contemporary adaptation of Sir Arthur Conan Doyle's Sherlock Holmes detective stories. Created by Steven Moffat and Mark Gatiss, it stars Benedict Cumberbatch as Sherlock Holmes and Martin Freeman as Doctor John Watson.",
      "runtime":90,
      "status":"Continuing",
      "network":"BBC One",
      "airDay":"Sunday",
      "airTime":"8:30 PM",
      "contentRating":"TV-14",
      "imdbId":"tt1475582",
      "tvdbId":176941,
      "tmdbId":19885,
      "language":"en",
      "images":{
         "poster":"http://static.trackseries.tv/banners/posters/176941-11.jpg",
         "fanart":"http://static.trackseries.tv/banners/fanart/original/176941-3.jpg",
         "banner":"http://static.trackseries.tv/banners/graphical/176941-g5.jpg"
      },
      "genres":[
         {
            "id":2,
            "name":"Adventure"
         },
         {
            "id":4,
            "name":"Drama"
         },
         {
            "id":14,
            "name":"Crime"
         },
         {
            "id":16,
            "name":"Mystery"
         },
         {
            "id":21,
            "name":"Thriller"
         }
      ],
      "added":"2014-08-08T13:32:27.247",
      "lastUpdated":"2016-08-17T03:07:09.747",
      "followedByUser":false,
      "slugName":"sherlock"
   },
   {
      "id":263365,
      "name":"Marvel's Agents of S.H.I.E.L.D.",
      "followers":5372,
      "firstAired":"2013-09-24T22:00:00-04:00",
      "country":"us",
      "overview":"Phil Coulson (Clark Gregg, reprising his role from \"The Avengers\" and \"Iron Man\" ) heads an elite team of fellow agents with the worldwide law-enforcement organization known as SHIELD (Strategic Homeland Intervention Enforcement and Logistics Division), as they investigate strange occurrences around the globe. Its members -- each of whom brings a specialty to the group -- work with Coulson to protect those who cannot protect themselves from extraordinary and inconceivable threats, including a formidable group known as Hydra.",
      "runtime":45,
      "status":"Continuing",
      "network":"ABC (US)",
      "airDay":"Tuesday",
      "airTime":"10:00 PM",
      "contentRating":"TV-PG",
      "imdbId":"tt2364582",
      "tvdbId":263365,
      "tmdbId":1403,
      "language":"en",
      "images":{
         "poster":"http://static.trackseries.tv/banners/posters/263365-16.jpg",
         "fanart":"http://static.trackseries.tv/banners/fanart/original/263365-26.jpg",
         "banner":"http://static.trackseries.tv/banners/graphical/263365-g7.jpg"
      },
      "genres":[
         {
            "id":1,
            "name":"Action"
         },
         {
            "id":2,
            "name":"Adventure"
         },
         {
            "id":4,
            "name":"Drama"
         },
         {
            "id":5,
            "name":"Fantasy"
         },
         {
            "id":8,
            "name":"Science-Fiction"
         }
      ],
      "added":"2014-08-08T13:39:45.967",
      "lastUpdated":"2016-08-18T03:05:30.987",
      "followedByUser":false,
      "slugName":"marvels-agents-of-shield"
   },
   {
      "id":81189,
      "name":"Breaking Bad",
      "followers":5227,
      "firstAired":"2008-01-20T21:00:00-04:00",
      "country":"us",
      "overview":"Walter White, a struggling high school chemistry teacher, is diagnosed with advanced lung cancer. He turns to a life of crime, producing and selling methamphetamine accompanied by a former student, Jesse Pinkman, with the aim of securing his family's financial future before he dies.",
      "runtime":45,
      "status":"Ended",
      "network":"AMC",
      "airDay":"Sunday",
      "airTime":"9:00 PM",
      "contentRating":"TV-MA",
      "imdbId":"tt0903747",
      "tvdbId":81189,
      "tmdbId":1396,
      "language":"en",
      "images":{
         "poster":"http://static.trackseries.tv/banners/posters/81189-10.jpg",
         "fanart":"http://static.trackseries.tv/banners/fanart/original/81189-21.jpg",
         "banner":"http://static.trackseries.tv/banners/graphical/81189-g21.jpg"
      },
      "genres":[
         {
            "id":4,
            "name":"Drama"
         },
         {
            "id":14,
            "name":"Crime"
         },
         {
            "id":20,
            "name":"Suspense"
         },
         {
            "id":21,
            "name":"Thriller"
         }
      ],
      "added":"2014-08-08T13:27:33.917",
      "lastUpdated":"2016-08-13T03:01:47.063",
      "followedByUser":false,
      "slugName":"breaking-bad"
   },
   {
      "id":247808,
      "name":"Suits",
      "followers":4835,
      "firstAired":"2011-06-24T21:00:00-04:00",
      "country":"us",
      "overview":"Suits follows college drop-out Mike Ross, who accidentally lands a job with one of New York's best legal closers, Harvey Specter. They soon become a winning team with Mike's raw talent and photographic memory, and Mike soon reminds Harvey of why he went into the field of law in the first place.",
      "runtime":45,
      "status":"Continuing",
      "network":"USA Network",
      "airDay":"Wednesday",
      "airTime":"9:00 PM",
      "contentRating":"TV-14",
      "imdbId":"tt1632701",
      "tvdbId":247808,
      "tmdbId":37680,
      "language":"en",
      "images":{
         "poster":"http://static.trackseries.tv/banners/posters/247808-27.jpg",
         "fanart":"http://static.trackseries.tv/banners/fanart/original/247808-43.jpg",
         "banner":"http://static.trackseries.tv/banners/graphical/247808-g17.jpg"
      },
      "genres":[
         {
            "id":4,
            "name":"Drama"
         }
      ],
      "added":"2014-08-08T13:33:45.423",
      "lastUpdated":"2016-08-18T03:04:21.37",
      "followedByUser":false,
      "slugName":"suits"
   },
   {
      "id":274431,
      "name":"Gotham",
      "followers":4718,
      "firstAired":"2014-09-23T20:00:00-04:00",
      "country":"us",
      "overview":"An action-drama series following rookie detective James Gordon as he battles villains and corruption in pre-Batman Gotham City.",
      "runtime":45,
      "status":"Continuing",
      "network":"FOX (US)",
      "airDay":"Monday",
      "airTime":"8:00 PM",
      "contentRating":"TV-14",
      "imdbId":"tt3749900",
      "tvdbId":274431,
      "tmdbId":60708,
      "language":"en",
      "images":{
         "poster":"http://static.trackseries.tv/banners/posters/274431-17.jpg",
         "fanart":"http://static.trackseries.tv/banners/fanart/original/274431-22.jpg",
         "banner":"http://static.trackseries.tv/banners/graphical/274431-g6.jpg"
      },
      "genres":[
         {
            "id":1,
            "name":"Action"
         },
         {
            "id":4,
            "name":"Drama"
         },
         {
            "id":8,
            "name":"Science-Fiction"
         },
         {
            "id":14,
            "name":"Crime"
         },
         {
            "id":21,
            "name":"Thriller"
         }
      ],
      "added":"2014-08-08T13:44:55.4",
      "lastUpdated":"2016-08-17T03:08:55.473",
      "followedByUser":false,
      "slugName":"gotham"
   }
]

To use these APIs in the application, I’ve created a class called TsApiService with a set of methods that, by using the HttpClient class of the .NET Framework and the popular JSON.NET library, takes care of downloading the JSON, parsing it and returning a set of objects that can be easily manipulated using C#. To structure my solution in a better way, I’ve decided to place all the classes related to the communication with the REST APIs (like services and entities) in another Portable Class Library, called InfoSeries.Core, which is a different PCL than the one that hosts the real Xamarin Forms app.

Here is, for example, how the method that takes care of parsing the previous JSON and to return a list of C# objects looks like:

public async Task<List<SerieFollowersVM>> GetStatsTopSeries()
{
    using (HttpClient client = new HttpClient())
    {
        try
        {
            var response = await client.GetAsync("https://api.trackseries.tv/v1/Stats/TopSeries");
            if (!response.IsSuccessStatusCode)
            {
                var error = await response.Content.ReadAsAsync<TrackSeriesApiError>();
                var message = error != null ? error.Message : "";
                throw new TrackSeriesApiException(message, response.StatusCode);
            }
            return await response.Content.ReadAsAsync<List<SerieFollowersVM>>();
        }
        catch (HttpRequestException ex)
        {
            throw new TrackSeriesApiException("", false, ex);
        }
        catch (UnsupportedMediaTypeException ex)
        {
            throw new TrackSeriesApiException("", false, ex);
        }
    }
}

The GetAsync() method of the HttpClient class performs a GET request to the URL, returning as result the string containing the JSON response. This result is stored into the Content property of the response: in case the request is successful (we use the IsSuccessStatusCode property to check this condition), we use the ReadAsAsync<T> method exposed by the Content property to automatically convert the JSON result in a collection of SerieFollowersVM object. SerieFollowersVM is nothing else than a class that maps each property of the JSON response (like name, country or runtime) into a C# property:

public class SerieFollowersVM
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int Followers { get; set; }
    public DateTimeOffset FirstAired { get; set; }
    public string Country { get; set; }
    public string Overview { get; set; }
    public int Runtime { get; set; }
    public string Status { get; set; }
    public string Network { get; set; }
    public DayOfWeek? AirDay { get; set; }
    public string AirTime { get; set; }
    public string ContentRating { get; set; }
    public string ImdbId { get; set; }
    public int TvdbId { get; set; }
    public string Language { get; set; }
    public ImagesSerieVM Images { get; set; }
    public ICollection<GenreVM> Genres { get; set; }
    public DateTime Added { get; set; }
    public DateTime LastUpdated { get; set; }
    public string SlugName { get; set; }
}

In the full sample on GitHub you’ll find many classes like this (which maps the various JSON responses returned by the TrackSeries APIs). Additionally, the TsApiService will implement additional methods, one for each API we want to leverage in our application. I won’t explain in details each method, since it would be out of scope for the article: you can see all the details on GitHub. For the purpose of this post, you just need to know that the service simply exposes a set of methods that we can use in the various ViewModels to retrieve info about the available TV Shows.

Note: by default, the HttpClient class doesn’t offer a ReadAsAsync<T> method, which is able to automatically deserialize the JSON response into C# objects. To get access to this extension method, we need to add the Microsoft.AspNet.WebApi.Client NuGet package to our Portable Class Library. To get it properly working, you need to add this package to every project of the solution (the Xamarin Forms PCL, the Core PCL and all the platform specific projects).

To properly leverage dependency injection, however, we need an interface that describes the operations offered by the TsApiService class. Here is how our interface looks like:

public interface ITsApiService
{
    Task<List<SerieFollowersVM>> GetStatsTopSeries();
    Task<SerieVM> GetSerieByIdAll(int id);
    Task<SerieInfoVM> GetSerieById(int id);
    Task<List<SerieSearch>> GetSeriesSearch(string name);
    Task<SerieFollowersVM> GetStatsSerieHighlighted();
}

Now that we have a service, we can learn how, thanks to Prism, we can register it into its dependency container and have it automatically injected in our ViewModels. Actually, from this point of view, there’s nothing special to highlight: the approach is the same we would use with any other MVVM framework which leverages a dependency injection approach. First, we need to register the association between the interface and the implementation we want to use in the container. In case of Prism, we need to do it in the RegisterTypes() method of the App class, by using the Container object and the RegisterType<T, Y>() method (where T is the interface and Y is the concrete implementation):

protected override void RegisterTypes()
{
    Container.RegisterTypeForNavigation<MainPage>();
    Container.RegisterType<ITsApiService, TsApiService>();
}

Now, since both the MainPage and the TsApiService are registered in the container, we can get access to it in our ViewModel, by simply adding a parameter in the public constructor, like in the following sample:

public class MainPageViewModel : BindableBase
{
    private readonly ITsApiService _apiService;

    public MainPageViewModel(ITsApiService apiService)
    {
        _apiService = apiService;
    }
}

When the MainPageViewModel class will be loaded, the implementation of the ITsApiService we’ve registered in the container (in our case, the TsApiService class) will be automatically injected into the parameter in the constructor, allowing us to use it in all the other methods and properties we’re going to create in the ViewModel. With this approach, it will be easy for us to change the implementation of the service in case we need it: it will be enough to change the registered type in the App class and, automatically, every ViewModel will start to use the new version.

Handle the navigation’s lifecycle

Now that we have a service that offers a method to retrieve the list of the top series, we need to call it when the ViewModel is loaded: our goal is to display, in the main page of the app, a list of the most trending TV shows. However, we are about to face a common problem when it comes to use the MVVM pattern: the method to retrieve the list of top series is asynchronous but, with the current implementation, the only place where we can perform the data loading is the ViewModel’s constructor, which can’t execute asynchronous calls (in C#, in fact, the constructor of a class can’t be marked with the async keyword and, consequently, you can’t use the await prefix with a method). In a non-MVVM application, this problem would be easy to solve, thanks to the navigation’s lifecycle methods offered basically by every platform. Xamarin Forms makes no exception and we could leverage, in the code behind class of a XAML page, the methods OnAppearing() and OnDisappearing(): since they are events, we can call asynchronous code without issues.

To solve this problem, Prism offers an interface that we can implement in our ViewModels called INavigationAware: when we implement it, we have access to the OnNavigatedTo() and OnNavigatedFrom() events, which we can use to perform data loading or cleanup operations. Here is our MainPageViewModel looks like after implementing this interface:

public class MainPageViewModel : BindableBase, INavigationAware
{
    private readonly TsApiService _apiService;
    private ObservableCollection<SerieFollowersVM> _topSeries;

    public ObservableCollection<SerieFollowersVM> TopSeries
    {
        get { return _topSeries; }
        set { SetProperty(ref _topSeries, value); }
    }

    public MainPageViewModel(TsApiService apiService)
    {
        _apiService = apiService;
    }

    public void OnNavigatedFrom(NavigationParameters parameters)
    {

    }

    public async void OnNavigatedTo(NavigationParameters parameters)
    {
        var result = await _apiService.GetStatsTopSeries();
        TopSeries = new ObservableCollection<SerieFollowersVM>(result);
    }
}

As you can see, now we have implemented a method called OnNavigatedTo(), where we can safely execute our asynchronous calls and load the data: we call the GetStatsTopSeries() method of the TsApiService class and we encapsulate the resulting collection into an ObservableCollection property. This is the property we’re going to connect, through binding, to a ListView control, in order to display the list of TV Shows in the main page.

For completeness, here is how the XAML of the MainPage looks like:

<?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:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
             prism:ViewModelLocator.AutowireViewModel="True"
             x:Class="InfoSeries.Views.MainPage"
             Title="Info Series">
  
  <ContentPage.Resources>
    <ResourceDictionary>
      <DataTemplate x:Key="TopSeriesTemplate">
        <ViewCell>
          <ViewCell.View>
            <Grid>
              <Grid.ColumnDefinitions>
                <ColumnDefinition Width="1*" />
                <ColumnDefinition Width="2*" />
              </Grid.ColumnDefinitions>

              <Image Source="{Binding Images.Poster}" Grid.Column="0" x:Name="TopImage" />
              <StackLayout Grid.Column="1" Margin="12, 0, 0, 0" VerticalOptions="Start">
                <Label Text="{Binding Name}" FontSize="18" TextColor="#58666e" FontAttributes="Bold" />
                <StackLayout Orientation="Horizontal">
                  <Label Text="Runtime: " FontSize="14" TextColor="#58666e" />
                  <Label Text="{Binding Runtime}" FontSize="14" TextColor="#98a6ad" Margin="5, 0, 0, 0" />
                </StackLayout>
                <StackLayout Orientation="Horizontal">
                  <Label Text="Air day: " FontSize="14" TextColor="#58666e" />
                  <Label Text="{Binding AirDay}" FontSize="14" TextColor="#98a6ad" Margin="5, 0, 0, 0" />
                </StackLayout>
                <StackLayout Orientation="Horizontal">
                  <Label Text="Country: " FontSize="14" TextColor="#58666e" />
                  <Label Text="{Binding Country}" FontSize="14" TextColor="#98a6ad" Margin="5, 0, 0, 0" />
                </StackLayout>
                <StackLayout Orientation="Horizontal">
                  <Label Text="Network: " FontSize="14" TextColor="#58666e" />
                  <Label Text="{Binding Network}" FontSize="14" TextColor="#98a6ad" Margin="5, 0, 0, 0" />
                </StackLayout>
              </StackLayout>
            </Grid>
          </ViewCell.View>
        </ViewCell>


      </DataTemplate>
    </ResourceDictionary>
  </ContentPage.Resources>

  <ListView ItemTemplate="{StaticResource TopSeriesTemplate}"
            ItemsSource="{Binding Path=TopSeries}" RowHeight="200"/>
  
</ContentPage>

If you already know Xamarin Forms (or XAML in general), you should find this code easy to understand: the page contains a ListView control, with a template that describes how a single TV show looks like. We display the show’s poster, along with some other info like the title, the runtime, the production country, etc. Since, due to the naming convention, the MainPageViewModel class is already set as BindingContext of the page, we can simply connect them by binding the ItemsSource property of the ListView with the TopSeries collection we’ve previously populated in the ViewModel.

Navigation with parameters

We’ve seen how to leverage the OnNavigatedTo() method to perform data loading, but often this method is useful also for another scenario: retrieving parameters passed by a previous page, which are usually needed to understand the current context (in our sample, in the detail page of our application we need to understand which TV Show the user has selected).

Prism support this feature thanks to a class called NavigationParameters, which can be passed as optional parameter of the NavigationAsync() method of the NavigationService and it’s automatically included as parameter of the OnNavigatedTo() and OnNavigatedFrom() events. Let’s see how to leverage this feature, by adding a detail page to our application, where to display some additional info about the selected show.

The first step is to add both a new page in the Views folder (called DetailPage.xaml) and a new class in the ViewModels folder (called DetailPageViewModel.cs). You need to remember also that every page needs to be registered in the container in the App class, inside the OnRegisterTypes() method:

protected override void RegisterTypes()
{
    Container.RegisterTypeForNavigation<MainPage>();
    Container.RegisterTypeForNavigation<DetailPage>();
    Container.RegisterType<ITsApiService, TsApiService>();
}

Due to the naming convention, we don’t have to do anything special: the new page and the new ViewModel are already connected. Now we need to pass the selected item in the ListView control to the new page. Let’s see, first, how to handle the selection in the MainPage. We’ll get some help by a library created by my dear friend Corrado Cavalli, which allows to implement behaviors in a Xamarin Forms app. Among the available behaviors, one of them is called EventToCommand and it allows us to connect any event exposed by a control to a command defined in the ViewModel. We’re going to use it to connect the ItemTapped event of the ListView control (which is triggered when the user taps on an item in the list) to a command we’re going to create in the MainPageViewModel to trigger the navigation to the detail page.

You can install the package created by Corrado from NuGet: its name is Corcav.Behaviors. To use it, you need to add an additional namespace to the root of the MainPage, like in the following sample:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
             xmlns:behaviors="clr-namespace:Corcav.Behaviors;assembly=Corcav.Behaviors"
             prism:ViewModelLocator.AutowireViewModel="True"
             x:Class="InfoSeries.Views.MainPage"
             Title="Info Series">

    ...

</ContentPage>

Then you can apply the behavior to the ListView control like you would do in a regular Windows app:

<ListView ItemTemplate="{StaticResource TopSeriesTemplate}"
          ItemsSource="{Binding Path=TopSeries}" RowHeight="200">
  <behaviors:Interaction.Behaviors>
    <behaviors:BehaviorCollection>
      <behaviors:EventToCommand EventName="ItemTapped" Command="{Binding GoToDetailPage}" />
    </behaviors:BehaviorCollection>
  </behaviors:Interaction.Behaviors>
</ListView>

Thanks to this behavior, we have connected the ItemTapped event of the ListView control to a command called GoToDetailPage, that we’re going to define in the ViewModel. From a framework point of view, Prism doesn’t do anything out of the ordinary to help developers implementing commands: it simply offers a class called DelegateCommand, which allows to define the operation to execute when the command is invoked and, optionally, the condition to satisfy to enable the command. If you have some previous experience with MVVM Light, it works exactly in the same way as the RelayCommand class. Here is how our command in the MainPageViewModel class looks like:

private DelegateCommand<ItemTappedEventArgs> _goToDetailPage;

public DelegateCommand<ItemTappedEventArgs> GoToDetailPage
{
    get
    {
        if (_goToDetailPage == null)
        {
            _goToDetailPage = new DelegateCommand<ItemTappedEventArgs>(async selected =>
            {
                NavigationParameters param = new NavigationParameters();
                param.Add("show", selected.Item);
                await _navigationService.NavigateAsync("DetailPage", param);
            });
        }

        return _goToDetailPage;
    }
}

The command we have created is a parametrized command; in fact, the property type is DelegateCommand<ItemTappedEventArgs>: this way, inside the method, we get access to the selected item, which is stored in the Item property. The method invoked when the command is triggered shows you how navigation with parameter works: first we create a new NavigationParameters object which, in the end, is nothing but a dictionary, where you can store key / value pairs. Consequently, we simply add a new item with, as key, the keyword show and, as value, the selected item, which type is SerieFollowersVM. This is the only difference compared to the navigation we’ve seen in the App class: the rest is the same, which means that we call the NavigateAsync() method of the NavigationService, passing as parameter the key that identifies the detail page (which is DetailPage) and the parameter.

Important! In the App class we were able to automatically use the NavigationService because it inherits from the PrismApplication class. If we want to use the NavigationService in a ViewModel (like in this case), we need to use the traditional approach based on dependency injection. The NavigationService instance is already registered in the Prism container, so we simply have to add an INavigationService parameter to the public constructor of the MainPageViewModel:

public MainPageViewModel(TsApiService apiService, INavigationService navigationService)
{
    _apiService = apiService;
    _navigationService = navigationService;
}

Now that we have performed the navigation to the detail page, we need to retrieve the parameter in the DetailPageViewModel class. The first step, like we did for the MainPageViewModel, is to let it inherit from the INavigationAware interface, other than the BindableBase class. This way, we have access to the OnNavigatedTo() event:

public class DetailPageViewModel : BindableBase, INavigationAware
{
    private SerieFollowersVM _selectedShow;

    public SerieFollowersVM SelectedShow
    {
        get { return _selectedShow; }
        set { SetProperty(ref _selectedShow, value); }
    }

    public DetailPageViewModel()
    {

    }

    public void OnNavigatedFrom(NavigationParameters parameters)
    {
            
    }

    public void OnNavigatedTo(NavigationParameters parameters)
    {
        SelectedShow = parameters["show"] as SerieFollowersVM;
    }
}

The previous code shows you how to handle the parameter we’ve received from the main page: the same NavigationParamaters object we’ve passed, in the MainPageViewModel, to the NavigateAsync() method is now passed as parameter of the OnNavigatedTo() method. As such, we can simply retrieve the item we’ve previously stored with the show key. In this case, since we are expecting an object which type is SerieFollowersVM, we can perform a cast and store it into a property of the ViewModel called SelectedShow. Thanks to this property, we can leverage binding to connect the various information of the selected show to the controls in the XAML page. Here is how the DetailPage.xaml looks like:

<?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:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
             prism:ViewModelLocator.AutowireViewModel="True"
             Title="{Binding Path=SelectedShow.Name}"
             x:Class="InfoSeries.Views.DetailPage">

  <StackLayout>
    <Image x:Name="InfoPoster"
           Source="{Binding Path=SelectedShow.Images.Fanart}" Aspect="AspectFill" />
    <Label Text="{Binding Path=SelectedShow.Overview}" LineBreakMode="WordWrap" FontSize="13" TextColor="#98a6ad" Margin="15" />
  </StackLayout>

</ContentPage>

The content is very simple: we display an image of the show (stored in the SelectedShow.Images.Fanart property) and a brief description (stored in the SelectedShow.Overview property).

Wrapping up

In this post we’ve seen some basic concepts to handle navigation and dependency injection in a Xamarin Forms app created with Prism as MVVM framework. In the next post we’re going to see a couple of advanced scenarios, related to navigation and handling of platform specific code. You can find the sample app used for this post on my GitHub repository: https://github.com/qmatteoq/XamarinForms-Prism

Posted in Xamarin | Tagged , , , | Leave a comment

Prism for Xamarin Forms – An overview (Part 1)

Even if I understand that it may not be the right technology for every project, I’m a huge fan of Xamarin Forms. As you’ll probably know if you follow my blog, I’m a Windows Developer and Xamarin Forms allows me to use basically all my current skills (XAML, binding, MVVM, etc.) to create applications also for other popular mobile platforms like iOS and Android. Additionally, it gives me the chance (like with native Xamarin) to take advantage of platform specific features and, at the same time, to maintain a user experience which is coherent with the look & feel of the operating system.

I’ve recently used Xamarin Forms to create a porting for Android of my simple Qwertee Shirts app and the advantage was clear: I was able to reuse most of the backend code I’ve already wrote for the UWP version and my XAML knowledge but, at the end, I got an application that fully embraced, from a UI point of view, the new Material Design created by Google, so it doesn’t look “alien” like it often happens with cross platform applications based on other cross platform technologies.

Screenshot_2016-08-20-12-10-58 Screenshot_2016-08-20-12-11-19

However, I’m not only a Windows Developer, but also a MVVM enthusiast and I’ve blogged about this topic multiple times, covering multiple platforms and frameworks. If you’re new to the MVVM pattern, I suggest you to start from this post and move on with the rest of the series. As such, the first thing I did when I decided to resume working with Xamarin Forms to port my app was looking for the best way to reuse my MVVM knowledge to develop the project and, as usual, the choice was hard. In this case, it was even more complicated because Xamarin Forms, compared to other XAML technologies like WPF or UWP, is pretty new, so it was hard to find in the beginning a choice that completely satisfied me.

Don’t get me wrong, if you remember my posts about learning the MVVM pattern, you’ll know that I’m a huge fan of the flexibility offered by MVVM Light and Laurent Bugnion did a superb job to introduce typical MVVM concepts (like binding and commands) in platforms that don’t natively support them, like Android and iOS. However, Xamarin Forms is a bit different than standard Xamarin: it already offers the concepts we need to leverage the MVVM pattern, like binding, data context, dependency properties, behaviors, etc. In this scenario, MVVM Light is still a great choice but, however, you still have to reinvent the wheel to solve many common scenarios you have to deal with when you’re developing a XAML app, like handling navigation, getting access to navigation events in a ViewModel or passing parameters between one page to the other.

Even do it on purpose, right before starting my porting I saw a tweet by Brian Lagunas, one of the MVPs behind the Prism project, announcing a new version of Prism specific for Xamarin Forms. Just to refresh your mind, Prism is a MVVM framework that, originally, was created by the Patterns & Practices division by Microsoft and that, some times ago, has been turned into an open source project driven by the community. Prism has always been a great choice to implement the MVVM pattern in XAML based applications, but sometimes you may have faced the risk to make the project over complicated just to follow its naming conventions and rules (like the requirement of having a bootstrapper to initialize it, despite the fact that XAML based application already have a startup class called App).

After completing the porting, I’ve found myself very satisfied with the Prism approach for Xamarin Forms, so I’ve decided to share my experience with you, hoping that it will get you up & running quicker when you start working on a new Xamarin Forms project.

Creating the first project

The easiest way to create a Xamarin Forms project based on Prism is to use its own Visual Studio extension, that you can download from the Visual Studio Gallery. After you’ve installed it, you will find in Visual Studio a new section called Prism, with various templates for each supported technology. The template we’re interested into is called Prism Unity App (Forms):

prism1

Actually, this template has even an advantage over the standard Xamarin Forms template. As you can see from the image below, it allows you to choose which platform you want to target when you create your project, while the default Xamarin Forms template automatically creates a project for each supported platforms (Android, iOS, Windows Phone 8.1, Windows 8.1, UWP), even if you aren’t interested in targeting one of them.

Project Wizard

After you’ve hit the Create project, you will end up with a standard Xamarin Forms solution: one Portable Class Library and one specific project for each platform you’ve chosen. Additionally, the Portable Class Library will already contain:

  • A Views folder, where to place your pages. The template includes a default one, called MainPage.xaml
  • A ViewModels folder, where to place your ViewModels. The templates includes a default one, called MainPageViewModel.cs.
  • An App class already configured to initialize the Prism infrastructure.

Here is how your default project will look like:

prism2

To demo Prism for Xamarin Forms, I’m going to create a simple client for TrackSeries, a TV Show website created by my great friends and colleagues Adrian Fernandez Garcia and Carlos Jimenez Aliaga.

Let’s start from the beginning and see which references have been automatically added by the template to the project:

prism3

As you can see, other than the standard Xamarin Forms NuGet package, Prism requires two packages: a Core one (which is in common across every platform) and a Forms one (which, instead, contains the specific helpers and services for Xamarin Forms). By default, the standard template leverages Unity as dependency injection container, so you’ll find installed also a bunch of other packages like Unity, Prism.Unity.Forms and CommonServiceLocator. However, if you don’t like Unity, Prism for Xamarin Forms offers some additional packages to integrate other popular dependency injection containers, like Ninject or Autofac.

The App class

One of the biggest changes compared to the old Prism versions is the removal of the bootstrapper concept, which was a dedicated class of the project that took care of initializing all the Prism infrastructure. Xamarin Forms (as every other XAML technology) already has an initializer class: the App one, which is included in the Portable Class Library, so the team has decided to leverage it instead of asking to the developer to create a new one. By default, this class inherits from the Application class. To properly support Prism, we need to change this and let the App class inherit from the PrismApplication one by:

  • In the App.xaml file, adding a new identifier for the namespace Prism.Unity and replacing the root Application node with the PrismApplication one.
<?xml version="1.0" encoding="utf-8" ?>
<prism:PrismApplication xmlns="http://xamarin.com/schemas/2014/forms"
                        xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                        xmlns:prism="clr-namespace:Prism.Unity;assembly=Prism.Unity.Forms"
                        x:Class="InfoSeries.App">

</prism:PrismApplication>
  • In the App.xaml.cs file, we need to change the default inheritance from Application to PrismApplication.
public partial class App : PrismApplication
{
    public App(IPlatformInitializer initializer = null) : base(initializer) { }

    protected override void OnInitialized()
    {
        InitializeComponent();

        NavigationService.NavigateAsync("MainPage");
    }

    protected override void RegisterTypes()
    {
        Container.RegisterTypeForNavigation<MainPage>();
    }
}

Additionally, the App class has three distinctive features:

  • It has a base constructor, which takes an IPlatformInitializer object as parameter.
  • It has a method called OnInitialized(), where we initialize the Forms infrastructure (by calling the InitializeComponent() method) and we trigger the navigation to the main page of the app (we’ll see later in details how navigation works).
  • It has a method called RegisterTypes(), which is where we register in the dependency injection container (in this case, Unity) every page and every service required by our application.

The IPlatformInitializer parameter is null by default, but it can be leveraged in case you need to register in the dependency container some specific classes that exists only in a platform specific project. You will find, in fact, that every platform specific project has its own custom initializer class (AndroidInitializer for Android, UwpInitializer for UWP, etc.) which, however, by default has an empty implementation of the RegisterTypes() method. Here is, for example, how the MainPage.xaml.cs of the UWP project looks like:

public sealed partial class MainPage
{
    public MainPage()
    {
        this.InitializeComponent();

        LoadApplication(new DeepNavigation.App(new UwpInitializer()));
    }
}

public class UwpInitializer : IPlatformInitializer
{
    public void RegisterTypes(IUnityContainer container)
    {

    }
}

Connecting Views and ViewModels

As you should already know if you have some previous experience with MVVM , the key to make the pattern working is to connect the ViewModel with its own View through binding. The only difference in a Xamarin Forms app compared to a Windows app is that the property to define the context is called BindingContext and not DataContext. Prism makes use of a simple naming convention to automatically assign a ViewModel to its View:

  • The XAML page should be stored into a folder of the project called Views
  • The ViewModel should be stored into a folder of the project called ViewModels and it needs to have the same name of the page plus the suffix ViewModel (so, for example, the ViewModel connected to the MainPage.xaml will be called MainPageViewModel).

As you can see, this is the exact infrastructure that the Prism template has created for us. Every page that we add to our application needs to be registered in the container, so that we can properly handle the navigation. To register it, we can leverage the RegisterTypes() method of the App class and use one of the methods offered by the Container called RegisterTypeForNavigation<T>, where T is the type of the page. In the starting template, we have just one page called MainPage, so it’s the only one that is automatically registered when the application starts. Here you can notice probably one of the biggest differences between Prism and other MVVM frameworks. With other toolkits, you are used to register in the container only the ViewModels and, eventually, all the services related to them. With Prism, instead, you just register the page’s type: it’s up to Prism to automatically register in the container also the ViewModel connected to the View. As you can see in the sample code, in fact, we have registered the MainPage class and not the MainPageViewModel one.

If you aren’t a fan of the naming convention approach, you aren’t forced to use it: in fact, the RegisterTypeForNavigation() method has another variant, which signature is RegisterTypeForNavigation<T, Y>(), where T is the page’s type and Y is the ViewModel’s type we want to set as BindingContext. So, for example, if you want to connect your MainPage to a ViewModel called MyCustomViewModel, it’s enough to register it using the following code:

protected override void RegisterTypes()
{
    Container.RegisterTypeForNavigation<MainPage, MyCustomViewModel>();
}

In the OnInitialized() method you can see a preview of how navigation works by default: every time you call the RegisterTypeForNavigation<T> method, Prism registers into the NavigationService a reference to that page using, as key, a string with the same type name. As such, since our page’s type is MainPage, we need to pass the string “MainPage” as parameter of the NavigateAsync() method to trigger the navigation to that page. If, by any chance, we want to override this behavior, we can pass as parameter of the RegisterTypeForNavigation<T>() a custom string and use it for the subsequent navigations, like in the following sample, where we have replaced the key “MainPage” with the “MyCustomPage” one.

public partial class App : PrismApplication
{
    public App(IPlatformInitializer initializer = null) : base(initializer) { }

    protected override void OnInitialized()
    {
        InitializeComponent();

        NavigationService.NavigateAsync("MyCustomPage");
    }

    protected override void RegisterTypes()
    {
        Container.RegisterTypeForNavigation<MainPage>("MyCustomPage");
    }
}

However, in the next posts we’ll see more details about how to handle navigation in a more advanced way.

The ViewModel

One of the features I’ve appreciated most of Prism for Xamarin Forms is that it doesn’t require us to do any change in XAML page to support it (for example, there are other MVVM frameworks which require you to change the ContentPage type with a custom one). You will only find, in the MainPage.xaml file, a specific Prism attribute, as property of the ContentPage entry, called ViewModelLocator.AutowireViewModel:

<?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:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
             prism:ViewModelLocator.AutowireViewModel="True"
             x:Class="InfoSeries.Views.MainPage"
             Title="MainPage">
  <StackLayout HorizontalOptions="Center" VerticalOptions="Center">
    <Label Text="{Binding Title}" />
  </StackLayout>
</ContentPage>

This property takes care of connecting the View with the ViewModel: when it’s set to true, the ViewModel will be automatically set as BindingContext of the View if we have respected the naming convention previously described. However, one of the changes introduced in Prism 6.2 is that this property isn’t required anymore, unless you want to explicitly disable the naming convention by setting it to false. The standard template adds it to give a more complete sample, but you can safely remove it.

A key feature offered by every MVVM framework is a class to use for our ViewModels to give quick access to the most used features, like the implementation of the INotifyPropertyChanged interface. Prism doesn’t make any exception and it offers a class called BindableBase, which our ViewModels can inherit from:

public class MainPageViewModel : BindableBase
{
    private string _title;
    public string Title
    {
        get { return _title; }
        set { SetProperty(ref _title, value); }
    }

    public MainPageViewModel()
    {

    }
}

Thanks to this class, whenever we need to create a property that implements the INotifyPropertyChanged interface (so that it can propagate its changes through the binding channel), we can simply use the SetProperty() method in the setter of the property. This method will take care of storing the value and, at the same time, sending a notification to all the controls that are in binding with this property that its value has changed, so they need to update their layout.

The sample app created by template does exactly this: it creates a property called Title, which is connected through binding to a Label control in the XAML page. Whenever we change the value of the property, we will see the UI updated in real time. To be honest, the sample app shows also something different: it sets the value of the Title property in a method called OnNavigatedTo() and it parses some parameters. We’re going to see how this approach works more in details in the next post.

In the next post

In this post we have just scratched the surface and we understood the basic concept behind a Xamarin Forms application created with Prism. In the next post we’ll see some more advanced concepts, like handling navigation in a ViewModel or registering additional services in the dependency container.

Posted in Xamarin | Tagged , , , | Leave a comment

Integrating Facebook in a Universal Windows app

Facebook is, without any doubt, one of the most popular social networks out there. There are many reasons why we would integrate their services into a mobile application: to make the login process easier, to allow sharing some content, to post something on the user’s timeline. I’ve already covered in the past on this blog how to integrate Facebook in a Windows or Windows Phone application. In this post we’re going to see how to achieve this goal in a Universal Windows app for Windows 10 using a new Facebook SDK released by a Microsoft team on GitHub a while ago. Specifically, we’re going to see how to retrieve the main information about the logged user and how to interact with the Graph APIs, the set of REST APIs provided by Facebook to access to their services.

Let’s start!

Configuring the app

The first step to start using the Facebook SDK is registering the app on the Facebook Developer Portal: every mobile or web app which uses the Facebook APIs needs to be connected to an app registered on the Facebook portal. Without this step, Facebook won’t authorize us to perform any operation. Let’s point our browser to https://developers.facebook.com/ and choose to register a new app.

newapp

As you can see, the Windows platform isn’t listed by default, so you have to choose to perform a basic setup with the link at the bottom.

facebook2

The next step will ask you to set a display name (typically, it’s the same name of your application), an optional namespace (which acts as unique identifier for your app) and the category. In the end, press the Create App ID button. At the end of this step, your Facebook app will be created and ready to be configured. Now we need to add support to the Windows platform: we do it in the Settings section, which we can find in the menu on the left. In this page we’ll find the Add platform link, as highlighted in the below image:

facebook3

When you click on the link, this time, you’ll find an option called Windows App in the list. After you’ve chosen it, the following section will appear in the Settings page:

facebook4

In our case, since it’s a Universal Windows app, we need to fill the Windows Store SID field; feel free to ignore the Windows Phone Store SID [BETA] field, since it applies only to old Silverlight apps for Windows Phone.

The SID is the unique identifier that the Windows Store assigns to our application when we associate it using the Store menu in Visual Studio. However, we don’t have to do it in advance to properly register the app on the Facebook portal. It’s enough to use the WebAuthenticationBroker class to retrieve this information: in case the app isn’t associated yet, we’ll retrieve a temporary value which is enough for our tests. Here is how to retrieve the SID in a Universal Windows app:

string sid = WebAuthenticationBroker.GetCurrentApplicationCallbackUri().ToString(); 

You have to take note of this value: the simplest approach is to use the Debug.WriteLine() method to print the value in the Visual Studio’s Output Window.

Here is how a SID looks like:

ms-app://s-1-15-2-2031376880-2039615047-2889735989-2649504141-752107641-3656655002-2863893494/ 

This is the value we need to to put into the Windows Store SID field of the Facebook portal. However, we need to remove the ms-app:// prefix and the ending /. So, based on the previous sample, the SID we would need to add in the developer’s portal is:

s-1-15-2-2031376880-2039615047-2889735989-2649504141-752107641-3656655002-2863893494

The last thing to do is to take note of another information provided by Facebook: the App ID, which will need later during the login phase. You can find it in the main dashboard of your app, as you can see in the following image:

clip_image002

 

Now we’ready to move on and write some code.

Integrating the library

The next step is to integrate the library into your app. Unfortunately, it isn’t available on NuGet, so you’ll need to download the whole project and compile it together with your app. The SDK is available on GitHub, so there are two ways to get it:

  1. Using the Download ZIP button, to download a zipped file with the whole content of the repository.
  2. Cloning the repository on your computer using GIT.

Personally, I suggest using the second approach: this way, you’ll be able to quickly get any update released by the team and keep your app always up-to-date. There are many ways to do it: you can choose the one you prefer, based on your experience with Git. The easiest one is to use the tools integrated in Visual Studio. Let’s see how:

  1. Open Visual Studio.
  2. Open the Team Explorer window. If it isn’t already available in your Visual Studio configuration, look for it in the View menu.
  3. You will find a section called Local Git repositories. Press the Clone button and set:
    1. In the first field, the URL of the GitHub repository, which is https://github.com/microsoft/winsdkfb
    2. In the second field, the local path on your computer where you want to save the project.
  4. Now press the Clone button: Visual Studio will download all the files in your local folder. Any time, by using Solution Explorer, you’ll be able to access to this repository and, by using the Sync button, to download the latest version of the source code from GitHub.

git

Now that you have the library, you can add it to your Visual Studio solution that contains your Universal Windows app, right click on it, choose Add existing project and look for one of the projects of the Facebook SDK you’ve just cloned on your computer:

  1. If it’s a Universal Windows app for Windows 10 (so based on UWP), you need to add the project located at FBWinSDK\FBSDK-UWP\FBSDK-UWP\FBSDK-UWP.vcxproj
  2. If it’s a Windows Store app for Windows 8.1, you need to add the project located at FBWinSDK\FBWinSDK\FBWinSDK.Windows\FBWinSDK.Windows.vcxproj
  3. If it’s a Windows Store app for Windows Phone 8.1, you need to add the project located FBWinSDK\FBWinSDK\FBWinSDK.WindowsPhone\FBWinSDK.WindowsPhone.vcxproj

The last step is to right click on your app’s project, choose Add reference and, from the Projects section, look for the Facebook project you’ve just added. Now you’re finally ready to write some code.

The login phase

The authentication to Facebook services is handled, as for many others similar services, using the oAuth protocol: the user will never share his credentials directly in the app, but inside a Web View which content is provided directly by the service’s owner (Facebook, in this case). If the credentials are accepted, Facebook wil return to the app a token, which we’ll need to perform any operation against the Facebook APIs. This approach improves the user’s security: a malicious developer won’t be able to access, in any case, to the user’s credentials.

The Facebook SDK we’ve added to our project makes easier to handle the login process: the Web View and the auhtentication will be handled directly by the library, which will return us automatically all the info about the logged user and a set of APIs to interact with the Graph APIs.

Here is the full login procedure:

private async void OnLogin(object sender, RoutedEventArgs e)
{
    FBSession session = FBSession.ActiveSession;
    session.WinAppId = Sid;
    session.FBAppId = AppId;

    List<string> permissionList = new List<string>();
    permissionList.Add("public_profile");
    permissionList.Add("email");

    FBPermissions permissions = new FBPermissions(permissionList);
    var result = await session.LoginAsync(permissions);
    if (result.Succeeded)
    {
        //do something
    }
}

The first step is to retrieve the current session, by using the static property FBSession.ActiveSession. If we haven’t completed the login procedure yet, this property will be empty: in this case, we need to move on and continue the login procedure.

The first important properties to set are WinAppId and FBAppId. The first one is the SID of the application, the one we have previously retrieved using the GetCurrentApplicationCallbackUri() method of the WebAuthenticationBroker class. FBAppId, instead, is the App Id that we have noted before from the Facebook’s developer portal. The next step is to define which kind of operations we want to do with the Facebook APIs, by using the permissions mechanism. You can find the complete list of available permissions in the documentation https://developers.facebook.com/docs/facebook-login/permissions

It’s imortant to highlight how Facebook doesn’t allow to get access to all the permissions by default. Only the basic ones, like public_profile or email, are automatically allowed. The most advanced ones (like publish_actions that allows to publish a post on behalf of the user) require that the Facebook app passes a review process, where the team will double check the reasons and the use cases for which you’re requesting such permissions. Don’t confuse it with the certification process done by Microsoft when you submit the app on the Store: this review is completely handled by Facebook.

Permissions are defined into a collection of strings, which is passed as parameter when you initialize the FBPermissions object. The last step is to call the LoginAsync() method, passing as parameter the FBPermissions object you’ve just defined. When you call it, if the user has never logged in with your app, the SDK will display a popup, which will embed the Facebook login page, as you can see in the following image:

clip_image004

The user will have to fill his credentials and give to our app the authorization to access to the permissions we’ve required. If everything goes well, the method will return us a FBResult object with the outcome of the operation. The first property we can leverage is called Succeded, which will tell us if the login operation went well or not. In case the answer is yes, we can leverage the User property of the FBSession class to get access to all the public information of the user. The following code stores into a variable the full name of the user:

var result = await session.LoginAsync(permissions);
if (result.Succeeded)
{
    string name = session.User.Name;
}

Interact with the Graph APIs

As mentioned in the beginning of the post, Graph APIs are a set of REST APIs offered by Facebook that we can use to perform many operations, like publishing a post, liking a comment, etc. Let’s see how the SDK can help us to interact with these APIs with a real sample: retrieving the e-mail address of the user. It isn’t one of the information exposed by the public profile, so you won’t find an Email property in the FBUser class, but you’ll need to use the Graph APIs to get it.

As every REST API, an operation is defined by:

  1. An endpoint, which is the URL we need to invoke to interact with the service. In our scenario, we need to use the https://graph.facebook.com/v2.5/me endpoint, followed by the query string parameter fields with the list of information we need. In our case, the full endpoint will be https://graph.facebook.com/v2.5/me?fields=email
  2. A method exposed by the HTTP protocol, to be used in combination with the endpoint. Typically, when we’re retrieving some data we use the GET method; writing operations (like posting a status on Facebook), instead, are performed with the POST method. Our scenario falls in the first category, so we will perform a GET.

The first thing we need is a class which maps the response that we’re going to receive from the API. For this purpose we can use the Graph API Explorer, a tool which we can use to simulate the operations with the Graph APIs and that is available at https://developers.facebook.com/tools/explorer

The tool features an address bar, where we can specify the endpoint and the HTTP method we want to use. After pressing the Submit button, we’ll see in the main windows the JSON response returned by the API. If, for example, we perform a test with the endpoint we’re interested into (/me?fields=email) this is the response we’ll get:

{
  "email": "mymail@mail.com",
  "id": "10203404048039813"
} 

Visual Studio offers a built-in option to convert a JSON data into a class. We just need to add a new class to the project and, once we have opened the file, using the option Paste Special –> Paste JSON as classes which is available in the Edit menu. Visual Studio will generate the following class:

public class UserProfile
{
    public string id { get; set; }

    public string email { get; set; }
}

However, to properly use the Facebook SDK, we need also another element in the class: a static method which is able to deserialize the JSON returned by the service to convert it into a UserProfile object. We create it with the help of the popular JSON.NET library, which we need to install in the project using NuGet (https://www.nuget.org/packages/Newtonsoft.Json/).

This is the complete definition of the class:

public class UserProfile
{
    public string id { get; set; }

    public string email { get; set; }

    public static UserProfile FromJson(string jsonText)
    {
        UserProfile profile = JsonConvert.DeserializeObject<UserProfile>(jsonText);
        return profile;
    }
}

The FromJson() method uses the JsonConvert class to take as input the JSON returned by Facebook and to return, as output, a UserProfile object. To understand why we have created such a method, we need to analyze the code required to interact with the Graph APIs:

private async void OnGet(object sender, RoutedEventArgs e)
{
    string endpoint = "/me";

    PropertySet parameters = new PropertySet();
    parameters.Add("fields", "email");

    FBSingleValue value = new FBSingleValue(endpoint, parameters, UserProfile.FromJson);
    FBResult graphResult = await value.GetAsync();

    if (graphResult.Succeeded)
    {
        UserProfile profile = graphResult.Object as UserProfile;
        string email = profile?.email;
        MessageDialog dialog = new MessageDialog(email);
        await dialog.ShowAsync();
    }
}

The first step is to define the endpoint. It’s important to highlight that the query string parameters can’t be added directly in the URL, but separately using the PropertySet collection, otherwise we will get an exception at runtime. This happens because the SDK, under the hood, automatically sets the base URL for the APis and adds the access token retrieved during the login phase. You can notice it from the fact that we have just set the value /me as endpoint; we didn’t have to specify the full URL with the https://graph.facebook.com/v2.5 prefix.

Using the PropertySet property is quite simple: it’s a collection, where we can add key-value pairs composed by a key (the name of the property, in our case fields) and a value (the property’s value, in our case email). In the next line of code you’ll finally understand why we had to create a FromJson() method inside the UserProfile class: it’s one of the paramters required when we initialize the FBSingleValue object, which is the class exposed by the SDK to interact with the Graph APIs. The other two parameters are the endpoind and the PropertySet collection with the list of parameters.

Now we are ready to perform the request. The FBSingleValue class offers many options, based on the HTTP method we need to use. In our case, since we need to perform a GET operation, we use the GetAsync() method, which will return us a FBResult object. It’s the same type of result we received during the login operation: this means that, also in this case, we can leverage the Succeded property to understand if the operation has completed succesfully or not. The difference is that, this time, we have also a Result property, which contains the result returned by the Graph API. It’s a generic object, since the Graph APIs don’t return a fixed structure; it’s our job to convert it into the type we expect, in this case a UserProfile object.

The rest is up to us and depends by our app’s logic: in the previous sample code, we just show to the user a dialog with the retrieved mail address.

This approach works for every interaction supported by the Graph APIs. What changes between one operation and the other is:

  1. The endpoint
  2. The values to add to the PropertySet collection, based on the parameters required by the API.
  3. The class to map the API’s response.
  4. The method of the FBSingleValue class to call to perform the operation.

For example, if instead of retrieving the user’s mail address we would have wanted to publish a post on the user’s timeline, we would have used the following code:

private async void OnPost(object sender, RoutedEventArgs e)
{
    PropertySet parameters = new PropertySet();
    parameters.Add("title", "Microsoft");
    parameters.Add("link", "https://www.microsoft.com/en-us/default.aspx");
    parameters.Add("description", "Microsoft home page");
    parameters.Add("message", "Posting from my Universal Windows app.");

    string path = "/me/feed";

    FBSingleValue sval = new FBSingleValue(path, parameters, FBReturnObject.FromJson);
    FBResult fbresult = await sval.PostAsync();

    if (fbresult.Succeeded)
    {
        // Posting succeeded
    }
    else
    {
        // Posting failed
    }
} 

The main difference here, other than the endpoint and the parameters, is that we’re dealing with a “write” operation. Consequently, we need to use the POST method of the HTTP protocol, which is translated into the PostAsync() method of the FBSingleValue class. As a reminder, remember that this method won’t work as it is: you’ll need to request the publish_actions permission, which is granted by Facebook only after the app has passed their review.

Wrapping up

In this post we’ve learned how to leverage the new Facebook SDK in a Universal Windows app to interact with the services offered by the popular social network. If you want to learn more, you can refer to the GitHub project (https://github.com/microsoft/winsdkfb) and o the official documentation (http://microsoft.github.io/winsdkfb/). Happy coding!

Posted in Universal Apps, UWP, wpdev | Tagged , , | Leave a comment