Using Server Side Timers and SignalR in ASP.NET MVC Applications

I thought it would be fun to create an “Internet uptime” page that you can see live here on Azure Websites. It shows how long the Internet (since ARPANET) has been around for.

image

Creating a Class that can be Managed by ASP.NET

The HostingEnvironment.RegisterObject method can be used to register an instance of an object that has its lifetime managed by the hosting environment.

To register an object it must implement the IRegisteredObject interface.

This interface defines a Stop method which gets called when ASP.NET needs to shutdown the app domain.

So, in the application start we can create an instance of our class and register it:

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();
    RouteConfig.RegisterRoutes(RouteTable.Routes);

    HostingEnvironment.RegisterObject(new BackgroundUptimeServerTimer());
}

Creating a SignalR Hub to Send Messages from the Server to Client

Next we create a SignalR hub and the HTML.

So the hub class is called UptimeHub:

public class UptimeHub : Hub
{
}

We can get the server to call a client JavaScript method called “internetUpTime” in the HTML page and have this client code display the what’s been sent from the server timer.

The following shows the complete HTML for the page. Notice the “hub.client.internetUpTime = function (time) …” this function will get executed every time our server timer event fires.

More...

SHARE:

Say Goodbye to Boring INotifyPropertyChanged Implementation in Universal Windows Apps with Fody

We need to implement INotifyPropertyChanged to allow bindings to be updated. For example in a simple viewmodel to add 2 numbers:

namespace UniFodyDemo
{    
    internal class CalculatorViewModel : INotifyPropertyChanged
    {
        private ICommand _addCommand;
        private string _firstNumber;
        private string _secondNumber;

        public CalculatorViewModel()
        {
            FirstNumber = "5";
            SecondNumber = "10";
            Result = "";

            AddCommand = new RelayCommand(Add);
        }


        // Use strings to simplify demo code (so no val converter)
        public string FirstNumber
        {
            get { return _firstNumber; }
            set
            {
                _firstNumber = value;
                OnPropertyChanged();
            }
        }

        public string SecondNumber
        {
            get { return _secondNumber; }
            set
            {
                _secondNumber = value;
                OnPropertyChanged();
            }
        }

        public string Result { get; set; }

        public ICommand AddCommand
        {
            get { return _addCommand; }
            private set
            {
                _addCommand = value;
                OnPropertyChanged();
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void Add(object obj)
        {
            var a = int.Parse(FirstNumber);
            var b = int.Parse(SecondNumber);

            Result = (a + b).ToString();
        }

        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            var handler = PropertyChanged;
            if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

There’s more code here than we’d need if we didn’t have to implement INotifyPropertyChanged. Really the important things are the 3 properties that we bind to and the add command / method.

The XAML in both the Windows Store app and Windows Phone app looks like:

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <StackPanel Width="200">
        <TextBlock Text="{Binding FirstNumber, Mode=TwoWay}"></TextBlock>
        <TextBlock Text="{Binding SecondNumber, Mode=TwoWay}"></TextBlock>
        <Button Command="{Binding AddCommand}">Add</Button>
        <TextBlock Text="{Binding Result, Mode=TwoWay}"></TextBlock>
    </StackPanel>
</Grid>

Without implementing INotifyProperty changed, clicking the Add button won’t be of much use, we wont see the result.

The solution looks like the following, the shared project contains the viewmodel.

image

It would be great not have to write this same INotifyProperty stuff for everything we want to bind to/from. Using a NuGet package called PropertyChanged.Fody we can achieve this.

First this package needs to be installed into both the Windows Store and Windows Phone app projects. This is because the shared code in the viewmodel isn’t compiled in that shared project, rather the source code is compiled individually in both the Store/Phone projects.

Now the viewmodel can be simplified:

namespace UniFodyDemo
{
    [ImplementPropertyChanged]
    class CalculatorViewModel
    {
        public CalculatorViewModel()
        {
            FirstNumber = "5";
            SecondNumber = "10";
            Result = "";

            AddCommand = new RelayCommand(Add);
        }

        private void Add(object obj)
        {
            var a = int.Parse(FirstNumber);
            var b = int.Parse(SecondNumber);

            Result = (a + b).ToString();
        }
        

        // Use strings to simplify demo code (so no val converter)
        public string FirstNumber { get; set; }
        public string SecondNumber { get; set; }
        public string Result { get; set; }

        public ICommand AddCommand { get; private set; }
    }
}

Notice the [ImplementPropertyChanged] attribute which means INotifyPropertyChanged will be automatically implemented for us. Notice that it’s much easier to see what’s essential in the viewmodel without all the noise of INotifyPropertyChanged.

If we decompile the Windows store app we can see the implementation:

namespace UniFodyDemo
{
    internal class CalculatorViewModel : INotifyPropertyChanged
    {
        public ICommand AddCommand
        {
            get
            {
                return this.u003cAddCommandu003ek__BackingField;
            }
            private set
            {
                if (this.u003cAddCommandu003ek__BackingField == value)
                {
                    return;
                }
                this.u003cAddCommandu003ek__BackingField = value;
                this.OnPropertyChanged("AddCommand");
            }
        }

        public string FirstNumber
        {
            get
            {
                return this.u003cFirstNumberu003ek__BackingField;
            }
            set
            {
                if (String.Equals(this.u003cFirstNumberu003ek__BackingField, value, 4))
                {
                    return;
                }
                this.u003cFirstNumberu003ek__BackingField = value;
                this.OnPropertyChanged("FirstNumber");
            }
        }

        public string Result
        {
            get
            {
                return this.u003cResultu003ek__BackingField;
            }
            set
            {
                if (String.Equals(this.u003cResultu003ek__BackingField, value, 4))
                {
                    return;
                }
                this.u003cResultu003ek__BackingField = value;
                this.OnPropertyChanged("Result");
            }
        }

        public string SecondNumber
        {
            get
            {
                return this.u003cSecondNumberu003ek__BackingField;
            }
            set
            {
                if (String.Equals(this.u003cSecondNumberu003ek__BackingField, value, 4))
                {
                    return;
                }
                this.u003cSecondNumberu003ek__BackingField = value;
                this.OnPropertyChanged("SecondNumber");
            }
        }

        public CalculatorViewModel()
        {
            this.FirstNumber = "5";
            this.SecondNumber = "10";
            this.Result = "";
            this.AddCommand = new RelayCommand(new Action<object>(this, CalculatorViewModel.Add));
        }

        private void Add(object obj)
        {
            int num = Int32.Parse(this.FirstNumber);
            int num1 = Int32.Parse(this.SecondNumber);
            this.Result = (num + num1).ToString();
        }

        public virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler propertyChangedEventHandler = this.PropertyChanged;
            if (propertyChangedEventHandler != null)
            {
                propertyChangedEventHandler(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }
}

So not only with Universal projects can we share code via the shared code project, adding Fody into the mix is even more awesome.

For a list of available addins or to contribute (or even create your own addin) check out the GitHub project site.

Also to learn more about Fody feel free to check out my Pluralsight course.

You can start watching with a Pluralsight free trial.

SHARE:

C# Tips eBook 50% Complete

I just published a new version of my C# Tips eBook that marks the half way point of the project.

C# Tips is available in PDF, EPUB, and MOBI.

The book is scheduled for completion by the end of the year and has 521 readers at present. It is currently free, you may also pay whatever you think it’s worth.

You can download it now from Leanpub.

An abridged copy of the current table of contents is shown below.

  • Merging IEnumerable Sequences with LINQ
  • Auto-Generating Sequences of Integer Values
  • Improving Struct Equality Performance
  • Creating Generic Methods in Non-Generic Classes
  • Converting Chars to Doubles
  • Non Short Circuiting Conditional Operators Using C# Keywords for Variable Names
  • Three Part Conditional Numeric Format Strings
  • Customizing the Appearance of Debug Information in Visual Studio
  • Partial Types
  • The Null Coalescing Operator
  • Creating and Using Bit Flag Enums
  • The Continue Statement
  • Preprocessor Directives
  • Automatically Stepping Through Code
  • Exceptions in Static Constructors
  • Safe Conversion To and From DateTime Strings
  • Parsing Strings into Numbers with NumberStyles
  • Useful LINQ Set Operations
  • The Decorator Pattern
  • The Factory Pattern
  • NUnit
  • xUnit.net

SHARE:

Write Less Repetitive Boilerplate Code with Fody

My newest Pluralsight course on Fody was just released.

Fody is a tool that frees us up from having to write repetitive boilerplate code. For example we can automate IDisposable implementation or automatically add Equals(), GetHashCode() and equality operators.

Fody is not one tool, but a collection of individual “addins” around the core Fody, with the core GitHub members: Simon Cropp, Rafał Jasica, and Cameron MacFarland.

Automatically Implementing Equality

As an example of what’s possible with Fody, we can auto-implement equality.

So first off we install the Equals Fody addin via NuGet:

PM> Install-Package Equals.Fody

Now we can add the [Equals] attribute to indicate that we want to auto-implement equality.

We can opt-out specific properties so they won’t be considered during equality by applying the [IgnoreDuringEquals] attribute.

We can also provide custom equality logic by creating a method and decorating it with the [CustomEqualsInternal] attribute. So for example if either altitude is –1 then consider altitudes equal.

The following code shows these attributes in action:

[Equals]
public class Location
{
    [IgnoreDuringEquals] 
    public int Altitude { get; set; }
    
    public int Lat { get; set; }
    public int Long { get; set; }

    [CustomEqualsInternal]
    private bool CustomEqualsLogic(Location other)
    {
        // this method is evaluated if the other auto-equal properties are equal

        if (this.Altitude == other.Altitude)
        {
            return true;
        }

        if (this.Altitude == -1 || other.Altitude == -1)
        {
            return true;
        }

        return false;
    } 
}

For a list of available addins or to contribute (or even create your own addin) check out the GitHub project site.

To learn more about how Fody works, how to use some of the available addins, and how to create your own check out my Pluralsight course.

You can start watching with a Pluralsight free trial.

SHARE:

Implementing Platform Specific Code in Universal Windows Apps with MVVMLight and Dependency Injection

In previous articles I’ve covered using MVVMLight in Universal Windows Apps and using C# partial classes and methods to implement different code on Windows Phone and Windows Store apps.

While partial classes/methods are a quick win to alter small amounts of code for each platform, overuse might become painful as the solution gets bigger. There are also limitations of partial methods such as they can only return void, they are implicitly private, cannot be virtual, etc.

If we’re using MVVMLight (or another framework or hand-rolled viewmodels) we can use dependency injection.

The viewmodel class is still shared between the two apps and doesn’t need to have partial methods which means we have more flexibility in the code we write.

As a dependency in the constructor, the viewmodel takes an instance of a class that implements an interface.

This interface-implementing class can then be two different classes, one in the phone project and one in the store project.

architecture diagram

So for example, in the shared project the following interface can be defined:

interface IGreetingService
{
    string GenerateGreeting();
}

Again in the shared project, the viewmodel is defined:

internal class MainViewModel : ViewModelBase
{
    private readonly IGreetingService _greetingService;
    private string _greeting;

    public MainViewModel(IGreetingService greetingService)
    {
        _greetingService = greetingService;

        SayHi = new RelayCommand(() => Greeting = _greetingService.GenerateGreeting());
    }

    public RelayCommand SayHi { get; set; }

    public string Greeting
    {
        get { return _greeting; }
        set { Set(() => Greeting, ref _greeting, value); }
    }
}

The key thing here is the constructor: it takes an IGreetingService.

When the SayHi command is executed, whichever instance of an IGreetingService was passed to the viewmodel, it’s GenerateGreeting() method will be called.

So in the store project the following class can be created:

public class WindowsStoreGreeter : IGreetingService
{
    public string GenerateGreeting()
    {
        return "Hello from Windows Store app!";
    }
}

And in the phone app:

public class WindowsPhoneGreeter : IGreetingService
{
    public string GenerateGreeting()
    {
        return "Hello from Windows Phone app!";
    }
}

It is in these specific implementations of the interface that the platform specific code is written.

So in the code-behind of the main window in the store app (for demonstration simplicity we’re not using a view model locator or DI library here):

public MainPage()
{
    this.InitializeComponent();

    this.DataContext = new MainViewModel(new WindowsStoreGreeter());
}

And in the phone app:

public MainPage()
{
    this.InitializeComponent();

    this.NavigationCacheMode = NavigationCacheMode.Required;

    this.DataContext = new MainViewModel(new WindowsPhoneGreeter());
}

In these code fragments a new MainViewModel is being created and supplied with a platform-specific IGreetingService implementation.

So in this way the shared MainViewModel class can still contain the majority of the code so we only have to write it once. But we still get the ability to write platform-specific code.

SHARE:

Using Shared Projects in Non-Universal App Projects

Using Visual Studio 2013 Update 2 and the Shared Project Manager Extension it’s possible to use shared projects in non Universal App projects.

This video shows a brief intro to shared projects in the context of Universal Apps and then how linked files work and how to refactor them to shared project.

As the documentation states: “Please note that this extension is preview technology and may have unforseen issues in the projects and solutions that it creates.”

Check out the video on YouTube or Vimeo.

SHARE:

Using MVVM Light in Universal Windows Apps

I though it would be interesting to see how easy it is to define an MVVM Light view model once and then use it in both a Universal Windows Phone and Windows Store project.

So I created a new blank universal apps project and added the “MVVM Light libraries only (PCL) NuGet” package to both the Windows 8.1 project and the Windows Phone 8.1 project.

Next create a new view model class in the shared project:

using System.Linq;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;

namespace UniMvvmLight
{
    class MainViewModel : ViewModelBase
    {
        public MainViewModel()
        {
            Words = "Hello";

            Reverse = new RelayCommand(() =>
                                       {
                                           Words = new string(Words.ToCharArray().Reverse().ToArray());
                                       });
        }

        private string _words;
        public RelayCommand Reverse { get; set; }

        public string Words
        {
            get
            {
                return _words;
            }
            set
            {
                Set(() => Words, ref _words, value);                
            }
        }
    }
}

I’m not going to create a view model locator etc, just simply set the datacontext in the code behind of both the phone and store MainWindow:

public MainPage()
{
    this.InitializeComponent();

    this.DataContext = new MainViewModel();
}

Next define the xaml in both the MainWindow.xaml in both phone and store projects:

<Grid>
    <StackPanel>
        <TextBox Text="{Binding Words}"></TextBox>
        <Button Command="{Binding Reverse}">Reverse</Button>
    </StackPanel>
</Grid>

Now running either the phone or store app works as expected, the view model binding works as expected and clicking the button reverses the string as expected. Whilst this is not surprising, the view model in the shared project is just like having a copy of it in both app projects, even so it’s still cool.

Windows phone simulator

If we wanted to we could then leverage C# partial classes and methods to define platform-specific viewmodel code.

SHARE:

Leveraging C# Partial Classes and Methods in Windows Universal Apps

There’s a number of ways we could implement platform specific code in Windows Universal Apps which I’ll cover in future articles.

In this article we’ll look at an often underused feature of C#: partial classes and methods.

Quick Overview

Partial classes allow us to split the definition of a class over multiple .cs files. The files all contain the same namespace and class names, but the class name is preceded by the partial keyword modifier.

Partial methods allow a method to be defined but that doesn’t contain an implementation, the implementation can then be provided in another partial class file.

(Check out my C# Tips eBook for more info on partial types.)

Using Simple Conditional Compilation Directives

If you want to get an overview of Universal Apps, check out this previous article.

For the sake of this demo, say we have a class “Identity” that displays a message box stating whether we’re in a Windows Store or Phone app.

We could do this using conditional directives:

using System;
using System.Threading.Tasks;
using Windows.UI.Popups;

namespace UsingPartials
{
    public class Identity
    {             
        public async Task WhoAmI()
        {
            string message = CalcMessage();

#if WINDOWS_APP

            message = "I'm a Windows Store App!";

#elif WINDOWS_PHONE_APP

            message = "I'm a Windows Phone App!";            

#endif

            var dialog = new MessageDialog(message);
            await dialog.ShowAsync();
        }
        
    }
}

And from a button click event handler in both the apps:

private async void WhoAmI_Click(object sender, RoutedEventArgs e)
{
    var id = new Identity();

    await id.WhoAmI();
}

Clicking the button in the apps results in the following message boxes being displayed:

image

 

image

 

Refactoring to Partial

So this is a simple example, but if there were lots of these conditional directives, we can tidy things up a little.

The idea is that the shared class “Identity” is made partial:

public partial class Identity

This class still contains the method that’s called from each of the apps, but this time the creation of the content of the message is delegated to a method called “CalcMessage”. This method sets the private field to be used in the dialog.

In the “Identity” class, the “CalcMessage” is declared as a partial method. This means that it doesn’t contain an implementation, but the “WhoAmI” method can still call it.

The actual implementation of the code that decides on the message is unique to the two apps.

So now the “Identity” class now looks like this:

using System;
using System.Threading.Tasks;
using Windows.UI.Popups;

namespace UsingPartials
{
    public partial class Identity
    {
        string _message;

        public async Task WhoAmI()
        {
            CalcMessage();

            var dialog = new MessageDialog(_message);
            await dialog.ShowAsync();
        }

        partial void CalcMessage();    
    }
}

We now create a new class file in the Windows Store app:

namespace UsingPartials
{
    public partial class Identity
    {
        partial void CalcMessage()
        {            
            _message = "I'm a Windows Store App!";
        }
    }
}

And another one in the Phone app:

namespace UsingPartials
{
    public partial class Identity
    {
        partial void CalcMessage()
        {
            _message = "I'm a Windows Phone App!";
        }
    }
}

Now the implementation of CalcMessage can be different for both platforms, but other code can still be shared in the shared project version of Identity.cs.

We also now don’t have any conditional directives in use.

If we only have one or two of these conditional directives, then it’s probably easier to just keep them as is, but if there are lots of them and it’s making readability harder then partials may be a useful alternative.

If you want to fill in the gaps in your C# knowledge be sure to check out my C# Tips and Traps training course from Pluralsight – get started with a free trial.

SHARE:

Getting Started Building a Universal Windows App

Universal Windows apps promise to enable the sharing of app code between Windows 8.1 Store apps and Windows Phone 8.1 apps.

In this demo, we’ll create a simple app and see how much work we can share between the two platforms. The sample code and design is probably not how we’d choose to implement a final solution but it will suffice for demo purposes.

Getting Started

Install Visual Studio 2013 Update 2.

Create a new project, head to the Visual C#, Store Apps, Universal Apps; choose the Blank App (Universal Apps) as the following screenshot shows. Name the app “Speechless”.

Visual Studio Universal App Create New Project

Once the solution is created, there will be 3 projects, one for Windows Store, one for Windows Phone, and a third project where we can put all the code we want to share between the two apps.

Universal App Solution

Creating a Shared Class

First off let’s create a class that we can share between apps:

solution screenshot

using System.Collections.Generic;

namespace Speechless
{
    static class Messages
    {
        public static IEnumerable<string> Greetings
        {
            get
            {
                yield return "Hello";
                yield return "Yo!";
                yield return "What's up?";
                yield return "Good day sir!";
            }
        }
    }
}

This just gives a few greetings that the user can choose from. Because this class was added in the Speechless.Shared project, it can be used from both apps.

So we could just go and create some XAML in each app and use this class, but let’s see if we can actually share XAML between apps to further reduce effort.

Creating a shared User Control

In the Speechless.Shared project, add a new item of type User Control called “ChooseGreatingControl.xaml”.

Add some XAML:

<UserControl
    x:Class="Speechless.ChooseGreatingControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:Speechless"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300"
    d:DesignWidth="400"    
    Width="300">
    
    <Grid>
        <StackPanel>
            <ComboBox Name="GreetingChoice" ></ComboBox>
            <Button Name="SayIt" Click="SayIt_OnClick">Speak</Button>
        </StackPanel>
    </Grid>
</UserControl>

This gives the user a ComboBox to choose which greeting to speak.

In the code behind:

using System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace Speechless
{
    public sealed partial class ChooseGreatingControl : UserControl
    {
        public ChooseGreatingControl()
        {
            this.InitializeComponent();

            GreetingChoice.ItemsSource = Messages.Greetings;

            GreetingChoice.SelectedIndex = 0;
        }

        private async void SayIt_OnClick(object sender, RoutedEventArgs e)
        {
        }
    }
}

Here we’re just wiring up the ComboBox items to those in the Messages class and setting the default selected item to the first one.

Next let’s try to add some code to do some text to speech:

private async void SayIt_OnClick(object sender, RoutedEventArgs e)
{
    var sayWhat = GreetingChoice.SelectedValue as string;

    var synth = new Windows.Media.SpeechSynthesis.SpeechSynthesizer();

    Windows.Media.SpeechSynthesis.SpeechSynthesisStream stream = await synth.SynthesizeTextToStreamAsync(sayWhat);

    var mediaElement = new MediaElement();
    mediaElement.SetSource(stream, stream.ContentType);
    mediaElement.Play();
}

So now we have some UI XAML and some code, let’s see how easy it is to share this user control between the two apps.

Using the Same User Control from Both Windows Store and Windows Phone Apps

In the MainPage.xaml of the Windows Store app project, let’s add an instance of the user control:

<Page
    x:Class="Speechless.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:Speechless"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <local:ChooseGreatingControl></local:ChooseGreatingControl>
    </Grid>
</Page>

Let’s go and do the same for the Windows Phone app:

<Page
    x:Class="Speechless.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:Speechless"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

    <Grid>
        <local:ChooseGreatingControl></local:ChooseGreatingControl>
    </Grid>
</Page>

Running the Apps

So lets try running now, first the Windows Store app (which is selected as the default start-up app), so F5…

Windows Store app screenshot

Clicking the Speak button works, and speaks outputs the selected greeting.

So let’s try the Windows Phone app, select it as the start-up app and hit F5…

System.UnauthorizedAccessException

This is because we need to add the Microphone capability to the Windows Phone app, once this is done the app runs and works as expected:

Windows Phone screenshot

Conclusions?

This is pretty cool. Having written an app in the past  that targets both Windows Store and Windows Phone this shared project makes things SO much easier – no linked file frustrations.

The next app I start writing (whether Store or Phone) I’ll use this Universal template just so if I want to port it to the other platform it will be ready to go.

It’s going to be interesting mixing this approach with Portable Class Libraries as well. Also a framework such as MVVMLight.

If there is code in the Shared project that only applies to either Store or Phone, we can use the predefined directives:

#if WINDOWS_APP
            // Store only app specific code here
#else
            // Phone only app specific code here
#endif

Whilst I don’t know what the plans are regarding Xbox One, it would be cool to have an Xbox One app store and we could just add an “Xbox One App” to our Universal Apps solution, build, and have the same app with most of the code and UI shared between Windows Store, Windows Phone, and Xbox One.

Exciting times!

SHARE:

Beyond the Compiler with ConventionTests

We often have conventions in our code. For example all DTOs/entity/etc. classes should be in a specific namespace, or the name of certain types of class should end with a given word. Another example, we may need to make sure that all classes (or those in a specific namespace) contain all-virtual members.

These kind of things are conventions that the team may agree to but the compiler won’t pick up as build errors or warnings. The code may still be completely valid C# even though it violates a convention.

ConventionTests is a brilliant idea (and it’s ideas like this that keep me loving programming) allows us to write tests to verify these conventions, conventions that the compiler cannot verify.

Installation

Simple installation via NuGet into your test project: PM> Install-Package TestStack.ConventionTests

Simple Usage

Using whatever testing framework you prefer (xUnit.net, NUnit, etc.) create a test method.

these kind of things are conventions that the team may agree to but the compiler won’t pick up

In this method, the first thing to do is to select all the types in the production code that we want to check against a convention.

We can do this with code such as:

var typesToCheck = Types.InAssemblyOf<SomeClass>();   

Here the Types.InAssemblyOf method is being used to find which assembly contains the class called SomeClass. Using this overload, all of the types in the assembly will be selected, however there are other overloads that allow the returning of types in a given namespace.

The next step is to create an instance of one of the out-of-the-box conventions.

var convention = new AllClassesHaveDefaultConstructor();

This convention checks that all the selected types have a default constructor defined.

Now we have the list of types we want to check, and a convention to check them against.

To actually perform the check, we use the Convention.Is method:

Convention.Is(convention, typesToCheck);

If any of the classes selected in typesToCheck don’t have a default constructor then an exception will be thrown (with some useful info in it) and the test will fail.

You can see some of the other out-of-the-box conventions on the GitHub site, you can also write your own custom conventions.

 

ConventionTests is one of the tools in the TestStack suite. To learn more about ConventionTests and the other TestStack tools, checkout out my Building the Right Thing in .NET with TestStack Plurasight course.

SHARE: