1 Comments

In the article How to prepare a cross platform visual studio project for MVVM, I explained how to create a Visual Studio solution for cross platform application development using PCL and MVVM. In this article I continue with the sample project and implement a very simple example to put things together and see how the project structure and organization is used.

Let’s do a quick example. Let’s do a list of persons and display it on each devices using our recently configured MVVM project.

The model

On the PCL project, on the “Models” folder, create a file called Person.cs and replace it with this code:

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

namespace SampleApp.Models
{
    public class Person : ObservableObject
    {
        private string name;
        public string Name
        {
            get { return name; }
            set { Set(ref name, value); }
        }
    }
}

We are inheriting from ObservableObject (from MVVM Light) thus implementing INotifyPropertyChanged. We will now create a simple service to store data in the device. For this we need two services: a data service that will be common to all platforms, and a storage service that will be device specific.

The data service

Let’s start with the storage service. The interface for this service is declared in the PCL, but the implementation will be specific to both WinRT and WP. On the PCL project, on the “Services\Interfaces” folder, create a class called IStorageService.cs:

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

namespace SampleApp.Services
{
    public interface IStorageService
    {
        Task SaveTextAsync(string file, string text);

        Task<string> LoadTextAsync(string file);
    }
}

Now, let’s implement this interface on each of the devices. On the WinRT project, on the “Services” folder create a class named StorageService.cs:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Storage;

namespace SampleApp.Services
{
    public class StorageService : IStorageService
    {

        public async Task SaveTextAsync(string fileName, string text)
        {
            StorageFile file = await ApplicationData.Current.LocalFolder.CreateFileAsync(fileName, CreationCollisionOption.ReplaceExisting);

            byte[] data = Encoding.UTF8.GetBytes(text);

            using (var s = await file.OpenStreamForWriteAsync())
            {
                await s.WriteAsync(data, 0, data.Length);
            }
        }

        public async Task<string> LoadTextAsync(string fileName)
        {
            try
            {
                StorageFile file = await ApplicationData.Current.LocalFolder.GetFileAsync(fileName);

                using (var s = await file.OpenStreamForReadAsync())
                {
                    using (var sr = new StreamReader(s))
                    {
                        return await sr.ReadToEndAsync();
                    }
                }
            }
            catch (Exception)
            {
                Debug.WriteLine("Error loading file '{0}'", fileName);
                return null;
            }
        }
    }
}

This is pretty simple, we just create a file on the application folder with the content. Let’s do the same for the WP project, but instead of creating and repeating the code, we will use the same file for the WinRT project, since the code is basically the same and it works without any changes on WP. This will be more and more the case as Microsoft is slowly converging both platforms, and now with the announce in Build2014 of universal apps this convergence is much closer. On the WP project, on the “Services” folder, add a link to the StorageService.cs file created before.

Now, we need to register both services with the IoC container. We will do this in LocatorService.cs file on the WinRT project (if you remember from the previous article, we just added this same file as a link on the WP project, se we need to change it once). Add the highlighted lines to the file:

using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Ioc;
using Microsoft.Practices.ServiceLocation;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SampleApp.Services
{
    public class DeviceLocatorService
    {
        static DeviceLocatorService()
        {
            ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);

            if (ViewModelBase.IsInDesignModeStatic)
            {
            }
            else
            {
            }

            if (!SimpleIoc.Default.IsRegistered<IStorageService>()) SimpleIoc.Default.Register<IStorageService, StorageService>();
        }

        public static void Cleanup()
        {
        }
    }
}

Compile your solution to make sure everything works. Now, let’s create the data service. This data service will use the storage service to store the data in an XML format. In the PCL project, on the “Services\Interfaces” folder, create a file called IDataService.cs and replace the code with this:

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

namespace SampleApp.Services
{
    public interface IDataService
    {
        Task<IEnumerable<Person>> GetPersonsAsync();

        Task AddPersonAsync(Person person);
    }
}

As I mentioned before, let’s keep it simple :-). Now the implementation, in the PCL project, on the “Services” folder, create a file called DataService.cs with this code:

using SampleApp.Models;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;

namespace SampleApp.Services
{
    public class DataService : IDataService
    {
        private const string dataFile = "data.xml";

        private IStorageService storageService;
        private List<Person> persons;

        public DataService(IStorageService storageService)
        {
            this.storageService = storageService;
        }

        public async Task<IEnumerable<Person>> GetPersonsAsync()
        {
            if (persons == null) await LoadAsync();
            return persons;
        }

        public async Task AddPersonAsync(Person person)
        {
            if (persons == null) await LoadAsync();
            persons.Add(person);
            await SaveAsync();
        }

        private async Task SaveAsync()
        {
            StringWriter sw = new StringWriter();
            XmlSerializer serializer = new XmlSerializer(typeof(List<Person>));
            serializer.Serialize(sw, persons);

            await storageService.SaveTextAsync(dataFile, sw.ToString());
        }

        private async Task LoadAsync()
        {
            string data = await storageService.LoadTextAsync(dataFile);

            if (!string.IsNullOrEmpty(data))
            {
                StringReader sr = new StringReader(data);
                XmlSerializer serializer = new XmlSerializer(typeof(List<Person>));

                persons = (List<Person>)serializer.Deserialize(sr);
                
            }
            else
            {
                persons = new List<Person>();
            }
        }
    }
}

The service just serializes and deserializes data to and from an XML file. Notice the constructor of the service, it expects as a parameter an instance to a storage service, this instance is resolved by the IoC container and injected at run time. The service that will be injected will be the one registered in the locator service specific to the platform where the app is running. Everything is wired up appropriately.

Design time data

Now, this works fine when running on the device, but what about Blend? What about design time data? Designers will thank us if we provide design time data as part of the project as well. Let’s do this. On the PCL project, create a folder called “Design” and add a class named DataService.cs:

using SampleApp.Models;
using SampleApp.Services;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SampleApp.Design
{
    public class DataService : IDataService
    {
        public Task<IEnumerable<Person>> GetPersonsAsync()
        {
            List<Person> persons = new List<Person>() {
                new Person() { Name = "Giovanni" },
                new Person() { Name = "Antonio"}
            };

            TaskCompletionSource<IEnumerable<Person>> tcs = new TaskCompletionSource<IEnumerable<Person>>();
            tcs.SetResult(persons);
            return tcs.Task;
        }

        public Task AddPersonAsync(Person person)
        {
            throw new NotImplementedException();
        }
    }
}

The above class will provide design time data for our views. Notice that we only provide the implementation of the GetPersosnAsync method, since this is the only method that we will need at design time. Now, we need to register this service to be used instead of the previous one when we are working at design time. We do this in the LocatorService.cs file in the PCL project. Open the file and add the lines highlighted below:

using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Ioc;
using Microsoft.Practices.ServiceLocation;
using SampleApp.ViewModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SampleApp.Services
{
    public class LocatorService
    {
        static LocatorService()
        {
            ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);

            // Services
            if (ViewModelBase.IsInDesignModeStatic)
            {
                SimpleIoc.Default.Register<IDataService, Design.DataService>();
            }
            else
            {
                SimpleIoc.Default.Register<IDataService, Services.DataService>();
            }

            // View Models
            SimpleIoc.Default.Register<IMainViewModel, MainViewModel>();
        }

        public IMainViewModel MainViewModel
        {
            get
            {
                return ServiceLocator.Current.GetInstance<IMainViewModel>();
            }
        }

        public static void Cleanup()
        {
        }
    }
}

With this the IoC container will inject the design time data service when in design time, and the real data service (the one that works with the device storage) at run time on the device.

We have completed the model and the data access, next thing is the view model.

The view model

Let’s add some methods to our view model. In the PCL project, on the “ViewModels\Interfaces” folder, edit the IMainViewModel.cs file as follows:

using GalaSoft.MvvmLight.Command;
using SampleApp.Models;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


namespace SampleApp.ViewModels
{
    public interface IMainViewModel
    {
        ObservableCollection<Person> Persons { get; }

        RelayCommand RefreshCommand { get; }
        RelayCommand AddCommand { get; }
    }
}
We’ve added an observable collection to bind to the views (we will do this later) and also commands to

execute business logic. Let’s implement the interface, open the MainViewModel.cs file and replace it with the following code:

using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using SampleApp.Models;
using SampleApp.Services;
using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


namespace SampleApp.ViewModels
{
    public class MainViewModel : ViewModelBase,IMainViewModel
    {
        private IDataService dataService;

        public MainViewModel(IDataService dataService)
        {         
            this.dataService = dataService;

            RefreshAsync();

        }

        private ObservableCollection<Person> persons = new ObservableCollection<Person>();
        public ObservableCollection<Person> Persons
        {
            get
            {
                return persons;
            }
        }

        #region Commands

        #region Refresh
        private RelayCommand refreshCommand;
        public RelayCommand RefreshCommand
        {
            get
            {
                return refreshCommand
                    ?? (refreshCommand = new RelayCommand(
                                          async () =>
                                          {
                                              await RefreshAsync();
                                          }));
            }
        }

        private async Task RefreshAsync()
        {
            persons.Clear();
            foreach (Person person in await dataService.GetPersonsAsync())
                persons.Add(person);
        }
        #endregion

        #region Add
        private RelayCommand addCommand;
        public RelayCommand AddCommand
        {
            get
            {
                return addCommand
                    ?? (addCommand = new RelayCommand(
                                          async () =>
                                          {
                                              Person person = new Person() { Name = "Giovanni" };
                                              await dataService.AddPersonAsync(person);
                                              persons.Add(person);
                                          }));
            }
        }
        #endregion

        #endregion
    }
}

Notice how the constructor expects a reference to a data service, which, as explained before, will be injected by the IoC container. The other thing to notice is the use of the design time data, the constructor does a refresh of the data so we can have data when working with the views.

We have completed our view model. Now we will work the views.

The views

I will provide a very simple view, no beauty on it, we will leave this for the designer. Instead, let’s focus on the code. Let’s first work the WinRT view. We will add a grid view and an app bar to add and refresh the data. On the WinRT project, open the MainPage.xaml and replace it with the following:

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

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

        <GridView ItemsSource="{Binding Persons}">
            <GridView.ItemTemplate>
                <DataTemplate>
                    <Grid>
                        <TextBlock Text="{Binding Name}" />
                    </Grid>
                </DataTemplate>
            </GridView.ItemTemplate>
        </GridView>
    </Grid>

    <Page.BottomAppBar>
        <AppBar>
            <Grid>
                <StackPanel Orientation="Horizontal">
                    <AppBarButton Command="{Binding AddCommand}" Icon="AddFriend" Label="Add Person" />
                </StackPanel>

                <StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
                    <AppBarButton Command="{Binding RefreshCommand}" Icon="Refresh" Label="Refresh" />
                </StackPanel>
            </Grid>
        </AppBar>
    </Page.BottomAppBar>
</Page>

We have used data binding to bind the list of persons and the commands as well. No code-behind! If you do this in the VS XAML editor, you will see the design time data:

WinRT view

On WP, we have one problem: the app bar doesn’t provide binding to commands. For this we will rely on a cool package called AppBarUtils. On the WP project, add this package using the nuget package manager. Replace the code in MainPage.xaml with the following:

<phone:PhoneApplicationPage
    x:Class="SampleApp.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"    
    xmlns:abu="clr-namespace:AppBarUtils;assembly=AppBarUtils"
    mc:Ignorable="d"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Portrait" Orientation="Portrait"
    shell:SystemTray.IsVisible="True"
    DataContext="{Binding MainViewModel,Source={StaticResource Locator}}">
    
    <!--LayoutRoot is the root grid where all page content is placed-->
    <Grid x:Name="LayoutRoot" Background="Transparent">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <!--TitlePanel contains the name of the application and page title-->
        <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
            <TextBlock Text="MY APPLICATION" Style="{StaticResource PhoneTextNormalStyle}" Margin="12,0"/>
            <TextBlock Text="page name" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
        </StackPanel>

        <!--ContentPanel - place additional content here-->
        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <phone:LongListSelector Margin="0,0,-22,0" ItemsSource="{Binding Persons}">
                <phone:LongListSelector.ItemTemplate>
                    <DataTemplate>
                        <Grid>
                            <TextBlock Text="{Binding Name}" />
                        </Grid>
                    </DataTemplate>
                </phone:LongListSelector.ItemTemplate>
            </phone:LongListSelector>
        </Grid>

        <!--<Image Source="/Assets/AlignmentGrid.png" VerticalAlignment="Top" Height="800" Width="480" Margin="0,-32,0,0" Grid.Row="0" Grid.RowSpan="2" IsHitTestVisible="False" />-->
    </Grid>

    <phone:PhoneApplicationPage.ApplicationBar>
        <shell:ApplicationBar Mode="Default" Opacity="1.0" IsMenuEnabled="True" IsVisible="True">
            <shell:ApplicationBarIconButton IconUri="/Assets/AppBar/add.png" Text="add" />
            <shell:ApplicationBarIconButton IconUri="/Assets/AppBar/refresh.png" Text="refresh" />
        </shell:ApplicationBar>
    </phone:PhoneApplicationPage.ApplicationBar>

    <i:Interaction.Behaviors>
        <abu:AppBarItemCommand Id="add" Command="{Binding AddCommand}" Text="Add Person" />
        <abu:AppBarItemCommand Id="refresh" Command="{Binding RefreshCommand}" Text="Refresh" />
    </i:Interaction.Behaviors>
</phone:PhoneApplicationPage>

We have used data binding to bind the list of persons and the commands as well. Again, no code-behind! If you do this in the VS XAML editor, you will see the design time data:

WP

We have completed the views. Now, test it (pray) and make sure that everything works.

You can download the sample code from here:

2 Comments

In a previous blog post I explained how to configure a visual studio project structure for cross platform application development, using a PCL project for most of our app logic. In this article I will continue on the example and explain how to prepare the projects to work with MVVM. There is a lot of documentation about MVVM on the web so I won’t repeat it here, instead I will focus on project organization: where do I put models? how do I organize folders? what changes do I need to make in VS?, etc. I hope with this article to save you time reading a bunch of articles that only show part of the big picture.

visualStudioSolutionI’m assuming you have a project structure such as the one in the figure, where you have a PCL project for the business logic (our models and view models in MVVM jargon), and a project for each of the platforms you want to target: Windows RT and Windows Phone in our example. The PCL project has been included as a reference on each of the platform specific projects.

We want to do things right so we will use an IoC container to inject objects in our code. You can use any IoC container you want, I’m a big fan of MVVM Light, so this is what I will use for the example. MVVM Light has its own IoC container and also has some utility classes that are very useful for MVVM. I recommend you read the documentation and see some sample of MVVM Light on its web page.

MVVM has three main entities: models, view models and views. Where do we put these? Models and view models should be independent of the platform, so they should go in the PCL project. Views, on the other hand, are dependent of the platform (e.g. to present a list of items in WinRT we use a  GridView, while in Windows Phone we use a LongListSelector), so they should go on each of the platform projects. There is another entity in a good MVVM project: services.

Services fill the gap between the platform independent code in the PCL and the platform dependent code on each of the platform projects. This is better illustrated with an example: suppose our business logic (which is coded in the view model) needs to display a message to the user; messages are displayed differently on each platform, so a dialog box in WP looks different and has a different API than the one in WinRT. The view model doesn’t know (and this is ok) how to display a message for a specific platform. This is the whole purpose of MVVM, each layer is only concerned with what it needs to do. Displaying a message is the job of the platform. So, how can we display a message to the user if the logic is in the view model. This is where services come in handy. We will have a service for each platform and we will tell the view model to use that service. When the view model wants to display a message to the user, it will call the appropriate service to do it. Since view models are independent of the platform, services are injected at run time using an IoC container. This works the same for a bunch of other features such as accessing devices specific hardware (GPS, accelerometer, etc.), accessing data on the device, working with the device screen, etc. There’s a lot of documentation on this on the web, this was just a brief description since we will need to know about this fourth entity (the service) when creating our project structure.

The views

Since this is all about organization, let’s start by organizing our views. When we create the WinRT/WP project VS will automatically create a MainPage.xaml (a view) into our project root. If we follow this, we will end up with all our views in the root folder. I like my root folder very clean, so the first thing is to create a “Views” folder on each of the WinRT and WP folder and move MainPage.xaml into it. If you just do this, you will find that your project might not even start. There are some things you need to do as well.

In the WinRT project this is straightforward, create the “Views” folder and move the MainPage.xaml into it. That’s it! This works since the initial page to show is called from App.xaml.cs on the OnLaunched event, and since we haven’t changed the name of the class nor its namespace things still work. In WP project is not as easy. Create the “Views” folder and move the MainPage.xaml into it, open the app manifest (located in Properties\WMAppManifest.xml) and edit the “Navigation Page” field to specify the full path to the page, including the “Views” folder (see image below). You will have a project structure as follows:

Views folder created on projects


The services

servicesNow, in the PCL project create folders for the “Models”, “ViewModels” and “Services”, as shown in the figure. For the “Models” and “ViewModels” folder, create a subfolder called "Interfaces”. This folder is where we will create all the interface declarations. Create a “Services” folder on both the WinRT and WP project as well. You should now have a structure such as the one on the figure.

Next, use the nuget package manager to install MVVM Light PCL. Install only the libraries. You need to install this package on all three projects. Next we will configure the MVVM Light IoC container and wire things up. We need a locator service, which will be responsible for configuring the IoC container and to provide the right view models to the view. In the case of platform services we will need to configure these on both WinRT and WP projects.

On the PCL project, on the “Services” folder, create a file called LocatorService.cs. Replace the code with the one below:

using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Ioc;
using Microsoft.Practices.ServiceLocation;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SampleApp.Services
{
    public class LocatorService
    {
        static LocatorService()
        {
            ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);


            // Services
            if (ViewModelBase.IsInDesignModeStatic)
            {
            }
            else
            {
            }

            // View Models
        }


        public static void Cleanup()
        {
        }
    }
}

We will later add code to this file to register all the services and view models. For the moment let’s leave it as it is and compile the solution. We will register here services that are cross platform. For services that are platform specific (most of them) we will need a similar file on both the WinRT and WP projects. On the WinRT project, on the “Services” folder, create a file called LocatorService.cs and replace the code with the following:

using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Ioc;
using Microsoft.Practices.ServiceLocation;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SampleApp.Services
{
    public class DeviceLocatorService
    {
        static DeviceLocatorService()
        {
            ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);

            if (ViewModelBase.IsInDesignModeStatic)
            {
            }
            else
            {

            }

        }

        public static void Cleanup()
        {
        }
    }
}

Notice that the name of the class is DeviceLocatorService. This is different than the one specified on the PCL project, since this locator service is for device specific services and since they both share the same namespace (remember that in our case we want the same namespace for all projects) we need to specify a different name. We need to do this on the WP project as well, but instead of creating a new class we will add a link to the file used for the WinRT project, as the code is the same for both platforms. This is one of the tricks used to share code between platform projects, just make sure to select the “Add as Link” from the drop down button in the “Add existing item” dialog box.

Now we need to register these services on each of the platforms. On the WinRT project, open the file App.xaml, add the lines highlighted below:

<Application
    x:Class="SampleApp.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:ignore="http://www.ignore.com"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"    
    mc:Ignorable="d ignore"    
    xmlns:services="using:SampleApp.Services"    
    xmlns:local="using:SampleApp">

    <Application.Resources>
        <ResourceDictionary>
            <services:DeviceLocatorService x:Key="Locator.W8" d:IsDataSource="True" />
            <services:LocatorService x:Key="Locator" d:IsDataSource="True" />
        </ResourceDictionary>
    </Application.Resources>
</Application>

The important thing to understand is that by declaring both classes (DeviceLocatorService and LocatorService) as resources the application will automatically execute the static code on both classes, thus configuring the IoC container with the classes we need. Notice that the device locator service is specified before the generic locator service. This is because the generic locator service will need references to device services and thus is dependent of these.

On the WP project, open the App.xaml file and add the lines highlighted below:

<Application
    x:Class="SampleApp.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    mc:Ignorable="d"    
    xmlns:services="clr-namespace:SampleApp.Services;assembly=SampleApp.PCL"
    xmlns:deviceServices="clr-namespace:SampleApp.Services">

    <!--Application Resources-->
    <Application.Resources>
        <local:LocalizedStrings xmlns:local="clr-namespace:SampleApp" x:Key="LocalizedStrings"/>
        <deviceServices:DeviceLocatorService x:Key="Locator.WP8" d:IsDataSource="true" />
        <services:LocatorService x:Key="Locator" d:IsDataSource="true" />
   </Application.Resources>

    <Application.ApplicationLifetimeObjects>
        <!--Required object that handles lifetime events for the application-->
        <shell:PhoneApplicationService
            Launching="Application_Launching" Closing="Application_Closing"
            Activated="Application_Activated" Deactivated="Application_Deactivated"/>
    </Application.ApplicationLifetimeObjects>

</Application>

At this point, compile your projects and make sure everything runs.

The view models

We will now create our view model for the MainPage.xaml view. On the PCL project, on the ViewModels\Interfaces folder, create a file called IMainViewModel.cs, and replace the code with the one below:

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

namespace SampleApp.ViewModels
{
    public interface IMainViewModel
    {        
    }
}

VS by default will add the folder structure as part of the namespace. This means that the interface will have the namespace SampleApp.ViewModels.Interfaces. This is ok, but I don’t want that many namespaces so I remove the .Interfaces part and make it just one namespace for the view models SampleApp.ViewModels. Next, let’s create the implementation of this interface. In the PCL project, on the “ViewModels” folder, create a file called MainViewModel.cs and replace the code as follows:

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


namespace SampleApp.ViewModels
{
    public class MainViewModel : IMainViewModel
    {
    }
}

Now, let’s register this view model with the IoC container and wire it up on the view. On the PCL project, open the LocatorService.cs file and add the lines highlighted below:

using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Ioc;
using Microsoft.Practices.ServiceLocation;
using SampleApp.ViewModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SampleApp.Services
{
    public class LocatorService
    {
        static LocatorService()
        {
            ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);

            // Services
            if (ViewModelBase.IsInDesignModeStatic)
            {
            }
            else
            {
            }

            // View Models
            SimpleIoc.Default.Register<IMainViewModel, MainViewModel>();
        }

        public IMainViewModel MainViewModel
        {
            get
            {
                return ServiceLocator.Current.GetInstance<IMainViewModel>();
            }
        }

        public static void Cleanup()
        {
        }
    }
}

On the WinRT project, open the Views\MainPage.xaml file and add the lines highlighted below:

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

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

    </Grid>
</Page>

We are setting up the data context of the page to the view model, which is exposed by the service locator (identified by the key Locator) through the property MainViewModel. We will do the same for our WP project. Open the Views\MainPage.xaml and add the lines highlighted below:

<phone:PhoneApplicationPage
    x:Class="SampleApp.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Portrait" Orientation="Portrait"
    shell:SystemTray.IsVisible="True"
    DataContext="{Binding MainViewModel,Source={StaticResource Locator}}">
    
    <!-- code omitted for simplicity -->

</phone:PhoneApplicationPage>

The project structure is already set up, things are wired up, and we can now start working on the specifics of our application.

I the next article I will explain how to use this project structure for a sample application.

0 Comments

In the previous post (How to show a progress bar for a long operation in Pivotal) I talked about how to improve the user experience when executing long running operations. I explained how to show a progress bar to provide feedback to users that an operation is in progress and they should (patiently) wait. The user experience changes a lot when we provide feedback to users.

In this post I will talk about an alternative for long running operations that basically removes the wait time from the user. In this case, the long running operation will be executing on the server while the user gets back the control of the system. An example that shows a good use of an asynchronous operation is the following: suppose that when the user submits a new service ticket there are a bunch of emails being sent (to the supervisor, to the service queue, to the user acknowledging the submission, etc.) All these emails take time to be sent. If we do this on the server task associated to the service ticket, then the user will have to wait a (possibly) long time until all emails are being sent. All the user wants is to submit the incident, he/she doesn’t care if the emails are being sent at submission time or later.

CropperCapture[5]There are many ways to do this. You can set up an email queue and then have a background process (e.g. the scheduler script) to read the queue and send emails. In this case the submission task is responsible to submit the email jobs to the queue. In this post I will talk of a simpler way: a generic asynchronous task that executes server task method in the background.


For illustration purposes, let’s use a simple task to simulate our long running operation. The same example for our previous post will do:

[TaskExecute]
public virtual void LongRunningOperation(Id recordId)
{
    Trace.WriteLine(String.Format("Starting LongRunningOperation with recordId '{0}'", recordId));
    System.Threading.Thread.Sleep(20000);
    Trace.WriteLine(String.Format("Finishing LongRunningOperation with recordId '{0}'", recordId));
}

The client task makes a call to this method:

[ClientTaskCommand]
public virtual void LongRunningTask()
{
    try
    {
        Globals.Execute(this.DataTemplate, "LongRunningOperation", new object[] { this.RecordId });
        PivotalMessageBox.Show("Done", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Information);
    }
    catch (Exception e)
    {
        Globals.HandleException(e.InnerException ?? e, true);
    }
}

As it is right now, the user will have to wait 20 seconds for the task to execute, and during this time the client is freezing doing nothing. Let’s see how we can change this and make all this asynchronous. The client will remain the same, we don’t to change the client side code. The server side code, however, will suffer a little change:

[TaskExecute]
public virtual void LongRunningOperationSync(Id recordId)
{
    Trace.WriteLine(String.Format("Starting LongRunningOperation with recordId '{0}'", recordId));
    System.Threading.Thread.Sleep(20000);
    Trace.WriteLine(String.Format("Finishing LongRunningOperation with recordId '{0}'", recordId));
}

[TaskExecute]
public virtual void LongRunningOperation(Id recordId)
{
    TransitionPointParameter t = new TransitionPointParameter();
    t.SetUserDefinedParameter(1, "Ticket Service");
    t.SetUserDefinedParameter(2, "LongRunningOperationSync");
    t.SetUserDefinedParameter(3, recordId);

    this.SystemServer.ExecuteServerTask("Async Service", "ExecuteApp", t.ParameterList, false);
}

We have split our long running operation in two: the LongRunningOperation method now makes a call to a new service task called “Async Service”, executing the method “ExecuteApp”, and passing some transition point parameters. These parameters are: the name of the service task (in this example I’m assuming our service task is called “Ticket Service”), and the method that actually does the hard work, and the parameters for such method. Our second method, the LongRunningOperationSync, is the one that actually does the job. The body of this method is the same as we had before.

The Async Service task is a generic service task that executes another service task asynchronously. Let’s see how to implement our async service:

[TaskExecute]
public virtual void ExecuteApp(ParameterList parameterList)
{
    string serverName = TypeConvert.ToString(TransitionPointParameter.GetUserDefinedParameter(1));
    string methodName = TypeConvert.ToString(TransitionPointParameter.GetUserDefinedParameter(2));

    object[] parameters = new object[] { };
    if (this.TransitionPointParameter.UserDefinedParametersNumber > 2) // get the rest of parameters
    {
        List<object> passedParameters = new List<object>();
        for (int i = 3; i <= this.TransitionPointParameter.UserDefinedParametersNumber; i++)
        {
            object parameter = this.TransitionPointParameter.GetUserDefinedParameter(i);
            if (String.IsNullOrWhiteSpace(TypeConvert.ToString(parameter)))
                passedParameters.Add(null);
            else
                passedParameters.Add(parameter);
        }
        parameters = passedParameters.ToArray();
    }

    ExecuteApp(serverName, methodName, parameters);
}

/// <summary>
/// Executes an application server task method
/// </summary>
/// <param name="appName">The name of the application server task</param>
/// <param name="methodName">The name of the server task method</param>
/// <param name="methodParameters">An array of parameters to be passed to the server taks</param>
private bool ExecuteApp(string appName, string methodName, object[] methodParameters)
{
    try
    {
        XElement xmlCommand = BuildExecuteServiceTaskCommand(appName, methodName, methodParameters == null ? new object[] {} : methodParameters);
        SendCommandAsync(xmlCommand);

        return true;
    }
    catch (Exception e)
    {
        // log the error
        throw;
    }
}

The service exposes only one public method. This method is responsible to retrieve the required parameters: the service task and method name, and the parameters for such method. It parses the transition point parameters for such information and then it calls the second method, which is more interesting. This method calls two helper methods: BuildExecuteServiceTask (to build an XML document) and SendCommandAsync (to do the async call). Let’s see these methods are implemented.

The BuildExecuteServiceTaskCommand job is to build an XML document according to the PBS XML specification (see the Pivotal Composite API Reference). This document will be sent to the PBS XML interface.

private const string PivotalNamespace = "urn:schemas-pivotal-com/LifecycleServer60";

private XElement BuildExecuteServiceTaskCommand(string serverRuleName, string methodName, params object[] parameters)
{
    XElement commandXml = new XElement(PivotalNamespace + "executeAppServerRule",
        new XElement(PivotalNamespace + "appServerRuleName", serverRuleName),
        new XElement(PivotalNamespace + "appServerRuleMethod", methodName));

    XElement commandXmlDocument = new XElement(PivotalNamespace + "command",
        new XElement(PivotalNamespace + "systemName", SystemServer.SystemInformation.SystemName),
        new XElement(PivotalNamespace + "loginType", "Client"));

    commandXmlDocument.Add(commandXml);

    if (parameters != null)
    {
        XElement commandParametersXml = new XElement(PivotalNamespace + "commandParameters");
        commandXml.Add(commandParametersXml);

        for (int i = 0; i < 6; i++) // the first six parameters must be empty
            commandParametersXml.Add(new XElement(PivotalNamespace + "emptyParameter"));

        foreach (object parameter in parameters)
        {
            string type, value;
            GetParameterData(parameter, out type, out value);
            commandParametersXml.Add(new XElement(PivotalNamespace + type, value));
        }
    }

    return commandXmlDocument;
}

For our example, the resulting XML document will be something like this:

<command xmlns="urn:schemas-pivotal-com/LifecycleServer60">
    <systemName>CRM</systemName>
    <loginType>Client</loginType>
    <executeAppServerRule>
        <appServerRuleName>Async Service</appServerRuleName>
        <appServerRuleMethod>ExecuteApp</appServerRuleMethod>
        <commandParameters>
            <emptyParameter/>
            <emptyParameter/>
            <emptyParameter/>
            <emptyParameter/>
            <emptyParameter/>
            <emptyParameter/>            
            <stringParameter>Ticket Service</stringParameter>
            <stringParameter>LongRunningOperation</stringParameter>
            <binaryParameter>0000000000000A81</binaryParameter>
        </commandParameters>
    </executeAppServerRule>
    <collectStatistics/>
</command>

This XML will be sent using a .Net HttpRequest object in the SendCommandAsync method. There is one method that requires attention in the above code, the GetParameterData method. This method converts a parameter to the Pivotal equivalent using the following strings:

//binaryParameter
//booleanParameter
//stringParameter
//stringParameter
//floatParameter
//dateParameter
//floatParameter
//binaryParameter
//binaryParameter
//integerParameter
//binaryParameter
//stringParameter
//timeInstantParameter
//timeInstantParameter

Since this is just a matter of querying the parameter type and then decide which string of the above to use, I will leave this out in sake of space, since the implementation is more related to .Net than to Pivotal and is not difficult to do. Let’s us see how the XML document is sent asynchronously to the PBS.

In order to do an async operation we will use the BeginInvoke method defined by .Net delegates. Our delegate needs the XML document to send, and the URI to send to:

private delegate void SendAsyncDelegate(XElement xmlDocument, Uri url);
private const string PivotalUrl = "http://localhost/ePower/XMLServices.asp";

The PBS endpoint for XML documents is XMLServices.asp, located in the root of the ePower virtual directory (this endpoint is old, but still works and is used by many Pivotal services such as the EMS, the scheduled script, ePartner/eService, etc.).

And this is how we send the document:

private void SendCommandAsync(XElement xmlDocument)
{
    SendAsyncDelegate sendAsyc = new SendAsyncDelegate(SendXml2UrlAsyncDelegate);
    IAsyncResult result = sendAsyc.BeginInvoke(xmlDocument, new Uri(PivotalUrl), null, null);
}

protected void SendXml2UrlAsyncDelegate(XElement xmlDocument, Uri url)
{
    try
    {
        HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(url);
        httpRequest.Method = "POST";
        httpRequest.ContentType = "text/xml";
        httpRequest.Credentials = CredentialCache.DefaultCredentials;

        StreamWriter writer = new StreamWriter(httpRequest.GetRequestStream());
        writer.Write(xmlDocument.ToString());
        writer.Flush();
        writer.Close();

        HttpWebResponse httpResponse = (HttpWebResponse)httpRequest.GetResponse();
        XmlTextReader reader = new XmlTextReader(httpResponse.GetResponseStream());
        XElement xmlResponse = XElement.Load(reader);

        reader.Close();
        httpResponse.Close();
    }
    catch (WebException e)
    {
        // handle error
    }
}

There are some interesting things here: notice how we create the HTTP request using the default network credentials, which will use NTLM credentials to call the endpoint. Also notice that we don’t care about the response (it’s an async method). Line 4 contains the most important part of our implementation: the asynchronous call.

This is all we need to improve the user experience when executing a long running operation: submit an async call to the server task method and return control to the user as soon as possible. Of courser there are some things that need to be considered before we can actually put this into a production system. Here is a list of things that need to be done:

  • Error handling: in the code above you’ve noticed that I’ve not done any error handling.
  • Security: the PBS endpoint might be configured in HTTPS. Also the default credentials might not be what we want. In this case we could do user impersonation to do the actual call
  • Logging: the async service doesn’t care about the result of the operation, but the user might. In this case we would need some kind of status report on the async tasks.
  • Form task methods: the example above works for service task, but sometimes we want to call methods in a form task.

All the above considerations are not difficult to do. Personally I prefer to use a solution that gives me all this and more: I personally use the Pivotal Development Tools created by Grupo Lanka, which include an async service with all that’s required for a good implementation of async tasks.

For now on, there is no excuse to leave the user wondering what happened with their application, you now have two tools to improve the user experience: progress bars and asynchronous calls. I hope you implement them!

0 Comments

I recently had to resolve a performance problem for one of our Pivotal systems and I thought I should share the findings. Pivotal has what are called server and client tasks which, as their name suggest, constitute logic that runs on the client and server side, respectively. The platform allows to pass objects between the server and client layers of the applications, and also to pass data between different layers/tasks on the server side. Internally this is accomplished using serialization. The platform uses this to pass data (using ADO.Net DataSet, DataTable and DataRow) from the server to the client, and from server to server. It turns out that passing a DataRow from server to client could affect systems performance under certain conditions.

The short version is the following: when passing a DataRow from a server task to another server task the platform is actually serializing the whole DataTable to which the data row belongs. The bigger the DataTable the longer it takes to serialize and reach the other task. Following is a more detailed explanation of this particular case.

Scenario

Let’s assume that we have a task that needs to work with a several data records. The task is designed so the work is split in two subtasks: one subtask reads all the required records from the database, and another subtask takes care of processing a specific record. There are many reasons why this is a good design practice: modularity, separation of concerns, transaction handling, etc. As an example, lets assume that we need to design an archiving process that is executed monthly. Every month there could be thousands of records to archive. If we do the archiving in a single task then we could have transaction issues (usually the transaction timeout is set to 60 seconds, and if the archiving takes longer than this then the transaction will be rolled back). To avoid transaction issues we create one task that selects all records that require archiving in a non-transactional context (all we are doing is a read) and then, for each record (or a batch of records if we want more performance) we call another task, executing under a transactional context, that takes care of the archiving.

Processing each record individually might not be the best approach here. Processing records in batch will be better. But for the sake of simplicity, and to illustrate the actual problem, I will explain the scenario using individual record processing. The concepts also apply to the case where batch record processing is used instead.

The Implementation

We’ve decided to implement our process using the design mentioned above, two separate tasks, one for selecting records and another to process such records:

  • The first task creates a DataTable (using the platform API to retrieve data from the database) containing all the records that need to be processed. It then loops for each of the data rows in the table, passing each row (a DataRow object) to the other task that takes care of processing the row.
  • The second task receives a DataRow as input, creates the transaction, and processes the record.

Back to our example, the archiving process does a query on the database retrieving all the records for the previous month (it could be thousands) and puts them in a DataTable, and then for each DataRow calls another task that actually does the archiving.

The Performance

We could think that our process is well designed: we are doing just one read on the database (the first task) and then we are processing each record individually (the second task). We could assume that the time to process an individual record is a constant, and what changes is the number of records to process. In other words, if each record is processed in a time t, then processing n records will take t*n time.

It turns out that, under this scenario, the time to process each record will be proportional to the number of records to process. The time to process each individual record is no longer a constant t, but a function on the number of records to process. We can express the total time as f(n)*n.

Obviously, f(n)*n is much bigger than t*n as n increases (our case). So why is this happening?

The Reality

When objects are passed between layers/tasks (in our case, passing a DataRow between the first task and the second task) these are serialized. In other words, each task will be executing on its own thread and in the case of this platform, if we want to pass parameters between these threads we need to serialize them (either using XML or binary serialization).

The problem is that in order to pass a DataRow as a parameter we have to serialize the DataRow. This might not be obvious but the serialization of the DataRow not only serializes the individual record, but it also serializes the whole DataTable to which the row belongs. So for example, if the first task creates a DataTable of 1000 records, when we serialize each record and pass the DataRow to the second task, we are actually serializing the whole DataTable and passing all the 1000 records to the second task (and we would this 1000 times).

This explains the formula stated before. If I have to process 1000 records it’s actually serializing the whole table 1000 times. The more records has the table the longer it will take to serialize it, and the longer will take to process each individual record.

The Correct Implementation

So, what can we do to solve this problem and have a scenario where the processing time is t*n? The right implementation would have the first task that creates the DataTable to pass the record id (primary key) instead of the DataRow to the second task that processes the record. The first task still creates the DataTable, but this table will contain only one field: the record id. This id will be passed to the second task, which will have to make a database read to get all the information for the particular record, and then process it.

But with this scenario we are doing n+1 database reads. So, why is this more efficient than the previous scenario where we only made 1 read to the database? The answer lies in the fact that, for this platform in particular, the time to do a database read is much lower than the time to serialize a big DataTable. So, if each database read takes d time, our processing time will be d+(t+d)*n, which will be a lot lower than d+f(n)*n, for big n.