Building an Mvvm cross Platform app from scratch with Xamarin

In this post, I am going to show the simplest possible implementation of a cross platform app, that yet has the many of those typical architecture perks in it and shows all the steps of our design process.

This is part one and covers the way up to the implementation of models, services, service-access and unit tests. The complete solution is available on GitHub.

As a simple example, I’ll take an app that displays the Github-Event stream, which looks like this:

overview

The first thing we usually design is the application domain (yes, I am one of those DDD guys). So we write down all the objects we work with, which are in this case: Events (someone commited), Repositories, Commits and of course the Users. They are placed in a portable library that is usually also called something with domain, so we’ll go with GitExplorer.Domain.

public class GitHubEvent
{
    public string Id { get; set; }
    public User Actor { get; set; }
    public GitHubRepository Repository { get; set; }
    public List Commits { get; set; }
}

public class GitHubRepository
{
    public string FullName { get; set; }
}

public class User
{
    public string Name { get; set; }
    public string ProfileImageUrl { get; set; }
}

public class GitHubRepository
{
    public string FullName { get; set; }
}

Yes, this are mostly dump objects and for mobile apps that just display data from a service, that’s as much as they learn in their life… Sad thing, but you will hopefully have spouse with higher ambitions. :)

Now we have our models, we need some services that keep track of them. As services are usually very tightly coupled to models, we usually keep them in the model project too. Services wrap operations on models like getting them from some online service, putting them into a repository or checking into live updates and everything else.

To keep things simple, our GitHubEventService will only obtain the events from the service and keep them in memory.

public class GitHubEventService
{
    private readonly IGitHubClient _client;

    private List<GitHubEvent> _events = new List<GitHubEvent>();

    public GitHubEventService(IGitHubClient client)
    {
        _client = client;
    }

    public async Task<List<GitHubEvent>> GetEventsAsync()
    {
        var items = await _client.DownloadEventsAsync();
        _events = items;
        return _events;
    }

    public List<GitHubEvent>  GetEventsFromMemory()
    {
        return _events;
    }
}

As you can see, the service requires a IGitHubClient to run properly, which looks like this:

public interface IGitHubClient
{
    Task<List<GitHubEvent>> DownloadEventsAsync();
}

Access to services is usually subject to change, as Apis get newer versions, other security measures, ore are completely exchanged against something else.
To be able to change them without reworking the complete application, we move it’s implementation to a new portable library called GitExplorer.Domain.Api.

A part of the Api projects are the DTOs, generated from the Services json response. There’s a neat Function in Visual Studio for this (Edit -> Paste Special -> Paste JSON as classes) or if you are using Xamarin Studio, you can use json2csharp.com to do the same. Usually, we strip away a lot of these auto generated properties, because we’ll never use them. Just makes things more readable.

(Yes, this leads to an exact copy of our model classes, just with some different names, and yes, we could just use the models and add some attributes, but if we need to change anything for the Api access, it doesn’t impact our models. This is usually worth the extra lines for converting between the types.)

In this case, it is a simple HttpClient implementation utilizing Json.Net.

public class GitHubGlobalEventClient : IGitHubClient
{
    public async Task&lt;List&gt; DownloadEventsAsync()
    {
        try
        {
            //var handler = new ModernHttpClient.NativeMessageHandler();
            var client = new HttpClient();

            client.DefaultRequestHeaders.Add("User-Agent", "Awesome 1.0");
            client.DefaultRequestHeaders.Add("Authorization", "Basic YOUR API KEY HERE");

            var result = await client.GetStringAsync("https://api.github.com/events");
            var data = JsonConvert.DeserializeObject&lt;List&gt;(result);

            return data
                .Where(e =&gt; e.type == "PushEvent")
                .Select(eventdto =&gt; new GitHubEvent()
                {
                    Id = eventdto.id,
                    Actor = new User()
                    {
                        Name = eventdto.actor.login,
                        ProfileImageUrl = eventdto.actor.avatar_url
                    },
                    Commits = eventdto.payload.commits?.Select(commitdto =&gt; new Commit()
                    {
                        Sha = commitdto.sha,
                        Comment = commitdto.message
                    }).ToList(),
                    Repository = new GitHubRepository()
                    {
                        FullName = eventdto.repo.name
                    }
                }).ToList();
        }
        catch(Exception e)
        {
            throw new Exception("Something went wrong");
        }
    }
}

Now comes the developers moment of delight: This is actually runnable code.

As there is no app yet, we usually place some tests now, to see if they run correctly.

[TestClass]
public class UnitTest1
{
    [TestMethod]
    public async Task TestApiClientDownload()
    {
        var client = new GitHubOrganisationEventClient();
        var data = await client.DownloadEventsAsync();

        Assert.IsTrue(data.Count > 0);
    }

    [TestMethod]
    public async Task TestService()
    {
        var client = new GitHubOrganisationEventClient();
        var service = new GitHubEventService(client);
        var data = await service.GetEventsAsync();

        Assert.IsTrue(data.Count > 0);
    }
}

Stay tuned for part 2, where we add ViewModels, Android Apps, etc., or check out the complete solution on GitHub.

Advertisements
Building an Mvvm cross Platform app from scratch with Xamarin

2 Gedanken zu “Building an Mvvm cross Platform app from scratch with Xamarin

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s