Getting started with Roslyn – Part 1

I have not blogged for quite some time.  Family, work, and life have all conspired to stop me finding the time to write here.  I am now going to start writing again, tentatively, with a view to making it a more permanent endeavour.  So, without further ado, I give you my first steps with Roslyn…

Much has already been written on Roslyn but I thought I would offer my own thoughts on getting started with this excellent tool being developed by Microsoft.

If you have yet to hear of the wonders of Roslyn then go check it out (http://msdn.microsoft.com/en-us/vstudio/roslyn.aspx go on, I will wait).  It is currently in CTP but is a workable ‘compiler as a service’ API – that is to say that it exposes the C# (and VB.NET if you are that way inclined) compiler as an API for developers to call and work with the syntax tree through.

Getting the CTP installed is relatively straight forward – simply download the setup file (https://www.microsoft.com/en-us/download/details.aspx?id=34685) and fire it up.  You will need Visual Studio 2012 and the Visual Studio 2012 SDK installed (you will be prompted for the latter if it is not already installed).

Once this is all installed you should have no problem starting Visual Studio and following along as we delve in and see just how exciting this tool really is.

We are going to build a simple console app which will run though some of the basics of using Roslyn and print out some interesting stuff to the screen.  We will end by using it to change a simple item within a class (an XML comment) and save this out as a new class.

In part 2 of this overview we will build a simple WPF app that will take a well-formed *.cs file and compile it on the fly to allow you to create instances of its types and call methods on them, but before that we need to cover the basics.

Step 0 – Creating the initial console app and sample class file

When you start visual studio after installing Roslyn you will not see any immediate difference but if you head up to File –> New –> Project you will see a set of Roslyn templates

Pro-Tip If you don’t see these then you can start Visual studio with the following command line switches and try again:

“C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\devenv.exe” /rootsuffix roslyn

image

Select this template folder and create a new Console Application from within it.  This will give you a new console app with the references that you need to get started with Roslyn.

Now we have the app ready we need to add a new class to the project.  This class is going to be the one that we manipulate with Roslyn and as such we don’t want it to compile with the rest of the project.

Add a new class, Person, and then right click on the file and choose properties, then set the Build Action to None and Copy to Output Directory to Copy Always.  This is the class that we are are going to be using.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace CSInRoslynPartOne
{
    public enum Sex
    {
        Male,
        Female
    }

    public class Person
    {
        public Person(string name, Sex sex, int age)
        {
            this.Name = name;
            this.Sex = sex;
            this.Age = age;
        }

        public Sex Sex { get; private set; }

        public string Name { get; private set; }

        public int Age { get; private set; }

        public bool IsAdult
        {
            get
            {
                return this.Age >= 18;
            }
        }

        /// <summary>
        /// Changes the persons name
        /// </summary>
        ///<param name="name">The name of the person</param>
        /// <returns>A new person representing the changed name</returns>
        public Person AlterName(string name)
        {
            return new Person(name, this.Sex, this.Age);
        }

        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append(this.Name);
            sb.Append(" is a ");
            sb.Append(this.Age);
            sb.Append(" year old ");
            sb.Append(this.IsAdult ? "Adult " : "Child ");
            sb.Append(this.Sex);
            return sb.ToString();
        }
    }
}

Step 1 – Parsing the file

Now we have the basics in place we need to start using the Roslyn API to read it.  The main representation of a source file when it comes to using Roslyn is the SyntaxTree.  It is the SyntaxTree that is the parsed display of C# code.

If the SyntaxTree represents the whole tree then the CompilationUnitSyntax represents the bits we can look at in the file.  In the case of our file there is only a single compilation unit which represents the entire file contents.

You create a SyntaxTree by using either a string or a file on disk, we are going to be using the Person.cs file that we created in the previous step.  From this SyntaxTree we will create a CompilationUnitSyntax from the root node in order to move on with our overview of the kind of things you can do with Roslyn.

SyntaxTree tree = SyntaxTree.ParseFile("Person.cs");
CompilationUnitSyntax root = tree.GetRoot();

Step 2 – So, What can I look at first

The CompilationUnitSyntax provides a large number of methods and properties that we can use to delve into the code but we are going to start simple.  The CompilationUnitSyntax has a Language property and this will tell us what language the file we have parsed is written in.  We will print this out in our console app and wrap it up nicely in a line that looks a little more English than simply printing out the Language on it’s own.

Console.WriteLine("the file is written in {0}", root.Language);

The CompilationUnitSyntax contains a collection property to see the descendants of the unit which we will get to in the next step but before we move on from looking at the members on this top level object we will look at the using directives for the code file.  We do this by looking at the Usings collection property – this is a SyntaxList<T> where T is of type UsingDirectiveSyntax, which has details of each using directive.  From here you can see the alias of the using if any have been set up and execute a number of methods of the to edit, view and remove the directive.  We are simply going to print the name of the using directives to the screen.

Console.WriteLine("The file's usings are:");
foreach (UsingDirectiveSyntax u in root.Usings)
{
    Console.WriteLine(u.Name);
}

Step 3 – Lets look at some file parts

Seeing the language and the using directives in the file might look nice but we need to start working with the different types of syntax members within the file, that are exposed by the Roslyn API, in order to find out any useful information about our code.

The CompilationUnitSyntax, along with other syntax types, exposes a Members property which allows us to see the contents of this syntax.  Our sample class has a single member at this level, the namespace, which in turn has two members of its own, namely the enumeration and the class.

Lets print out this information along with the type and name of the members.

The Members property is another SyntaxList<T> but T is now of type MemberDeclarationSyntax. SyntaxList<T> implements IEnumerable so we can use Linq to get the member that we require.  As we know that the root node is a namespace we can explicitly declare that we want to find a NamespaceDeclarationSyntax, if we didn’t know what type of member we wanted then we could have simply used the MemberDecalrationSyntax until we have found more information about the syntax node of interest.

NamespaceDeclarationSyntax ns = root.Members.Single(m => m is NamespaceDeclarationSyntax) as NamespaceDeclarationSyntax;
Console.WriteLine("the root namespace is {0} and contains the following types:", ns.Name);

Once we have the namespace we can loop through its Members collection and list them out.  Again, as we know the types of members we want we can use BaseTypeDeclartionSyntax to display the name and kind of the member as both ClassDeclarationSyntax (via TypeDeclarationSyntax, along with StructDeclarationSyntax and InterfaceDeclarationSyntax) and EnumDeclarationSyntax ultimately derive from this class.

foreach (BaseTypeDeclarationSyntax member in ns.Members.Cast<BaseTypeDeclarationSyntax>())
{
    Console.WriteLine("{0}, which is of type '{1}'", member.Identifier, member.Kind);
}

The BaseTypeDeclarationSyntax exposes the Identifier and Kind (which is inherited from SyntaxNode) of the syntax object which we can use to display the details of this member to the screen.

Step 4 – Dive into Enumerations

Now we know the different types in the root node we can start to look at them directly.  We know that we have an enumeration and a class so lets start with the enumeration. As we have already seen it is defined by the EnumDeclarationSyntax type which, along with the other syntax types we have seen, exposes its members through a property called Members. Iterating through the collection allows us to access the values of the enumeration which are exposed as EnumMemberDeclarationSyntax objects, which, again, inherits from SyntaxNode and so exposes the Identifier property which we can use to list the names of the enumeration values.

EnumDeclarationSyntax sexEnum = ns.Members.Single(m =>; m is EnumDeclarationSyntax) as EnumDeclarationSyntax;
Console.WriteLine("The enum member has {0} elements and they are:", sexEnum.Members.Count());
foreach (EnumMemberDeclarationSyntax syntax in sexEnum.Members
{
    Console.WriteLine(syntax.Identifier);
}

As we can see there is a pattern forming in the way that we access the different parts of the file.  If we want to access a member as a certain type then we must cast to that type before we use it.

Step 5 – Looking at methods

The last member in our file is a class which is exposed by the ClassDeclarationSyntax type.  We access this in the same way as the other types through the Members property.  The class, in turn, has its own members collection and we can use this to access the methods, properties, and other parts of the class. The method has a property called ParameterList which exposes its own Parameters property of type SeparatedSyntaxList<T> where T is of type ParameterSyntax, It is this collection of ParameterSyntax that exposes the individual parameters of the method and, as with other syntax lists, it can be iterated through and the Identifier can be obtained.  It also exposes the Type of the parameter.

ClassDeclarationSyntax personClass = ns.Members.Single(m => m is ClassDeclarationSyntax) as ClassDeclarationSyntax;
MethodDeclarationSyntax method = personClass.Members.OfType<MethodDeclarationSyntax>().First(mds => mds.Identifier.ValueText == "AlterName");
SeparatedSyntaxList<ParameterSyntax> paramList = method.ParameterList.Parameters;
Console.WriteLine("The AlterName method has {0} parameters, and they are:", paramList.Count());

foreach (ParameterSyntax arg in paramList)
{
    Console.WriteLine("{0}, which is a {1} parameter", arg.Identifier, arg.Type);
}

That covers the basic outline of a file but this just touches on what we can do with Roslyn.  The next couple of steps will cover looking at the non-code portions of a method, replacing a method’s XML header and then saving the changes back to a new file.

Step 6 – Investigating trivia

Trivia to Roslyn is the whitespace and non-code elements of the file.  We are going to use the trivia types to look at the whitespace and comment at the head of the AlterName method that we looked at in the previous step.  There are several different methods for fetching trivia including leading, trailing, and descendant members trivia but we are going to look at the leading trivia as that is where the comment we are interested in is located.

When you look at the method it appears that there is only one set of leading trivia for this method and that is the comment but there are actually four:

  • The end of the line for the previous method.
  • The empty line between the previous method and the comment.
  • The comment itself.
  • The leading whitespace on the line with the method signature.

To access this trivia we call the GetLeadingTrivia method on the MethodDecalrarionSyntax type which return a SyntaxTriviaList.  This is not the same generic type that the members property returns but it implements IEnumerable so, again, we can iterate through the list to look at the different trivia elements at the start of the method.  I have picked out the whitespace and newline elements so they display something on the screen rather than an empty space but other than that the pattern is, again, much the same as before.

SyntaxTriviaList trivia = method.GetLeadingTrivia();
Console.WriteLine("The AlterName method has the following trivia:");
foreach (SyntaxTrivia t in trivia)
{
    if (t.Kind == SyntaxKind.WhitespaceTrivia)
    {
        Console.WriteLine("''WHITESPACE''");
    }
    else if (t.Kind == SyntaxKind.EndOfLineTrivia)
    {
        Console.WriteLine("''END_OF_LINE''");
    }
    else
    {
        Console.WriteLine(t);
    }
}

Note that in the else block we simply write the SyntaxTrivia to the console, this is because SyntaxTrivia provides a handy override of ToString() which writes out the text when the element is a comment.

Step 7 – Removing a comment

Now we have found our comment we can edit it.  Roslyn allows you to edit, remove and replace any element in the SyntaxTree but we are using a comment as it is the most straight-forward thing to remove.

We know that the trivia list only contains one comment so we can use this knowledge to get a reference to it.  Once we have this SyntaxTrivia item we can call the ReplaceTrivia method on the MethodDecalrationSyntax passing in the trivia we want to replace (the comment) and a list of trivia to replace it with. In our case we are replacing it with an empty list (SyntaxTriviaList.Empty) as we want to remove the comment altogether.

SyntaxTrivia comment = trivia.First(t => t.Kind == SyntaxKind.DocumentationCommentTrivia);
MethodDeclarationSyntax newAlterMethod = method.ReplaceTrivia(comment, SyntaxTriviaList.Empty);

As we can see the ReplaceTrivia method actually returns a new MethodDecalrationSyntax rather than changing the current one, this is important, as we will see next.

Step 8 – Saving out

The final stop on out whistle stop tour is saving the change we have made.

We first need to create a new SyntaxTree that incorporates the changed method.  The SyntaxTree.Create() static method creates a SyntaxTree from a CompilationUnitSyntax.

The ReplaceNode method on the CompilationUnitSyntaxType (our original root object from above) operates in the same way as the ReplaceTrivia method in the previous step and takes the original and replacement elements and returns a new CompilationUnitSyntax.

Once we have the new tree we can use standard .NET file handling methods to write the string of the CompilationUnitSyntax out to a new file which, in our case, is Person2.cs.

SyntaxTree tree2 = SyntaxTree.Create(root.ReplaceNode(method, newAlterMethod));
using (StreamWriter file = File.CreateText("Person2.cs"))
{
    file.Write(tree2.ToString());
    file.Flush();
}

The code used in this small console app is available herenote that you will need to install the Roslyn bits as they are currently non-distributable components.

This has been a whirlwind tour of the top level features of the Roslyn API.  I may have meandered through them but it is such an exciting topic that once I started to put together the sample app I couldn’t stop putting more little bits in to show the power of this tool. As I have already mentioned, my next post will be an app to read in C# code and execute against the types and methods within.  It wont be quite as long a wait as it has been for this post but the family, work and life are still there and the sample for it is only half complete :).

Thanks for reading, I hope you enjoyed it as much as I did!

EF Code First and WPF with the Chinook database. Part 3 – Styles and DataTemplates 101

I have decided to split out the styling work into 2 posts as it would be a huge post to restyle even something so simple.  so this post is going to change the controls to be more style-conscious and introduce basic style and the next post will introduce some more advance concepts such as using adorners to display additional details.

Going back to the previous post we had a basic app as follows:

This is slightly ugly and needs a little work so the first thing I want to add is  a style that will tidy up the artist list.

I want the artist list to have a nice look and feel with rounded button type items and also contain a count of the number of albums – I want each item in the list to look something like this:

image

The first step to getting this design in place is adding the DataTemplate so that it is picked up by the item.  A DataTemplate is a template that gets applied to an object that has no default way of showing itself and manifests itself as its type name.

NOTE – this can also be be done by overriding Object.ToString() but this is a client side post so I don’t want to have to change model code to do something.

I have added a simple DataTemplate to the Application.Resources section in App.xaml as follows:

<DataTemplate DataType="{x:Type business:Artist}">
    <TextBlock x:Name="contentHolder">
        <TextBlock.Text>
            <MultiBinding StringFormat="{}{0} - {1} albums">
                <Binding Path="Name"/>
                <Binding Path="Albums.Count" />
            </MultiBinding>
        </TextBlock.Text>                
    </TextBlock>
    <DataTemplate.Triggers>
        <DataTrigger Binding="{Binding Albums.Count}" Value="1">
            <DataTrigger.Setters>
                <Setter Property="TextBlock.Text" TargetName="contentHolder">
                    <Setter.Value>
                        <MultiBinding StringFormat="{}{0} - {1} album">
                            <Binding Path="Name"/>
                            <Binding Path="Albums.Count" />
                        </MultiBinding>
                    </Setter.Value>
                </Setter>
            </DataTrigger.Setters>
        </DataTrigger>
    </DataTemplate.Triggers>
</DataTemplate>

There are several things going on here:

  1. the first line declares the type that this template is associated with – you have to add the namespace to this file first in order to make this work:
    xmlns:business="clr-namespace:MusicApp.Model;assembly=MusicApp.Model"
    
  2. The MultiBinding has an associated StringFormat – this is the same as a normal format string except for the “{}” after the equals sign – this simply escapes the format string.
  3. The binding to Albums.Count – yes you can bind to “built-in” properties as well.
  4. The DataTrigger is a simple way of saying that if we have only one album then the trailing text shouldn’t have an ‘s’ on the end.

It is possible to do the whole string in a converter but I like the declarative way as you can see everything going on in one place.  For those that like using converters you would bind the TextBlock’s Text property to the whole Artist ({Binding}) and then use a converter like the following:

public class ArtistStringConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        string retVal = string.Empty;
        var artist = value as Artist;
        if (artist != null)
        {
            retVal += string.Format("{0} - {1} {2}", artist.Name, artist.Albums.Count, artist.Albums.Count == 1 ? "artist" : "artists");
        }

        return retVal;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

this is then used from the xaml as follows:

<local:ArtistStringConverter x:Key="artistConverter"/>
<DataTemplate DataType="{x:Type business:Artist}">
    <TextBlock x:Name="contentHolder" Text="{Binding Converter={StaticResource artistConverter}}" />
</DataTemplate>

Once this is added (either option) you need to remove the DisplayMemberPath property from the ArtistList.xaml view so that the template is used instead.

I now have a list of Artists that show the name and the total albums they have so I can work on the actual style to make the list items look like the above image.

I want all three lists to look the same so I am adding a style with no key to the app.xaml file.  If you want specific styles for your controls then you can add ‘x:Key=”YourKeyName”’ and reference it using ‘{StaticResource YourKeyName}’ (in this instance the reference would be in the ItemContainerStyle property of the ListBox).

<Style TargetType="ListBoxItem">
    <Style.Setters>
        <Setter Property="Margin" Value="5,2" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="ListBoxItem">
                    <Grid>
                        <Rectangle Opacity="0.5" Height="30" StrokeThickness="1" x:Name="backBox"
                                        Stroke="Silver" RadiusX="5" RadiusY="5" Fill="Azure"/>
                        <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
                    </Grid>
                    <ControlTemplate.Triggers>
                        <Trigger Property="Selector.IsSelected" Value="True">
                            <Setter TargetName="backBox" Property="Fill" Value="Silver"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style.Setters>
</Style>

Again I have a couple of things going on inside this style:

  1. It targets ListBoxItem as this is what we want to style (not the ListBox itself).
  2. The margin separates the items nicely.
  3. The actual style part is contained inside a ControlTemplate which is then assigned  the Template property of the ListBoxItem.
  4. The ContentPresenter will present whatever content it is given, in this case it is presenting the passed in DataTemplate.
  5. The trigger here indicates that when the ListBoxItem is selected we want to change the fill colour of the rectangle to indicate we have selected an item.

To finish I have added a new DataTemplate for the albums – this looks the same with the type and property names changed to display the correct things and I have also rearranged the view as follows:

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="0.5*" />
        <ColumnDefinition Width="0.5*" />
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="0.5*"/>
        <RowDefinition Height="0.5*"/>
    </Grid.RowDefinitions>

    <ListBox ItemsSource="{Binding Path=Artists}" Margin="5" 
                Grid.Column="0" Grid.Row="0"
                Grid.RowSpan="2"
                SelectedItem="{Binding SelectedArtist}" />
        
    <ListBox ItemsSource="{Binding Path=SelectedArtist.Albums}" Margin="5" 
                Grid.Column="1" Grid.Row="0" 
                SelectedItem="{Binding SelectedAlbum}" />
        
    <ListBox ItemsSource="{Binding Path=SelectedAlbum.Tracks}" Margin="5" 
                DisplayMemberPath="Name" 
                Grid.Column="1" Grid.Row="1" />
</Grid>

This now gives me the following view which I am sure you will agree looks a lot better and is easily achievable by simply using XAML – we could have done this in blend as well but for the simple changes we have made I prefer to edit the XAML directly.

image

In the next post I will be adding some adorner goodness to the screen for displaying album and track details (which also covers changes to the model).

EF Code First and WPF with the Chinook database. Part 2 – The client

Now we have the data fetching work sorted out we can turn our attentions to the front-end.

I am going to make a very simple view in this post listing the artists and associated albums with their tracks.  It is going to look like this:

image

Now, this is very basic but it serves its purpose to show the tools we are going to be using – a later post will use the power of WPF to style and transform the screen into something more palatable.

The first thing to do is add a WPF project(I have named mine MusicApp.WPF.Client).  If you rename the the MainWindow.xaml file then don’t forget to change the startup uri in app.xaml

<Application x:Class="MusicApp.WPF.Client.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="Main.xaml">

In terms of the structure for the project I have separate folders for views, view models and common files.

The View

Once the basic structure is in place we can add our view to the Views folder.  The view in this case is a user control that we will add to the main window.

The view itself is very simplistic – 1 grid containing 3 ListBoxes and is created as follows

<UserControl x:Class="MusicApp.WPF.Client.Views.ArtistList"
              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
              Height="Auto" Width="Auto">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="0.5*" />
            <ColumnDefinition Width="0.5*" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="0.7*"/>
            <RowDefinition Height="0.3*"/>
        </Grid.RowDefinitions>
        <ListBox ItemsSource="{Binding Path=Artists}" Margin="5" 
                 DisplayMemberPath="Name" Grid.Column="0" 
                 Grid.ColumnSpan="2" Grid.Row="0" 
                 SelectedItem="{Binding SelectedArtist}" />
        
        <ListBox ItemsSource="{Binding Path=SelectedArtist.Albums}" Margin="5" 
                 DisplayMemberPath="Title" Grid.Column="0" Grid.Row="1" 
                 SelectedItem="{Binding SelectedAlbum}" />
        
        <ListBox ItemsSource="{Binding Path=SelectedAlbum.Tracks}" Margin="5" 
                 DisplayMemberPath="Name" Grid.Column="1" Grid.Row="1" />
    </Grid>
</UserControl>

This is a view with a 2 x 2 grid with columns of equal width (1/2 of the grid each) and one row at 70% width and one at 30%.  Inside the grid there is a ListBox that takes up the whole top row (ColumnSpan=2) and one ListBox in each of the columns in the lower row.

I have included all of the bindings so that I know what is required on the view model when I write it.  I will need a collection property called ‘Artists’ and 2 properties for the selected artist and selected album.

The DisplayMemberPath details which property of the object will be displayed as text in the ListBoxItem.

Once the control has been written then we can add it to the main window xaml.  There are 2 things to do to add a usercontrol to another xaml file

  1. add the correct namespace.
  2. add the control

Adding the namespace requires that we add an xmlns to the top of the main window file

xmlns:views="clr-namespace:MusicApp.WPF.Client.Views"

Once we have this then we can simply add the control as a new object on the window

<views:ArtistList/>

which gives us a Main window with the following xaml

<Window x:Class="MusicApp.WPF.Client.Main"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:views="clr-namespace:MusicApp.WPF.Client.Views"
        Title="Main" Height="475" Width="425">
    <Grid>
        <views:ArtistList/>
    </Grid>
</Window>

The ViewModel

Now the view is done I can create a ViewModel to support it.  The ViewModel will need to implement INotifyPropertyChanged and I have the following snippet method that will fire the event implemented by it

private void Notify(string propertyName)
{
    if (PropertyChanged != null)
    {
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

Unity

I want to be able to use a different data provider here if I want to so I am going to introduce the Unity IoC container to the application at this point.  Unity can be installed into the current project directly from NuGet (install-package unity) or you can download directly. It needs a little configuration before we can use it.

I am going to use it to resolve a reference to the IDataProvider interface we created previously so I add a new app.config file to the client project and add the following configuration

<configuration>
    <configSections>
        <section name="unity"
                             type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration" />
    </configSections>
    <unity>
        <containers>
            <container>
                <type type="MusicApp.Model.IDataProvider, MusicApp.Model" mapTo="MusicApp.Model.EFCodeFirstDataProvider, MusicApp.Model" />
            </container>
        </containers>
    </unity>
</configuration>

This is simply adding a mapping between IDataProvider and EFCodeFirstDataProvider which allows me to resolve the former to the latter.

We need a way of referencing this container in our application so I use a factory class with a static member to hold the actual UnityContainer

class ContainerFactory
{
    private static UnityContainer container;

    public ContainerFactory()
    {
        if (container == null)
        {
            container = new UnityContainer();
            UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
            section.Containers.Default.Configure(container);
        }
    }

    public UnityContainer Container
    {
        get
        {
            return container;
        }
    }
}

I can then have a reference to an IDataProvider in the ViewModel and resolve it from the constructor as follows

ContainerFactory factory = new ContainerFactory();
provider = factory.Container.Resolve<IDataProvider>();

The whole ViewModel including properties now looks like this.

public class ArtistListViewModel : INotifyPropertyChanged
{
    private IDataProvider provider;
    private ObservableCollection<Artist> artists;
    private Artist selectedArtist;
    private Album selectedAlbum;

    public ArtistListViewModel()
    {
        ContainerFactory factory = new ContainerFactory();
        provider = factory.Container.Resolve<IDataProvider>();
        GetArtists();
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public ObservableCollection<Artist> Artists
    {
        get
        {
            return artists;
        }
        private set
        {
            artists = value;
            Notify("Artists");
        }
    }

    public Artist SelectedArtist
    {
        get
        {
            return selectedArtist;
        }
        set
        {
            selectedArtist = value;
            Notify("SelectedArtist");
        }
    }

    public Album SelectedAlbum
    {
        get
        {
            return selectedAlbum;
        }
        set
        {
            selectedAlbum = value;
            Notify("SelectedAlbum");
        }
    }

    private void GetArtists()
    {
        Artists = new ObservableCollection<Artist>(provider.GetArtists());
    }

    private void Notify(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

Wire it up

Now we have the ViewModel and view in place we need to wire them together this is just a case of setting the views DataContext from its constructor

public ArtistList()
{
    InitializeComponent();
    this.DataContext = new ArtistListViewModel();
}

Wrapping up

Now we have these wired we simply need to add the ConnectionStrings to the config file (that we added the unity config to earlier), change the startup project to the new WPF app and run it.  This will now display the window shown at the start and I can change the artist to update the albums/tracks at the bottom.

Next time – making the view look good.

EF Code First and WPF with the Chinook database. Part 1c – the unit tests

In the final part of the server side code (we have already written a Code First provider and data provider) I am going to implement some unit tests for the two methods I currently have on the data provider.

My unit tests will need to have no access to the database as that would break the encapsulation of the test so we need to mock out the raw data access layer while still providing the functionality that we would expect from the Entity Framework context.

To do this we need to make several changes to the current project to allow us to inject a mocked up context into the data provider.

The first thing we need to do is to abstract the context used by the data provider out into an interface, being as we currently have a small set of classes then the interface is simply:

public interface IContext
{
    IDbSet<Artist> Artist { get; set; }

    IDbSet<Album> Album { get; set; }

    IDbSet<Track> Track { get; set; }
}

Notice the IDbSet<T> – this is to allow us to mock up the DbSet’s using the same interface.

Next up we need to edit our Chinook class so that it uses this new interface (note, again, the IDbSet<T>’s)

public class Chinook : DbContext, IContext
{
    protected override void OnModelCreating(System.Data.Entity.ModelConfiguration.ModelBuilder modelBuilder)
    {
        modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
    }

    public IDbSet<Artist> Artist { get; set; }

    public IDbSet<Album> Album { get; set; }

    public IDbSet<Track> Track { get; set; }
}

Now we have this we can use the interface in the data provider and set it to a Chinook instance by default (for the time being).

private IContext db = new Chinook();

Right we now have a good basis to start working on the test so add a new test project to the solution and create a new class called MockDbSet.  This allows us to simulate the actions of a real DbSet in the database for a given set of objects.  Huge thanks to Julie Lerman for showing the starting point for this work with her series on EF4 repositories (A great read!).

The MockDbSet implements the IDbSet<T> Interface supplied by the Entity Framework and allows us to replicate the functionality as follows (note I have not implemented the create or find methods as I don’t need them right now.)

public class MockDbSet<T> : IDbSet<T> where T : class
{
    readonly IList<T> _container = new List<T>();

    public T Add(T entity)
    {
        _container.Add(entity);
        return entity;
    }

    public T Attach(T entity)
    {
        _container.Add(entity);
        return entity;
    }

    public TDerivedEntity Create<TDerivedEntity>() where TDerivedEntity : class, T
    {
        throw new NotImplementedException();
    }

    public T Create()
    {
        throw new NotImplementedException();
    }

    public T Find(params object[] keyValues)
    {
        throw new NotImplementedException();
    }

    public System.Collections.ObjectModel.ObservableCollection<T> Local
    {
        get
        {
            return new ObservableCollection<T>(_container);
        }
    }

    public T Remove(T entity)
    {
        _container.Remove(entity);
        return entity;
    }

    public IEnumerator<T> GetEnumerator()
    {
        return _container.GetEnumerator();
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return _container.GetEnumerator();
    }

    public Type ElementType
    {
        get
        {
            return typeof(T);
        }
    }

    public System.Linq.Expressions.Expression Expression
    {
        get
        {
            return _container.AsQueryable<T>().Expression;
        }
    }

    public IQueryProvider Provider
    {
        get
        {
            return _container.AsQueryable<T>().Provider;
        }
    }
 }

This is a simple implementation that stores the set in a local List.

Now we have a mock set we can mock up the context which is something that implements IContext and allows us to access the DbSets we want to work with outside of a database environment.  I have added some methods to add test data into the sets as well.

class MockContext : IContext
{
    private IDbSet<Artist> artist;
    private IDbSet<Album> album;
    private IDbSet<Track> track;

    public IDbSet<Artist> Artist
    {
        get
        {
            this.CreateArtists();
            return this.artist;
        }

        set
        {
            throw new NotImplementedException();
        }
    }

    public IDbSet<Album> Album
    {
        get
        {
            this.CreateAlbums();
            return this.album;
        }
        
        set
        {
            throw new NotImplementedException();
        }
    }

    public IDbSet<Track> Track
    {
        get
        {
            this.CreateTracks();
            return this.track;
        }
        
        set
        {
            throw new NotImplementedException();
        }
    }

    private void CreateArtists()
    {
        if (artist == null)
        {
            artist = new MockDbSet<Artist>();
            artist.Add(new Artist { ArtistId = 1, Name = "Test Artist 1" });
            artist.Add(new Artist { ArtistId = 2, Name = "Test Artist 2" });
            artist.Add(new Artist { ArtistId = 3, Name = "Test Artist 3" });
        }
    }

    private void CreateAlbums()
    {
        if (album == null)
        {
            album = new MockDbSet<Album>();
            album.Add(new Album { AlbumId = 1, Title = "Test Album 1", ArtistId = 1 });
            album.Add(new Album { AlbumId = 2, Title = "Test Album 2", ArtistId = 2 });
            album.Add(new Album { AlbumId = 3, Title = "Test Album 3", ArtistId = 3 });
            album.Add(new Album { AlbumId = 4, Title = "Test Album 4", ArtistId = 3 });
        }
    }

    private void CreateTracks()
    {
        if (track == null)
        {
            track = new MockDbSet<Track>();
            track.Add(new Track { TrackId = 1, Name = "Test Track 1", AlbumId = 1 });
            track.Add(new Track { TrackId = 2, Name = "Test Track 2", AlbumId = 1 });
            track.Add(new Track { TrackId = 3, Name = "Test Track 3", AlbumId = 1 });
            track.Add(new Track { TrackId = 4, Name = "Test Track 4", AlbumId = 2 });
            track.Add(new Track { TrackId = 5, Name = "Test Track 5", AlbumId = 2 });
            track.Add(new Track { TrackId = 6, Name = "Test Track 6", AlbumId = 2 });
            track.Add(new Track { TrackId = 7, Name = "Test Track 7", AlbumId = 3 });
            track.Add(new Track { TrackId = 8, Name = "Test Track 8", AlbumId = 3 });
            track.Add(new Track { TrackId = 9, Name = "Test Track 9", AlbumId = 4 });
            track.Add(new Track { TrackId = 10, Name = "Test Track 10", AlbumId = 4 });
        }
    }
}

Now we have a context and sets mocked up we can almost write our tests but at the moment we have no way of getting the new mock context into the data provider.  This is where we can use an often overlooked assembly attribute, InternalsVisibleTo, which allows the given project access to internal members of the a project.  So all we need to do is apply the following to the AssemblyInfo.cs class of the model project.

[assembly: InternalsVisibleTo("MusicApp.Model.Tests")]

and change the context member in the data provider (db) from private to internal and we can access it from the our test project.

I have two tests – one for each method in the data provider and have implemented them as follows:

public class EFCodeFirstDataProviderTest
{
    [TestMethod()]
    public void GetArtistsTest()
    {
        EFCodeFirstDataProvider target = new EFCodeFirstDataProvider() { db = new MockContext() };

        List<Artist> expected = new List<Artist>();
        expected.Add(new Artist { ArtistId = 1, Name = "Test Artist 1" });
        expected.Add(new Artist { ArtistId = 2, Name = "Test Artist 2" });
        expected.Add(new Artist { ArtistId = 3, Name = "Test Artist 3" });

        List<Artist> actual = target.GetArtists();
        CollectionAssert.AreEquivalent(expected, actual);
    }

    [TestMethod()]
    public void SearchArtistsTest()
    {
        EFCodeFirstDataProvider target = new EFCodeFirstDataProvider() { db = new MockContext() };

        string searchTerm = "Artist 1";
        List<Artist> expected = new List<Artist>();
        expected.Add(new Artist { ArtistId = 1, Name = "Test Artist 1" });

        List<Artist> actual = target.SearchArtists(searchTerm);

        CollectionAssert.AreEquivalent(expected, actual);
    }
}

As you can see they are simple tests to determine that the methods return the objects that I wanted.  As they stand these methods will fail as the CollectionAssert.AreEquivalent method checks for equality and we have no override for equality (or hash code) in our Artist class so we just need to add them in:

public override int GetHashCode()
{
    return ArtistId;
}

public override bool Equals(object obj)
{
    return ArtistId == (obj as Artist).ArtistId;
}

and the tests will now pass.

In the next post I will create a simple WPF front-end to display the information and then I will build the interface from that point on.

EF Code First and WPF with the Chinook database. Part 1b – the provider

I like to isolate my data access code to a single point so that my client does not have to worry about creating contexts or anything of the sort.  This makes it simpler to change the way the data is delivered to the client as it is abstracted away.

In thinking about what methods I would need for this I discovered that for the first phase I would only need two:

  • GetArtists() – Returns all artists.
  • SearchArtists(string searchTerm) – Searches for artists and returns any matches.

I don’t need any methods at the moment to fetch albums or tracks because I have virtual lazy loading properties set up to deal with them.  I will be adding more methods to this provider as the series grows (such as adding, deleting…etc).

Lets go ahead and test those lazy properties:

class Program
{
    static Chinook db = new Chinook();

    static void Main(string[] args)
    {
        // Using ToList() executes the command so the datareader is closed.
        var artists = db.Artist.ToList();
        foreach (var a in artists)
        {
            Console.WriteLine(a.Name);
            PrintAlbums(a.Albums);
        }

        Console.ReadLine();
    }

    static void PrintAlbums(ICollection<Album> albums)
    {
        foreach (var a in albums)
        {
            Console.WriteLine("\t" + a.Title);
            PrintTracks(a.Tracks);
        }
    }

    static void PrintTracks(ICollection<Track> tracks)
    {
        foreach (var t in tracks)
        {
            Console.WriteLine("\t\t" + t.Name);
        }
    }
}

image

Whoops – seems we have an invalid column name “ArtistArtistId”.

This is due to the way Code First decides on what the foreign key columns are called if we don’t explicitly include them – the default is “{TypeName}{TypeName}Id” which we obviously don’t have in the database.

We need to add the foreign key properties to our objects so EF picks up the correct names (this needs to be done for both Album and Track – note the new ArtistId and AlbumId respectively):

public class Album
{
    public int AlbumId { get; set; }

    public string Title { get; set; }

    public int ArtistId { get; set; }

    public virtual Artist Artist { get; set; }

    public virtual ICollection<Track> Tracks { get; set; }
}

public class Track
{
    public int TrackId { get; set; }

    public string Name { get; set; }

    public int AlbumId { get; set; }

    public virtual Album Album { get; set; }

    public string Composer { get; set; }
}

We can now run our demo and get a correct output:

image

We are now in a position to implement our simple data provider.

I am going to put the data provider behind an interface to allow for easy extension and dependency injection should we want to go that way.

public interface IDataProvider
{
    List<Artist> GetArtists();

    List<Artist> SearchArtists(string searchTerm);
}

This is then implemented as follows for the code first model:

public class EFCodeFirstDataProvider : IDataProvider
{
    private Chinook db = new Chinook();

    public List<Artist> GetArtists()
    {
        return this.db.Artist.ToList();
    }

    public List<Artist> SearchArtists(string searchTerm)
    {
        return this.db.Artist.Where(a => a.Name.Contains(searchTerm)).ToList();
    }
}

We have a private instance of the Chinook data context that controls all of the fetching of data.  When the Artist requests its albums then this context is used.  This is the same with the tracks.

The intention here is to allow the client to call simple methods to interact with the data and we are able to swap out for another provider if we so wish easily.

The only thing we now need to change is the little test app so that it uses the new data provider (we will hard code the type here but will be using dependency injection in our WPF app).

static IDataProvider dp = new EFCodeFirstDataProvider();

static void Main(string[] args)
{
    var artists = dp.GetArtists();
    foreach (var a in artists)
    {
        Console.WriteLine(a.Name);
        PrintAlbums(a.Albums);
    }

    Console.ReadLine();
}

And that’s all there is to it – we now have a separate data provider to work with our entity framework objects.

The next part of this series (1c) is going to involve writing unit tests for the data provider.  This is easier said than done and involves much mocking of the EF classes.

EF Code First and WPF with the Chinook database. Part 1 – the model

Introduction

I am going to start a series of posts building a simple app using the Chinook database as a back-end and putting a WPF client on the front-end.  I am going to keep it loose as I don’t want to commit to blog posts that I may not get chance to complete so I will keep every post self-contained covering 1 detail of the implementation.

The technologies and tools I plan on using for this series are as follows:

As you can see the idea is to use the latest technologies available to build a simple app to display the music details from the Chinook database.  As I am not committing to a large series I will say that my intentions for the series include:

  • Setting up the model using EF4 Code First (this post).
  • creating a basic screen listing the artists and associated albums.
  • Creating an album details adorner to show the tracks of individual albums.

Possible future posts will include:

  • Adding the ability for customers to place an order (creating invoices).
  • Adding employees to manage the customer invoices (this is a WPF app so the employee will be doing all of the work as this is not a customer facing app).
  • Adding the ability to create custom playlists that can reviewed.

Note that all of these items already exist in the Chinook database and I will be focusing on the data access and UI layers.

Building the model using EF Code First

The first thing we need to do is create a new solution for our app.  Being as we are creating the model first I am going to create a class library.

Once the solution and project are in place we need to get the Code First bits into the project.  I am going to use NuGet so you need to have this installed.

In the NuGet package manager window we can find the required package by firing the command:

Get-Package –remote –filter CodeFirst

This will give us the following output:

image

This shows us the package that we need to install is EFCodeFirst so we issue

Install-Package EFCodeFirst

this should add the EntityFramework reference to your project but it didn’t do that on my class library so I had to add the reference manually ({SolutionFolder}\packages\EFCodeFirst.0.8\lib\EntityFramework.dll).

Now we have the reference we can start to create our POCO objects.  I am going to create a model that initially uses the Artist, Album and Track tables as they are going to be used in the first part of this app – I will add more as I go along.

EF Code First allows us to create standard POCOs to represent our model so for my initial model I have:

public class Artist
{
    public int ArtistId { get; set; }
    public string Name { get; set; }
    public virtual ICollection<Album> Albums { get; set; }
}

public class Album
{
    public int AlbumId { get; set; }
    public string Title { get; set; }
    public virtual Artist Artist { get; set; }
    public virtual ICollection<Track> Tracks { get; set; }
}

public class Track
{
    public int TrackId { get; set; }
    public string Name { get; set; }
    public virtual Album Album { get; set; }
    public string Composer { get; set; }
}

Note the virtual association properties – this is to allow these properties to be lazy-loaded.

The next thing we need is the actual dbContext which is defined as follows:

using System.Data.Entity;
using System.Data.Entity.ModelConfiguration.Conventions.Edm.Db;
.
.
.
public class Chinook : DbContext
{
    protected override void OnModelCreating(System.Data.Entity.ModelConfiguration.ModelBuilder modelBuilder)
    {
        modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
    }

    public DbSet<Artist> Artist { get; set; }
    public DbSet<Album> Album { get; set; }
    public DbSet<Track> Track { get; set; }
}

This is a class that includes one property per table in the database and handles the mapping to our objects.  This is using default conventions with the exception of the one removed in the overridden OnModelCreating method.  This says that the database we have doesn’t have pluralised names as Code First expects and instead the names match the entities.

Next we need to add an app.config file to the project and add the ConnectionString for the database.  I use SQLServer so adjust accordingly.

<connectionStrings>
    <add name="Chinook" providerName="System.Data.SqlClient"
        connectionString="Data Source=.;Initial Catalog=chinook;Integrated Security=true" />
</connectionStrings>

Notice that the name of the connectionString must be the same as the class name when using the default conventions.

Testing that it works

OK, we have the model built now and can run a crude test to see if it works.  Add a console app to your solution and set it as the startup project.  Add references to the Model assembly and the Code First assembly and move the app.config to the new project. Now add the following code to the main method.

static void Main(string[] args)
{
    using (Chinook db = new Chinook())
    {
        foreach (var artist in db.Artist)
        {
            Console.WriteLine(artist.Name);
        }

        Console.ReadLine();
    }
}

This will loop through all of the artists and print their name to the screen.

That’s all there is to creating a simple model with Entity Framework Code First CTP5.  In the next instalment I plan on writing a simple data provider class that will abstract the actual DbContext calls away from the user and allow the user to simply call methods like provider.GetArtists().

WPF/Silverlight ListBox and equality checking

In WPF we bind collections of objects to ListBoxes and the like all the time – its part and parcel of the WPF development cycle but this is something that stung me recently.

I bound a collection of objects to the ItemsSource property as usual but the selection was odd.  Every time I selected an item the ListBox assumed that the first item was also selected and subsequent selections marked all previous selections as selected, also the SelectedIndex was always 0.  It took some time but I tracked it down to the way that ListBoxes use equality.

Something I didn’t know was that the objects that I was using had an overridden Equals method which was simply comparing a single string on the objects to determine if they were equal.  Because I only wanted a small subset of of the object I only populated those properties I needed along with the id of the object and not the string being compared.

The below shows an example of what I was doing.

public class MainViewModel : INotifyPropertyChanged
{
    private ObservableCollection foos;

    public ObservableCollection Foos
    {
        get
        {
            return foos;
        }
        set
        {
            foos = value;
        }
    }

    public MainViewModel()
    {
        this.Foos = new ObservableCollection();
        this.Foos.Add(new Foo { id = 1, Display = "First" });
        this.Foos.Add(new Foo { id = 2, Display = "Second" });
        this.Foos.Add(new Foo { id = 3, Display = "Third" });
        this.Foos.Add(new Foo { id = 4, Display = "Fourth" });
        this.Foos.Add(new Foo { id = 5, Display = "Fifth" });
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

public class Foo
{
    public int id { get; set; }

    public string Display { get; set; }

    public string FooCode { get; set; }

    public override bool Equals(object obj)
    {
        return FooCode == (obj as Foo).FooCode;
    }
}

As we can see I have no interest in the FooCode property and as a result don’t use it in my ViewModel.

The problem with this is that now the ListBox has no way of knowing if the objects are different as we have an overriding Equals method that implements value equality rather than reference equality and because the value is always going to be the same (as I don’t set it) then the ListBox will assume that every object is essentially the same object.

A simple change to include the FooCode property in each object in the collection solves this problem and gives us different values for equality testing.

A sample project with 2 lists displaying this different behaviour can be found here.

Follow

Get every new post delivered to your Inbox.