1 Comments

For my recent blog post about how to consume a web service in the Portable Class Library (PCL) I decided to write the client for Windows 10 which allows to create apps for every platform that runs Windows 10. In this post I will focus on the platforms Desktop, Tablet and Mobile showing how to create a basic application based on a MVVM architecture. To create a Windows 10 app you will need a computer running Windows 10 and Visual Studio 2015.

Creating a basic app

First lets create a list of people that we can navigate to in the detail view. Here fore we will create two pages. On the first page MainPage.xaml we will simply show the list:

<Page
    x:Class="HttpClientSample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:HttpClientSample"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    DataContext="{Binding Main, Source={StaticResource Locator}}"
    mc:Ignorable="d">

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <GridView ItemsSource="{Binding People}" SelectedItem="{Binding SelectedPerson, Mode=TwoWay}"></GridView>

        <AppBar VerticalAlignment="Bottom" IsOpen="True" >
            <AppBarButton Icon="Add" Label="Add Person" Command="{Binding AddNewPerson}" />
        </AppBar>
    </Grid>
</Page>

The user can select an element of the list on which we will navigate to the detail of the person allowing us to edit the person. This is done in the MainViewModel.cs which is based on the MVVM Light Framework for implementation:

public class MainViewModel:ViewModelBase
{
    private readonly IPersonService _personService;
    private ObservableCollection<Person> _people;
    private Person _selectedPerson;

    public MainViewModel(IPersonService personService)
    {
        if (personService == null) throw new ArgumentNullException(nameof(personService));
        _personService = personService;
        _people = new ObservableCollection<Person>();
        ShowPerson = person => { };
        AddNewPerson = new RelayCommand(() => ShowPerson(-1));
    }

    public ObservableCollection<Person> People => _people;
    public Action<int> ShowPerson { get; set; }

    public Person SelectedPerson
    {
        get { return _selectedPerson; }
        set
        {
            if (_selectedPerson == value) return;
            _selectedPerson = value;
            RaisePropertyChanged(nameof(SelectedPerson));
            if (_selectedPerson != null) ShowPerson(_people.IndexOf(_selectedPerson));
        }
    }

    public ICommand AddNewPerson { get; private set; }

    public async Task Init()
    {
        var people = await _personService.GetPeople();

        _people.Clear();

        foreach (var person in people)
        {
            _people.Add(person);
        }
    }
}

The View Model also prepares the List of people that is displayed on the main page. The PersonDetailPage.xaml will allow to edit the first and surname of the person:

<Page
    x:Class="HttpClientSample.PersonDetailPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:HttpClientSample"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    DataContext="{Binding Person, Source={StaticResource Locator}}"
    Loaded="PersonDetail_OnLoaded"
    mc:Ignorable="d">

    <StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <TextBox Header="Firstname" Text="{Binding Firstname, Mode=TwoWay}"/>
        <TextBox Header="Lastname" Text="{Binding Lastname, Mode=TwoWay}"/>
        <Button Content="Save" Command="{Binding StoreCommand, Mode=TwoWay}" IsEnabled="{Binding HasPendingChanges}" HorizontalAlignment="Center" Margin="0,10"/>
    </StackPanel>
</Page>

When selecting save the person will be updated, all the logic is implemented in the PersonDetailViewModel.cs:

public class PersonDetailViewModel:ViewModelBase
{
    private readonly IPersonService _personService;
    private int _id;
    private string _firstname;
    private string _lastname;
    private bool _hasPendingChanges;

    public PersonDetailViewModel(IPersonService personService)
    {
        if (personService == null) throw new ArgumentNullException(nameof(personService));
        _personService = personService;

        StoreCommand = new RelayCommand(StorePerson, () => true);
        HasPendingChanges = false;
    }

    public bool HasPendingChanges
    {
        get { return _hasPendingChanges; }
        set
        {
            if (value == _hasPendingChanges) return;
            _hasPendingChanges = value;
            RaisePropertyChanged(nameof(HasPendingChanges));
        }
    }

    public string Firstname
    {
        get { return _firstname; }
        set
        {
            if (value == _firstname) return;
            _firstname = value;
            HasPendingChanges = true;
            RaisePropertyChanged(nameof(Firstname));
        }
    }

    public string Lastname
    {
        get { return _lastname; }
        set
        {
            if (_lastname == value) return;
            _lastname = value;
            HasPendingChanges = true;
            RaisePropertyChanged(nameof(Lastname));
        }
    }

    public ICommand StoreCommand { get; set; }

    public async Task Init(int id)
    {
        _id = id;
        var person = id > 0 ? (await _personService.GetPeople()).ToList()[id] : new Person("", "");
        Firstname = person.FirstName;
        Lastname = person.LastName;
        HasPendingChanges = false;
    }

    private async void StorePerson()
    {
        HasPendingChanges = false;

        var person = new Person(Firstname, Lastname);

        if (_id >= 0)
        {
            await _personService.UpdatePerson(_id, person);
        }
        else
        {
            await _personService.CreatePerson(person);
        }
    }
}

To prevent the user from invoking the storing of a person multiple times the store button is only enabled when there are pending changes and you probably want to improve the error handling in production code as it is non-existent in the StorePerson method.

Basic Navigation

From the main page we implement the navigation in MainPage.xaml.cs which allows the user to navigate to the detail page. We also pass along a navigation parameter which contains the ID or ahem in this basic example the array index of the person we want to see:

private void ShowPerson(int personId)
{
    Frame.Navigate(typeof (PersonDetailPage), personId);
    _viewModel.SelectedPerson = null;
}

The navigation is done over Frame.Navigate, which takes the type of the target and a parameter as an argument. The SelectedPerson is then set to null, after invoking the navigation. This is done so that the user may reselect the person the second time around.

Additionally when the user adds a person over the AppBar it will invoke the same navigation method but pass in the –1 as parameter indicating that no Index is set.

Further the user has the possibility to navigate back to the main page. Here fore we have to enable the back navigation which we set in the Loaded event handler of the person detail page and add an event handler for the BackRequest:

private void PersonDetail_OnLoaded(object sender, RoutedEventArgs e)
{
    SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility = AppViewBackButtonVisibility.Visible;
    SystemNavigationManager.GetForCurrentView().BackRequested += OnBackRequested;
}

The event handler is implemented as follows:

private void OnBackRequested(object sender, BackRequestedEventArgs backRequestedEventArgs)
{
    if (Frame.CanGoBack)
    {
        Frame.GoBack();
        backRequestedEventArgs.Handled = true;
    }
}

While testing the app under Windows 10 mobile I noticed that the navigation was invoked twice when selecting the hardware back button. By setting the Handled property to true in the event arguments the framework is indicated that the navigation has been taken care of.

Taking it to other form factors

A great thing about creating your apps as a Universal Windows Platform app is that the APIs remain the same across the devices. In regards to the upcoming Windows 10 Mobile release we can even reuse the UI code. So we can run this basic app on a phone without making any changes. The UI will be automatically adopted to the new form factor.

Now of course for more complex apps you will want to use different layouts according to the screen size, but even then you will be creating adaptive layouts (same as with responsive Websites) rather than developing multiple apps to target different platforms. So a lot less overhead and work to have a running app across multiple form factors.

Conclusion

In this post we saw how to create a basic Windows 10 UWP app including basic navigation features and how to implement the MVVM pattern. If you are coming from a WPF, Silverlight, Windows 8.x or Windows Phone background you have seen that a lot of elements are very familiar.

I’ve been lately playing around with F# which unfortunately is currently not a supported language to write UWP apps. This also includes not being able to share Portable Class Libraries with UWP apps. If you feel the same way as me or want to throw the F# community a bone please let Microsoft know that they enable support for F# UWP apps here.

You can find the entire sample code of this blog post on GitHub.

0 Comments

When working with a mobile app you will often work with a backend, which if you are working with C# might very probably be a Web API backend. In this blog we will look at how we can consume and write to a Web API Controller that we can host on Azure. Why Azure? Because it is the easiest way of hosting a web service straight out of Visual Studio and if you happen to have a MSDN subscription you can do this all for free. For the client we will be using a Windows 10 Universal App which allows us to write a client for Desktop, Tablet and Phone.

The app we will be building will add the capability to read a list of people from a service and add a person to the existing. So we will see how we can read and write to a HTTP service.

The client

As a client we will be targeting Windows Phone (soon to be Windows Mobile again), Android and iOS. Our implementation of integrating with the backend we will perform in the Portable Class Library (PCL) which provides us the unique advantage of only having to write our backend service integration once.

PCL integration

In the PCL we will require the following NuGet packages:

Armed with the capabilities of now being able to communicate to a HTTP backend and serializing i.e. deserializing objects to and from JSON we can start implementing our communication layer by creating a HTTP client in the constructor. We usually only need one instance of the HTTP client as it will handle multiple requests and only spawn as many active connections as are reasonable over HTTP:

public class PersonService : IPersonService
{
    private HttpClient _httpClient;

    public PersonService()
    {
        _httpClient = new HttpClient();
    }

    // ... Person Service implementation
}

For reading over HTTP we should use the GET keyword which is provided by the HTTP client and is implemented as follows:

public async Task<IEnumerable<Person>> GetPeople()
{
    var result = await _httpClient.GetAsync(BASE_URI);
    var peopleJson = await result.Content.ReadAsStringAsync();

    return JsonConvert.DeserializeObject<IEnumerable<Person>>(peopleJson);
}

Note that if you are using a free website on Azure you can choose to run communications over SSL, the only thing you have to change for this is adding an s in the URI after http i.e. resulting in an https URI.

Writing to a HTTP service depends on the action we want to perform. Creating something new e.g. adding a new person to the existing person list, should be performed over a HTTP POST.  Implementing the post can be done as follows:

public async Task<bool> CreatePerson(Person person)
{
    var personJson = JsonConvert.SerializeObject(person);
    var content = new StringContent(personJson, Encoding.UTF8, "application/json");
    var result = await _httpClient.PostAsync(BASE_URI, content);

    return result.IsSuccessStatusCode;
}

The StringContent method has additional parameters to indicate to the server how the content can be interpreted. This is required to inform the backend service that the data we are sending is serialized as JSON. Not doing so would end in false information in the header which would prevent Web API to automatically deserialize the body.

Updating an existing person usually is done via PUT, which is similar to the CreatePerson method but contains an ID in the URI which usually corresponds with the ID from the Person which is set on the backend.

public async Task<bool> UpdatePerson(int id, Person person)
{
    var uri = Path.Combine(BASE_URI, id.ToString());

    var personJson = JsonConvert.SerializeObject(person);
    var content = new StringContent(personJson, Encoding.UTF8, "application/json");

    var result = await _httpClient.PutAsync(uri, content);

    return result.IsSuccessStatusCode;
}

As you can see implementing a Web service is quite straight forward with the HTTP Client and allows to easily create a backend integration for native clients that can be shared across platforms.

The UI

On the client side we now can invoke our portable service and display a list of people.

<Page
    x:Class="HttpClientSample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:HttpClientSample"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    DataContext="{Binding Main, Source={StaticResource Locator}}"
    mc:Ignorable="d">

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <GridView ItemsSource="{Binding People}" SelectedItem="{Binding SelectedPerson, Mode=TwoWay}"></GridView>

        <AppBar VerticalAlignment="Bottom">
            <AppBarButton Icon="Add" Label="Add" Command="{Binding AddNewPerson}" />
        </AppBar>
    </Grid>
</Page>

In the ViewModel we can invoke the backend service to provide the data.

public class MainViewModel:ViewModelBase
{
    private readonly IPersonService _personService;
    private ObservableCollection<Person> _people;
    private Person _selectedPerson;

    public MainViewModel(IPersonService personService)
    {
        if (personService == null) throw new ArgumentNullException(nameof(personService));
        _personService = personService;
        _people = new ObservableCollection<Person>();
        ShowPerson = person => { };
        AddNewPerson = new RelayCommand(() => ShowPerson(0));
    }

    public ObservableCollection<Person> People => _people;
    public Action<int> ShowPerson { get; set; }

    public Person SelectedPerson
    {
        get { return _selectedPerson; }
        set
        {
            if (_selectedPerson == value) return;
            _selectedPerson = value;
            RaisePropertyChanged(nameof(SelectedPerson));
            if (_selectedPerson != null) ShowPerson(_people.IndexOf(_selectedPerson));
        }
    }

    public ICommand AddNewPerson { get; private set; }

    public async Task Init()
    {
        var people = await _personService.GetPeople();

        _people.Clear();

        foreach (var person in people)
        {
            _people.Add(person);
        }
    }
}

Adding a person means we have to add a further page to our client application that provides us with a form to enter the name and first name of a person. To keep things simple we will just use the same UI and identify via the navigation parameter if we have to create or update the person on the backend.

<Page
    x:Class="HttpClientSample.PersonDetail"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:HttpClientSample"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    DataContext="{Binding Person, Source={StaticResource Locator}}"
    Loaded="PersonDetail_OnLoaded"
    mc:Ignorable="d">

    <StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <TextBox Header="Firstname" Text="{Binding Firstname, Mode=TwoWay}"/>
        <TextBox Header="Lastname" Text="{Binding Lastname, Mode=TwoWay}"/>
        <Button Content="Save" Command="{Binding StoreCommand, Mode=TwoWay}" IsEnabled="{Binding HasPendingChanges}" HorizontalAlignment="Center" Margin="0,10"/>
    </StackPanel>
</Page>

The ViewModel is handling the integration with the PersonService from the PCL library:

public class PersonViewModel:ViewModelBase
{
    private readonly IPersonService _personService;
    private int _id;
    private string _firstname;
    private string _lastname;
    private bool _hasPendingChanges;

    public PersonViewModel(IPersonService personService)
    {
        if (personService == null) throw new ArgumentNullException(nameof(personService));
        _personService = personService;

        StoreCommand = new RelayCommand(StorePerson, () => true);
        HasPendingChanges = false;
    }

    public bool HasPendingChanges
    {
        get { return _hasPendingChanges; }
        set
        {
            if (value == _hasPendingChanges) return;
            _hasPendingChanges = value;
            RaisePropertyChanged(nameof(HasPendingChanges));
        }
    }

    public string Firstname
    {
        get { return _firstname; }
        set
        {
            if (value == _firstname) return;
            _firstname = value;
            HasPendingChanges = true;
            RaisePropertyChanged(nameof(Firstname));
        }
    }

    public string Lastname
    {
        get { return _lastname; }
        set
        {
            if (_lastname == value) return;
            _lastname = value;
            HasPendingChanges = true;
            RaisePropertyChanged(nameof(Lastname));
        }
    }

    public ICommand StoreCommand { get; set; }

    public async Task Init(int id)
    {
        _id = id;
        var person = id > 0 ? (await _personService.GetPeople()).ToList()[id] : new Person("", "");
        Firstname = person.FirstName;
        Lastname = person.LastName;
        HasPendingChanges = false;
    }

    private async void StorePerson()
    {
        HasPendingChanges = false;

        var person = new Person(Firstname, Lastname);

        if (_id > 0)
        {
            await _personService.UpdatePerson(_id, person);
        }
        else
        {
            await _personService.CreatePerson(person);
        }

        HasPendingChanges = false;
    }
}

Again integrating a PCL library is not difficult and requires no additional hoops to jump through. What we gain by putting our logic into the PCL is that we can reuse the code across multiple platforms.

The Controller

We will focus on the client part during this post but for getting an understanding of the bigger picture here is the controller we will be communicating with.

public class PersonController : ApiController
{
    private readonly static Lazy<IList<Person>> _people = new Lazy<IList<Person>>(() => new PersonService().GeneratePeople(1000), LazyThreadSafetyMode.PublicationOnly);
    // GET: api/Person
    public IEnumerable<Person> Get()
    {
        return _people.Value;
    }

    // GET: api/Person/5
    public Person Get(int id)
    {
        if (id < 0 || _people.Value.Count < id) return null;
        return _people.Value[id];
    }

    // POST: api/Person
    [HttpPost]
    public IHttpActionResult Post(Person value)
    {
        if (value == null) return BadRequest();

        _people.Value.Add(value);

        return CreatedAtRoute("DefaultApi", new { id = _people.Value.IndexOf(value) }, _people.Value.Last());
    }

    // PUT: api/Person/5
    [HttpPut]
    public IHttpActionResult Put(int id, [FromBody]Person value)
    {
        if (id < 0 || id >= _people.Value.Count()) return BadRequest();

        _people.Value[id] = value;

        return Ok(value);
    }

    // DELETE: api/Person/5
    public IHttpActionResult Delete(int id)
    {
        if (id < 0 || id >= _people.Value.Count()) return BadRequest();

        _people.Value.RemoveAt(id);

        return StatusCode(System.Net.HttpStatusCode.NoContent);
    }
}

internal class PersonService
{
    public IList<Person> GeneratePeople(int count)
    {
        var firstNames = new List<string>(count);
        var lastNames = new List<string>(count);

        for (int i = 0; i < count; ++i)
        {
            firstNames.Add(NameGenerator.GenRandomFirstName());
            lastNames.Add(NameGenerator.GenRandomLastName());
        }

        return firstNames.Zip(lastNames, (firstName, lastName) => new Person(firstName, lastName)).ToList();
    }
}

As you can see it is rather basic and through the static variable we have some sort of poor mans database. Do not use this way of storing data in a production environment!

Conclusion

In this post we saw how we can integrate a ASP.Net Web API server in a PCL. Thereby seeing how to read and write objects to a web service. Further we saw how we can display and enter the data on a Windows 10 client. The entire sample could have been written for Xamarin.iOS, Xamarin.Android or WPF which is exactly the sweet spot of writing your business logic in the PCL it does not matter what client you are intending to write now or in the future as long as the PCL allows you to integrate multiple client platforms.

You can find the entire sample project on NuGet.

1 Comments

JSON Logo i.e. blog post logo

Though frowned upon often due to overuse inheritance remains a powerful and (when used correctly) great feature of an object oriented programming language such as C#. But when it comes down to serializing inheritance object structures i.e. deserializing them on the other side things tend to get hairy. The post will show you how serialization and deserialization of inheritance related objects can be performed with JSON.Net.

So lets have a look at the project setup. The server will be your standard ASP.Net Web API restful web service that comes with JSON.Net out of the box. On the client side we will be using consuming the service from a Portable Class Library PCL that will be able to run with most C# stacks e.g. Windows Store, .Net, Xamarin.iOS, Xamarin.Android etc.. I’ll be using a Xamarin.Forms app but the code will run just fine in your ever day WPF app. The basic system setup is the client calls the server for data, the server returns the data serialized as JSON which will then be deserialized on the client and then used to display the information to the user.

System overview showing communication flow from the client to the server and back via JSON serialized data.

So lets have a look how it works in more detail.

Setting up the project

Lets start with looking at the server which mainly exists of a controller:

public class InheritanceController : ApiController
{
// GET: api/Inheritance
public IEnumerable<ParentClass> Get()
{
return new ParentClass[] {new ParentClass(), new ChildClass()};
}
}

The controller creates a list of ParentClasses and ChildClasses before serializing them back to the caller.

public class ParentClass
{
public virtual string Title
{
get { return "Parent"; }
}

public virtual string Descirption
{
get { return "Hello from the parent."; }
}
}

public class ChildClass:ParentClass
{
public override string Title
{
get { return "Child"; }
}

public override string Descirption
{
get { return "The child says hi..."; }
}

public string ChildSecret
{
get { return "42"; }
}
}

So not a lot of magic going as you can see on the server side. So lets have a look at the client. In the PCL we will use the HTTP Client NuGet package to call the server and the JSON.Net package to deserialize the data from the server.

Nuget Package overview on the client showing JSON.NET, Microsoft BCL Build Components, MVVMLIght libraries only, Microsoft HTTP Client Libraries and Xamarin.Forms packages

On the client we will display the data in a list, you can see the UI code in the MainPage.xaml:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="InheritanceJsonSerialization.Client.Views.MainPage">
<Grid>
<ListView ItemsSource="{Binding DataItems}" ItemSelected="ListView_OnItemSelected" />
<ActivityIndicator IsRunning="{Binding IsLoading}" IsEnabled="{Binding IsLoading}" IsVisible="{Binding IsLoading}"/>
</Grid>
</ContentPage>

In the HttpHandler class in the GetData method the data is requested from the server and then deserialized.

using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using InheritanceJsonSerialization.Client.Models;
using Newtonsoft.Json;

namespace InheritanceJsonSerialization.Client.Services.Http.Impl
{
public class HttpHandler:IHttpHandler
{
private readonly HttpClient _httpClient;

public HttpHandler()
{
_httpClient = new HttpClient();
}

public async Task<IEnumerable<ParentClass>> GetData()
{
// Ensure that uri matches the service backend you are calling
//const string uri = "http://localhost:52890/api/inheritance";
const string uri = "https://inheritancejsonserializationweb.azurewebsites.net/api/inheritance";

var httpResult = await _httpClient.GetAsync(uri);
var jsonContent = await httpResult.Content.ReadAsStringAsync();
var result = JsonConvert.DeserializeObject<IEnumerable<ParentClass>>(jsonContent);

return result;
}
}
}

Now when we deserialize the information on the client we run into the problem that the type information is not passed on to the client and therefore all objects deserialized are of type ParentClass.

Serializing with type information

Luckely JSON.Net allows us to easily include the type information when we serialize the type. On the server in the Register method within the WebApiConfig class we can setup how JSON.Net serializes objects:

public static void Register(HttpConfiguration config)
{
// Web API configuration and services
config.Formatters.JsonFormatter.SerializerSettings.TypeNameHandling = TypeNameHandling.All;

// Web API routes
config.MapHttpAttributeRoutes();

config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}

Now the information will be serialized in the JSON string:

{
"$type": "InheritanceJsonSerialization.Models.ParentClass[], InheritanceJsonSerialization",
"$values": [
{
"$type": "InheritanceJsonSerialization.Models.ParentClass, InheritanceJsonSerialization",
"Title": "Parent",
"Descirption": "Hello from the parent."
},
{
"$type": "InheritanceJsonSerialization.Models.ChildClass, InheritanceJsonSerialization",
"Title": "Child",
"Descirption": "The child says hi...",
"ChildSecret": "42"
}
]
}

On the client side we will have to do a bit more work to get deserialization working.

Deserializing with Type information

For deserializing with type information you might have already found the following line of code that will trigger JSON.Net to check for the type information and try to deserialize it according to the information present in the JSON string.

            JsonConvert.DeserializeObject<IEnumerable<ParentClass>>(jsonContent, new JsonSerializerSettings{TypeNameHandling = TypeNameHandling.All});

The problem here is that all will go well when you serialize and deserialize from the same binary/namespace but in this setup (which I regard as the common setup) you will get an exception as the namespace will not exist i.e. be different on the client than on the server. To solve this issue we have to write a SerializationBinder that inherits from the DefaultSerializationBinder as follows:

public class InheritanceSerializationBinder : DefaultSerializationBinder
{
public override Type BindToType(string assemblyName, string typeName)
{
switch (typeName)
{
case "InheritanceJsonSerialization.Models.ParentClass[]": return typeof(ParentClass[]);
case "InheritanceJsonSerialization.Models.ParentClass": return typeof(ParentClass);
case "InheritanceJsonSerialization.Models.ChildClass[]": return typeof(ChildClass[]);
case "InheritanceJsonSerialization.Models.ChildClass": return typeof(ChildClass);
default: return base.BindToType(assemblyName, typeName);
}
}
}

This will simply map the server namespace to local types. Finally we can update the GetData method in the HttpHandler class:

public async Task<IEnumerable<ParentClass>> GetData()
{
// ...
var result = JsonConvert.DeserializeObject<IEnumerable<ParentClass>>(jsonContent, new JsonSerializerSettings{TypeNameHandling = TypeNameHandling.All, Binder = new InheritanceSerializationBinder()});

return result;
}

And now when we deserialize the list the ChildClass will be correctly identified i.e. the list will be preserved through deserialization.

Conclusion

In this post you saw how inheritance hirarchies can be correctly serialized and deserialized on the client using JSON.Net. By doing so we had to configure our ASP.Net Web API and add handling mechanisms on the client side. I hope this post is of any help and please let me know if I may have mist anything Smile

You can find the code on GitHub.

0 Comments

StorageImage

A lot of applications have to persist application data or state. When developing mobile applications with C# such as for Windows or with Xamarin for iOS and Android it is a common approach to share your business logic and backend implementations in the Portable Class Library (PCL). In this blog post we’ll look at how we can also implement storage within the PCL and therefore will only need to implement the storage services once. We will be focusing on the following topics:

  1. Setting up the project
  2. Storing and loading objects to files
  3. Storing/using binary data such as images

So lets start off by setting up the project. I’ll be demonstrating the sample with a Xamarin.Forms project as it allows me to quickly develop, deploy and test an app on all three major mobile platforms. But as the code is in the PCL you can use the exact same approach to implement the system in Windows Store, WPF etc. applications.

Setting up the project

Lets create an app that lists Companies by name, URL and displays the company logo. To do this we will create a view that will display the content as follows:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamarinFormsOfflineStorage.Views.MainPage">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Button Text="Refresh" Command="{Binding UpdateCompaniesCommand}"></Button>
<ListView ItemsSource="{Binding Companies}" Grid.Row="1">
<ListView.ItemTemplate>
<DataTemplate>
<ImageCell Text="{Binding Name}" ImageSource="{Binding ImageUri}" Detail="{Binding ImageDescription}"></ImageCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<ActivityIndicator Grid.Row="1" IsRunning="{Binding IsLoadingData}"></ActivityIndicator>
</Grid>
</ContentPage>

The data is provided by a View Model that is based upon the MVVM Light framework by Laurent Bugnion. I wrote a post a while ago on how to get started with MVVM Light and Xamarin.Forms.

public class MainViewModel:ViewModelBase
{
private readonly ICompanyService _companyService;
private bool _isLoadingData;

public MainViewModel(ICompanyService companyService)
{
if (companyService == null) throw new ArgumentNullException("companyService");
_companyService = companyService;

Companies = new ObservableCollection<Company>();
IsLoadingData = false;
UpdateCompaniesCommand = new RelayCommand(UpdateCompanies, () => !IsLoadingData);
}

public bool IsLoadingData
{
get { return _isLoadingData; }
set
{
if (value == _isLoadingData) return;
_isLoadingData = value;
RaisePropertyChanged(() => IsLoadingData);
}
}

public ObservableCollection<Company> Companies { get; set; }

public ICommand UpdateCompaniesCommand { get; set; }

public async Task Init()
{
await UpdateCompaniesList();
}

private async void UpdateCompanies()
{
IsLoadingData = true;

await _companyService.UpdateCompanies();
await UpdateCompaniesList();

IsLoadingData = false;
}

private async Task UpdateCompaniesList()
{
var companies = await _companyService.GetCompanies();

Companies.Clear();

foreach (var company in companies)
{
Companies.Add(company);
}
}
}

Which calls a CompanyService that calls the backend:

// ...

public async Task UpdateCompanies()
{
// URL should point to where your service is running
const string uri = "http://offlinestorageserver.azurewebsites.net/api/values";
var httpResult = await _httpClient.GetAsync(uri);
var jsonCompanies = await httpResult.Content.ReadAsStringAsync();

var companies = JsonConvert.DeserializeObject<ICollection<Models.Company>>(jsonCompanies);
_companies = companies;
}

// ...

And provides a list of companies:

public IEnumerable<Models.Company> GetCompanies()
{
return _companies;
}

Now lets look on how we can store this list to the “disk” and display the information even if the app is started when there is no connection to the backend.

Enabling storage access in the PCL

Thanks to Daniel Plaisted accessing the file storage from within the PCL of your applications is actually really easy. All that is left to do for us is installing the NuGet package PCL Storage. Ensure that you install it not only for the PCL but only for the platforms you are targeting with your app:

PclStorageNugetInstall

Before we store lets just still quickly have a look at where we actually want to store the files. The PCL storage provides a start location which can be accessed by calling the FileSystem.Current.LocalStorage property. This will return an IFolder object which can be allows navigating to further folders by invoking the GetFolder method, alternatively the CreateFolder method can also be used with the collision option OpenIfExists, I generally use the second approach as it allows to write less code. So if we want to store our data in a folder within the root location of the local storage it would be done as follows:

private static async Task<IFolder> NavigateToFolder(string targetFolder)
{
IFolder rootFolder = FileSystem.Current.LocalStorage;
IFolder folder = await rootFolder.CreateFolderAsync(targetFolder,
CreationCollisionOption.OpenIfExists);

return folder;
}

As you can see the PCL Storage embraces the Async/Await pattern nicely and therefore will not block your app i.e. UI when working against the file system. Now lets get down to storing some data.

Persist an object

Now lets first store the list of objects we receive from our service into a file. As I’m already using JSON.Net for deserializing the data that comes from our service I’ll be using this library to serialize our objects to a JSON string and then store the now text data to a file in the SerializeCompanies method:

private static async Task SerializeCompanies(IFolder folder, ICollection<Models.Company> companies)
{
IFile file = await folder.CreateFileAsync(CompaniesFileName, CreationCollisionOption.ReplaceExisting);
var companiesString = JsonConvert.SerializeObject(companies);
await file.WriteAllTextAsync(companiesString);
}

As you can see files are created similarly to folders but differ in the collision option. It generally is a generally easier to handle merging of data in the C# memory world itself (given that the list is not to large for this) and then simply overwriting the preexisting cache.

Loading the data object

We can now update the GetCompanies method to return the list when we call it.

public async Task<IEnumerable<Models.Company>> GetCompanies()
{
return _companies ?? (_companies = await ReadCompaniesFromFile());
}

Once the data has been persisted by the website we do no longer require an internet connection to present the user with the information. And we can simply read them from a file as in ReadCompaniesFromFile:

private async Task<IEnumerable<Models.Company>>  ReadCompaniesFromFile()
{
var folder = await NavigateToFolder(CompaniesFolder);

if ((await folder.CheckExistsAsync(CompaniesFileName)) == ExistenceCheckResult.NotFound)
{
return new List<Models.Company>();
}

IFile file = await folder.GetFileAsync(CompaniesFileName);
var jsonCompanies = await file.ReadAllTextAsync();

if (string.IsNullOrEmpty(jsonCompanies)) return new List<Models.Company>();

var companies = JsonConvert.DeserializeObject<IEnumerable<Models.Company>>(jsonCompanies);

return companies;
}

Now the object data is persisted but we haven’t yet stored the images which is not text data but binary data. So lets see how we can store images to the file system.

Store binary data

To store the images we will have to get the images and store the binary data from the web to a file. This is done using the file stream of the opened file in the StoreImagesLocallyAndUpdatePathmethod:

private async Task StoreImagesLocallyAndUpdatePath(IFolder folder, IEnumerable<Models.Company> companies)
{
foreach (var company in companies)
{
var file = await folder.CreateFileAsync(company.Name + ".jpg", CreationCollisionOption.ReplaceExisting);
using (var fileHandler = await file.OpenAsync(FileAccess.ReadAndWrite))
{
var httpResponse = await _httpClient.GetAsync(company.ImageUri);
byte[] imageBuffer = await httpResponse.Content.ReadAsByteArrayAsync();
await fileHandler.WriteAsync(imageBuffer, 0, imageBuffer.Length);

company.ImageUri = file.Path;
}
}
}

Streams should always be disposed or else memory leaks will occur so the stream is wrapped in a using block. For storing the binary data we download the image via the URL provided and read the content into a byte array which allows us to easily pass it into the stream so it can get stored. Finally we replace the ImageUri data in the POCO (Plain Old CLR Object) before it gets serialized.

I recommend that you use the file endings according to the data you are storing. Certain containers rely on the information so as long as the good practice is kept up we are not running the risk of having to debug a strange error of information not showing up on the screen.

Loading images

Now we could load the images back into memory but as images are somewhat a special case the local path / ImageUri alone is enough to be set in the image control. So we actually do not have to change any code in the UI or add any additional handling as the image control will simply now load the image from the local storage.

Conclusion

In this post we saw how we can setup our projects to store files directly out of the PCL. We stored a data object i.e. text data to a file and proceeded to store an image/binary data. I think a big thank you is due to Daniel Plaisted as his work really streamlines persisting data with from the PCL.

You can find the entire code on GitHub.

References

Title Image by Dr. Hannes Grobe under Creative Commons V3

1 Comments
cloning_by_silverstormblackfang-d5bkptt

Usually when cloning an object in .Net I just use the Binary stream, this will automatically perform a deep copy of the object. But when writing code on the PCL we do not have the Binarystram and therefore have to look for new options. I'm not a big fan of doing this manually by implementing copy constructors on each an every object as it is an error prone task as it leaves it up to the devs to implement it on new or changes to existing classes.

So the next best option to hand is using another stream writer, I started to use JSON.Net for the task as it is available for all the major mobile platforms and on the server objects. So we can rest assured for now that it will run on all the platforms we target. Another goody I like to include implementing it as an extension method on object. So lets have a look at how this would be done:

public static T Clone<T>(this T source)
{
if (Object.ReferenceEquals(source, null))
{
return default(T);
}

// In the PCL we do not have the BinaryFormatter
return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(source));
}

So from now on when ever we need to clone/deep copy an object we can simply invoke it by calling the clone method on the required object.

var original = new NestedObject();

var clone = original.Clone();

HTH