Integrating .NET Core tools into the build

Thanks to the new .csproj format and the changes to NuGet packages, it’s now easy to create a tool that can run as part of the build process. To try this, we’ll create a solution with two projects – one for the tool and one for the tool to run as part as the build process. Using the console, the following is a simple way to create the initial solution:

> mkdir ToolExample
> cd ToolExample
> dotnet new sln
> dotnet new console -o ConsoleApp
> dotnet new console -o ToolApp
> dotnet sln add ConsoleApp
> dotnet sln add ToolApp

To get our tool to do something as part of the build, when we package it as a NuGet package we need to add a Package.targets file that contains the MSBuild target we want to run as part of the project that the package gets installed to. To prove our tool is running we’ll start off with a simple message that gets output when our target is invoked. Add the following file called Package.targets inside the ToolApp directory:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Target Name="ToolTarget"
          AfterTargets="AfterBuild">
    <Message Text="Message from ToolApp" Importance="High" />
  </Target>
</Project>

In order for NuGet to use the file, it must have the same name as the package that contains it. We can use the $(PackageId) MSBuild property to ensure when the file is packages inside the nupkg file is has the expected name. Alter the ToolApp.csproj file to match the following, which also marks it as a developer dependency:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp2.1</TargetFramework>

    <DevelopmentDependency>true</DevelopmentDependency>
    <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
    <Version>0.0.1</Version>
  </PropertyGroup>

  <ItemGroup>
    <Content Include="Package.targets">
      <Pack>true</Pack>
      <PackagePath>build/$(PackageId).targets</PackagePath>
      <Visible>true</Visible>
    </Content>
  </ItemGroup>
</Project>

Since we’ve set it to build the package on build, running dotnet build ToolApp will create our nupkg file that can be consumed by our test console application. To consume it inside the console app you can either host it on a NuGet server or, more conveniently during testing, tell NuGet the folder that contains the package via the NuGet.config file inside the ConsoleApp directory:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <packageSources>
        <add key="LocalDebug" value="../ToolApp/bin/Debug" />
    </packageSources>
</configuration>

Install the package inside the ConsoleApp.csproj by editing it to look like the following:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp2.1</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="ToolApp" Version="0.0.1" />
  </ItemGroup>
</Project>

If you now build the console application you should now see the message from the tool we created:

> dotnet build ConsoleApp
>   ConsoleApp -> .../ConsoleApp.dll
>   Message from ToolApp

Running our own code

The above created the foundation for running a task when your package is installed in another project. Now if we wanted to run our own code instead, that can be done using the same technique. First we’ll put the code we want to run inside the Program.cs file inside the ToolApp project:

namespace ToolApp
{
    using System;

    public static class Program
    {
        public static void Main(string[] args)
        {
            Console.WriteLine("Hello from ToolApp!");
        }
    }
}

Can’t get simpler than that. However, if we build it and package it now when the package gets installed the target project would have a reference to our ToolApp.dll. This is because the output of a build by default gets packed inside the lib folder inside the nupkg, which in turn causes it to get added as a reference. To get around this we’ll force the output to be packed inside another folder inside the nupkg, however, this will generate the warning an assembly file that is not in lib folder so we’ll suppress that too. Edit ToolApp.csproj with the following added:

<PropertyGroup>
...
<BuildOutputTargetFolder>tasks</BuildOutputTargetFolder>
<NoWarn>$(NoWarn);NU5100</NoWarn>
...
</PropertyGroup>

Finally, change the Package.target to run our new code by changed the Message element to an Exec element, using the MSBuild property to find the current location of where our package was installed:

<Exec Command="dotnet $(MSBuildThisFileDirectory)../tasks/netcoreapp2.1/ToolApp.dll" />

Finally, if you bump the version of the tool package (in both csproj files) and build the console application you should see the following output:

> dotnet build ConsoleApp
>   ConsoleApp -> .../ConsoleApp.dll
>   Hello from ToolApp!

Resolving Assemblies in .NET Core

.NET Core applications rely heavily on NuGet to resolve their dependencies, which is simplifies development. Unless you’re packaging the application up as a self-contained deployment, at runtime the resolution of assemblies is not as straightforward, however, as all the dependencies are no longer coppied to the output folder.

I needed to reflect over the types defined in an external assembly in order to look for specific attributes. The first problem is how to load an assembly from the disk in .NET Core.

AssemblyLoadContext

The System.Runtime.Loader package contains a type called AssemblyLoadContext that can be used to load assemblies from a specific path, meaning we can write code like this:

public sealed class Program
{
    public static int Main(string[] args)
    {
        Assembly assembly =
            AssemblyLoadContext.Default.LoadFromAssemblyPath(args[0]);

        PrintTypes(assembly);
        return 0;
    }

    private static void PrintTypes(Assembly assembly)
    {
        foreach (TypeInfo type in assembly.DefinedTypes)
        {
            Console.WriteLine(type.Name);
            foreach (PropertyInfo property in type.DeclaredProperties)
            {
                string attributes = string.Join(
                    ", ",
                    property.CustomAttributes.Select(a => a.AttributeType.Name));

                if (!string.IsNullOrEmpty(attributes))
                {
                    Console.WriteLine("    [{0}]", attributes);
                }
                Console.WriteLine("    {0} {1}", property.PropertyType.Name, property.Name);
            }
        }
    }
}

However, as soon as an attribute that is defined in another assembly is found (e.g. from a NuGet package), the above will fail with a System.IO.FileNotFoundException. This is because the AssemblyLoadContext will not load any dependencies – we’ll have to do that ourselves.

Dependencies File

When you build a .NET Core application, the compiler also produces some Runtime Configuration Files, in particular the deps.json file that includes the dependencies for the application. We can hook in to this to allow us to resolve the assemblies at runtime, using additional helper classes from the System.Runtime.Loader package to parse the file for us.

internal sealed class AssemblyResolver : IDisposable
{
    private readonly ICompilationAssemblyResolver assemblyResolver;
    private readonly DependencyContext dependencyContext;
    private readonly AssemblyLoadContext loadContext;

    public AssemblyResolver(string path)
    {
        this.Assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(path);
        this.dependencyContext = DependencyContext.Load(this.Assembly);

        this.assemblyResolver = new CompositeCompilationAssemblyResolver(new ICompilationAssemblyResolver[]
        {
            new AppBaseCompilationAssemblyResolver(Path.GetDirectoryName(path)),
            new ReferenceAssemblyPathResolver(),
            new PackageCompilationAssemblyResolver()
        });

        this.loadContext = AssemblyLoadContext.GetLoadContext(this.Assembly);
        this.loadContext.Resolving += OnResolving;
    }

    public Assembly Assembly { get; }

    public void Dispose()
    {
        this.loadContext.Resolving -= this.OnResolving;
    }

    private Assembly OnResolving(AssemblyLoadContext context, AssemblyName name)
    {
        bool NamesMatch(RuntimeLibrary runtime)
        {
            return string.Equals(runtime.Name, name.Name, StringComparison.OrdinalIgnoreCase);
        }

        RuntimeLibrary library =
            this.dependencyContext.RuntimeLibraries.FirstOrDefault(NamesMatch);
        if (library != null)
        {
            var wrapper = new CompilationLibrary(
                library.Type,
                library.Name,
                library.Version,
                library.Hash,
                library.RuntimeAssemblyGroups.SelectMany(g => g.AssetPaths),
                library.Dependencies,
                library.Serviceable);

            var assemblies = new List<string>();
            this.assemblyResolver.TryResolveAssemblyPaths(wrapper, assemblies);
            if (assemblies.Count > 0)
            {
                return this.loadContext.LoadFromAssemblyPath(assemblies[0]);
            }
        }

        return null;
    }
}

The code works by listening to the Resolving event of the AssemblyLoadContext, which gives us a chance to find the assembly ourselves (the class also implements the IDisposable interface to allow unregistering from the event, as the AssemblyLoadContext is static so will keep the class alive). During resolution, we find the assembly inside the dependency file (note the use of a case insensitive comparer) and wrap this up inside a CompilationLibrary. This can actually be skipped if we set the PreserveCompilationContext option in the csproj file to true, as we can then use the DependencyContext.CompileLibraries property, however, the above code works without that setting being present. Also note that I don’t use the result of TryResolveAssemblyPaths, as it will return true even if it didn’t add any paths to the list.

All that’s left is to modify the main program and the code will now be able to resolve attributes in other assemblies:

public static int Main(string[] args)
{
    using (var dynamicContext = new AssemblyResolver(args[0]))
    {
        PrintTypes(dynamicContext.Assembly);
    }
    return 0;
}

Nesting files in a project

As part of the code generation work, I wanted to group the generated code file with the associated source. This was provided for free under project.json if you kept the filename the same and simply appended a new extension, however, this has been lost in the conversion to MSBuild files.

Solution Explorer

Having said that, the project file format for .NET core projects in Visual Studio 2017 has been greatly simplified, for example, you no longer have an entry for each file in the project. There also exists a nice Microsoft.Build NuGet package that simplifies working with the project file and, as a bonus, it also works for .NET Core applications.

Implementation

The way to get Visual Studio to group an item is by adding a Compile item with the DependentUpon set to the parent item, i.e.:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    ...
  </PropertyGroup>

  <ItemGroup>
    <Compile Update="Child.cs">
      <AutoGen>True</AutoGen>
      <DependentUpon>Parent.txt</DependentUpon>
    </Compile>
  </ItemGroup>
</Project>

This can be done in code quite easily by the following code:

string project = "Example.csproj";
string childName = "Example.txt.cs";
string parentName = "Example.txt";

// Load the project file
var root = ProjectRootElement.Open(
    project,
    ProjectCollection.GlobalProjectCollection,
    preserveFormatting: true);

// We need to put the Compile in an ItemGroup
ProjectItemGroupElement group = root.AddItemGroup();

// MUST set the Update attribute before adding it to the group
ProjectItemElement compile = root.CreateItemElement("Compile");
compile.Update = childName;
group.AppendChild(compile);

// MUST be in the group before we can add metadata
compile.AddMetadata("AutoGen", "True");
compile.AddMetadata("DependentUpon", parentName);

// Save changes
root.Save();

As you can see, the code follows the XML structure and can be easily expanded to re-use the same ItemGroup for all the dependent items. Also worth noting is that I’m preserving the formatting of the project file by specifying true for the preserveFormatting parameter in the call to the Open method, as the project files can now be edited manually from within Visual Studio it would annoy me if another tool had overwritten my hand-crafted changes 🙂

Adding a tool to a .NET Core build

I need a command line tool to run over some files in a project and generate some code that can then be built with the rest of the project’s source code. However, the documentation to get this to be an automatic step of the build is a bit lacking – there are plenty of articles on creating a .NET Core CLI tool, however, these have to be manually invoked at the command prompt.

Background

.NET Core projects files (the Visual Studio 2017 csproj type) allow the NuGet packages to be specified in the same file as any other project/assembly reference. It also allows a special type of NuGet package that was created as a DotNetCliTool type to be pulled into a project and integrated with the rest of the dotnet tooling, for example:

dotnet restore
dotnet my-tool

The tool is just a standard .NET Core console application that runs in the projects directory and can receive command line arguments as any other console program can (i.e. dotnet my-tool argument would pass ‘argument’ to the entry point of the program).

Creating a tool

Creating a tool is simple: create a new .NET Core console app (MUST be a .NET Core App 1.0, not 1.1) and edit the project file to set the package type to be a .NET CLI tool (at the moment there’s no UI for this in Visual Studio, so you’ll have to edit the csproj file, but that can be done from Visual Studio now by right clicking on the project and then there will be an Edit option in the context menu).

Here’s an example project file:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp1.0</TargetFramework>
    <PackageType>DotNetCliTool</PackageType>
  </PropertyGroup>
</Project>

Another thing that we need to do is ensure the application is prefixed with dotnet- in order for it to work with dotnet. This can be done via the UI (the Assembly name in the properties) or by editing the csproj:

<PropertyGroup>
  ...
  <AssemblyName>dotnet-example-tool</AssemblyName>
</PropertyGroup>

You can now build that and then create a NuGet package by running the dotnet pack command in the project’s folder.

Using the tool

For testing purposes, it’s probably easier to put the tool on your local machine and setting up Visual Studio to use the local package source:

NuGet Source

In another project, you can now reference the tool as a NuGet package. Unfortunately, at the time of writing the Visual Studio NuGet UI throws an error of “Package ‘ExampleTool’ has a package type ‘DotNetCliTool’ that is not supported by project ‘ExampleConsole’”. This means you’ll need to edit the csproj file to include it manually:

<ItemGroup>
  <DotNetCliToolReference Include="ExampleTool" Version="1.0.0" />
</ItemGroup>

To test this works, open the command prompt in the project’s directory and run the following:

dotnet restore
dotnet example-tool

You should see “Hello World!” displayed (or whatever you made your program do). We’re nearly there, however, I wanted to the tool to run before each build so it can generate some source files that get swept up in the build – at the moment it’s a manual step.

Integration with the build

Although the project.json was nice and compact, one advantage of moving back to MSBuild is we can now take advantage of the exec task to run our tool during the build. To do this, edit the csproj file of the project consuming the tool to add the following:

<Target Name="RunExampleTool" BeforeTargets="Build">
  <Exec Command="dotnet example-tool" WorkingDirectory="$(ProjectDir)" />
</Target>

Now when you build the solution, if you check the build output you should see “Hello World!” in there. Success!

Analysing the above, you can see we’ve created a target that runs before the built in Build task (note you used to be able to just name your task BeforeBuild, however, this no longer works – I’m guessing it’s a result of no longer including the common targets?). Next the task the target will run is an exec task, which invokes our tool (via the dotnet command). Here the important thing to note is that we’re setting the working directory to be the project’s directory, which is achieved using the MSBuild macro $(ProjectDir) – dotnet will only automatically pick up the tool from the NuGet packages is we’re in that directory.

That’s it, quite simple but took me a while to piece everything together as the documentation is missing in some areas and I guess it’s not a common thing I’m trying to achieve.

Loading indicator for content controls

With C# 5 (.NET 4.5) it became a lot easier to create asynchronous methods. There’s also a great MSDN article on how to leverage this using MVVM so that you can have properties update the view when they’ve finished loading. What I wanted was a simple control that would indicate to the user that the content was being fetched (via binding to the NotifyTaskCompletion.IsNotCompleted property).

What I wanted though was a simple attached property on a ContentControl (or HubSection in my case but it’s easy to modify for other control types) and it would switch to the loading indicator based on the bound value, as I didn’t want to have to modify lots of DataTemplates to add the indicator to them and then mess around with the visibility of the content/indicator based on if the value was being loaded or not.

The actual visual part of the control is straight forward:

public sealed class AsyncIndicator : Control
{
    protected override Size MeasureOverride(Size availableSize)
    {
        Size desiredSize = base.MeasureOverride(availableSize);

        return new Size(
            GetSize(availableSize.Width, desiredSize.Width),
            GetSize(availableSize.Height, desiredSize.Height));
    }

    private static double GetSize(double available, double desired)
    {
        return double.IsPositiveInfinity(available) ? desired : available;
    }
}

All this does is make the control take all the available size of the parent, taking into account if the parent provides us with an infinite amount of space (e.g. StackPanel). Here’s the simple template for it, which I tuck away inside Generic.xaml:

<Style TargetType="controls:AsyncIndicator">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="controls:AsyncIndicator">
                <Border Background="#33888888">
                    <StackPanel HorizontalAlignment="Center"
                                VerticalAlignment="Center">
                        <ProgressRing HorizontalAlignment="Center"
                                      IsActive="True" />

                        <TextBlock Style="{ThemeResource BodyTextBlockStyle}"
                                   Text="Loading" />
                    </StackPanel>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Like I said, nothing complex about this nor nothing that would really warrant a new control; it’s just a spinning progress (new to WinRT) with a label. However, I’m also going to store the attached property in this control. How the attached property works is when it’s set to true it will replace the ContentTemplate property of the attached control to one which just contains the loading indicator; when it’s set to false it restores the original value to the attached control. Therefore, I’m going to use two dependency properties, a public one for the attached property and a private one for storing the current value of the ContentTemplate before it is overwritten.

public static readonly DependencyProperty IsLoadingProperty =
    DependencyProperty.RegisterAttached("IsLoading", typeof(bool), typeof(AsyncIndicator), new PropertyMetadata(false, OnIsLoadingChanged));

private static readonly DependencyProperty OriginalTemplateProperty =
    DependencyProperty.RegisterAttached("OriginalTemplate", typeof(TemplateData), typeof(AsyncIndicator), new PropertyMetadata(null));

public static bool GetIsLoading(DependencyObject obj)
{
    return (bool)obj.GetValue(IsLoadingProperty);
}

public static void SetIsLoading(DependencyObject obj, bool value)
{
    obj.SetValue(IsLoadingProperty, value);
}

private static void OnIsLoadingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    if ((bool)e.NewValue)
    {
        TemplateData data = BackupTemplateProperty(d);
        if (data != null)
        {
            SetIndicator(d, data);
        }
    }
    else
    {
        RestoreTemplateProperty(d);
    }
}

private class TemplateData
{
    public DependencyProperty Property { get; set; }

    public object Template { get; set; }
}

The reason for the private TemplateData nested class is to allow for different properties of different controls to be backed up, replaced and restored (at the moment I need ContentControl and HubSection, which don’t share the same ContentTemplate property). Here’s the actual code which switches out the current template and replaces it with one that just contains the new control:

private static DependencyProperty GetTemplateProperty(object element)
{
    if (element is ContentControl)
    {
        return ContentControl.ContentTemplateProperty;
    }
    else if (element is HubSection)
    {
        return HubSection.ContentTemplateProperty;
    }

    return null;
}

private static TemplateData BackupTemplateProperty(DependencyObject d)
{
    TemplateData data = null;

    DependencyProperty templateProperty = GetTemplateProperty(d);
    if (templateProperty != null)
    {
        data = new TemplateData();
        data.Property = templateProperty;
        data.Template = d.GetValue(templateProperty);
    }

    d.SetValue(OriginalTemplateProperty, data);
    return data;
}

private static void RestoreTemplateProperty(DependencyObject d)
{
    var data = (TemplateData)d.GetValue(OriginalTemplateProperty);
    if (data != null)
    {
        d.SetValue(data.Property, data.Template);
        d.ClearValue(OriginalTemplateProperty);
    }
}

private static void SetIndicator(DependencyObject d, TemplateData data)
{
    // Note: The namespace must match the namespace this class belongs to.
    const string IndicatorDataTemplate =
@"<DataTemplate xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'
                xmlns:local='using:PurplePhobos.View.Controls'>
    <local:AsyncIndicator />
</DataTemplate>";

    d.SetValue(data.Property, XamlReader.Load(IndicatorDataTemplate));
}

To keep the code generalised, it tries to find a suitable dependency property based on the type of the control it is being attached to. If it finds a property it then saves the current value of it to our private attached property (this also works fine for static resources, however, it won’t work for bindings, but there shouldn’t be much need for a binding of a DataTemplate). A new DataTemplate is created from a string that contains the new control – note if you use this code and change the namespace of where the class is be sure to update the string as well to the new namespace! Finally restoring is a lot easier, the control just needs to check if a template property has been backed up to the private attached property and, if so, set it back (clearing the OriginalTemplateProperty to reduce resources).

The full class can be found here – you’ll just need to style it somewhere in your app. Usage is something like this:

<HubSection ctrls:AsyncIndicator.IsLoading="{Binding Property.IsNotCompleted}"
            ContentTemplate="{StaticResource ExampleTemplate}" />

WeakEventManager for WinRT

When registering to an event with an instance method then a reference will be stored from the event source to the event handler. This is normally fine, however, there are situations when the event source may live longer than the event handler. An example I recently ran into was when I wanted to listen to the Clipboard.ContextChanged event, which is static.

In WPF land you’d use the WeakEventManager<TEventSource, TEventArgs> class, however, this isn’t available to Window Store apps, so let’s build it! I’ve changed the API slightly, as I needed overloads to accept a Type due to Clipboard being a static class (which you can’t use for generic type parameters). So, here’s what I ended up with to register the event:

WeakEventManager.AddHandler<object>(
    typeof(Clipboard),
    "ContentChanged",
    this.OnClipboardContentChanged);

Here’s the main class – the actual logic is performed by the nested class:

using System;
using System.Collections.Generic;
using System.Reflection;

/// <summary>
/// Implements a weak event listener that allows the owner to be garbage
/// collected if its only remaining link is an event handler.
/// </summary>
public static class WeakEventManager
{
    private readonly static List<WeakEvent> registeredEvents = new List<WeakEvent>();

    /// <summary>
    /// Adds the specified event handler to the specified event.
    /// </summary>
    /// <typeparam name="TEventArgs">The type that holds the event data.</typeparam>
    /// <param name="sourceType">
    /// The type of the class that contains the specified event.
    /// </param>
    /// <param name="eventName">The name of the event to subscribe to.</param>
    /// <param name="handler">The delegate that handles the event.</param>
    public static void AddHandler<TEventArgs>
        (Type sourceType, string eventName, EventHandler<TEventArgs> handler)
    {
        EventInfo eventInfo = sourceType.GetRuntimeEvent(eventName);
        registeredEvents.Add(
            new WeakEvent(null, eventInfo, handler));
    }

    /// <summary>
    /// Adds the specified event handler to the specified event.
    /// </summary>
    /// <typeparam name="TEventSource">The type that raises the event.</typeparam>
    /// <typeparam name="TEventArgs">The type that holds the event data.</typeparam>
    /// <param name="source">
    /// The source object that raises the specified event.
    /// </param>
    /// <param name="eventName">The name of the event to subscribe to.</param>
    /// <param name="handler">The delegate that handles the event.</param>
    public static void AddHandler<TEventSource, TEventArgs>
        (TEventSource source, string eventName, EventHandler<TEventArgs> handler)
    {
        EventInfo eventInfo = typeof(TEventSource).GetRuntimeEvent(eventName);
        registeredEvents.Add(
            new WeakEvent(source, eventInfo, handler));
    }

    /// <summary>
    /// Removes the specified event handler from the specified event.
    /// </summary>
    /// <typeparam name="TEventArgs">The type that holds the event data.</typeparam>
    /// <param name="sourceType">
    /// The type of the class that contains the specified event.
    /// </param>
    /// <param name="eventName">
    /// The name of the event to remove the handler from.
    /// </param>
    /// <param name="handler">The delegate to remove.</param>
    public static void RemoveHandler<TEventArgs>
        (Type sourceType, string eventName, EventHandler<TEventArgs> handler)
    {
        EventInfo eventInfo = sourceType.GetRuntimeEvent(eventName);
        foreach (WeakEvent weakEvent in registeredEvents)
        {
            if (weakEvent.IsEqualTo(null, eventInfo, handler))
            {
                weakEvent.Detach();
                break;
            }
        }
    }

    /// <summary>
    /// Removes the specified event handler from the specified event.
    /// </summary>
    /// <typeparam name="TEventSource">The type that raises the event.</typeparam>
    /// <typeparam name="TEventArgs">The type that holds the event data.</typeparam>
    /// <param name="source">
    /// The source object that raises the specified event, or null if it's
    /// a static event.
    /// </param>
    /// <param name="eventName">
    /// The name of the event to remove the handler from.
    /// </param>
    /// <param name="handler">The delegate to remove.</param>
    public static void RemoveHandler<TEventSource, TEventArgs>
        (TEventSource source, string eventName, EventHandler<TEventArgs> handler)
    {
        EventInfo eventInfo = typeof(TEventSource).GetRuntimeEvent(eventName);
        foreach (WeakEvent weakEvent in registeredEvents)
        {
            if (weakEvent.IsEqualTo(source, eventInfo, handler))
            {
                weakEvent.Detach();
                break;
            }
        }
    }

    private class WeakEvent
    {
        // Implementation details to follow
    }
}

Naturally, in production you’d want some argument validation (i.e. not nulls and that GetRuntimeEvent returned something), but to keep the code simple I’ve omitted it. The actual logic goes in the WeakEvent nested class. This is needed because you can’t just keep a weak reference to the event handler object, as this most likely will be a temporary object that will soon get garbage collected. You also can’t keep a strong reference to the event handler, as it has a reference to the instance of the target so will keep it alive, defeating the point of the class! Therefore, the WeakEvent class has to wrap the parts of the event handler delegate in a way that allows the target class to be garbage collected. Here’s how I’ve approached it:

private class WeakEvent
{
    private static readonly MethodInfo onEventInfo =
        typeof(WeakEvent).GetTypeInfo().GetDeclaredMethod("OnEvent");

    private EventInfo eventInfo;
    private object eventRegistration;
    private MethodInfo handlerMethod;
    private WeakReference<object> handlerTarget;
    private object source;

    public WeakEvent(object source, EventInfo eventInfo, Delegate handler)
    {
        this.source = source;
        this.eventInfo = eventInfo;

        // We can't store a reference to the handler (as that will keep
        // the target alive) but we also can't store a WeakReference to
        // handler, as that could be GC'd before its target.
        this.handlerMethod = handler.GetMethodInfo();
        this.handlerTarget = new WeakReference<object>(handler.Target);

        object onEventHandler = this.CreateHandler();
        this.eventRegistration = eventInfo.AddMethod.Invoke(
            source,
            new object[] { onEventHandler });

        // If the AddMethod returned null then it was void - to
        // unregister we simply need to pass in the same delegate.
        if (this.eventRegistration == null)
        {
            this.eventRegistration = onEventHandler;
        }
    }

    public void Detach()
    {
        if (this.eventInfo != null)
        {
            WeakEventManager.registeredEvents.Remove(this);

            this.eventInfo.RemoveMethod.Invoke(
                this.source,
                new object[] { eventRegistration });

            this.eventInfo = null;
            this.eventRegistration = null;
        }
    }

    public bool IsEqualTo(object source, EventInfo eventInfo, Delegate handler)
    {
        if ((source == this.source) && (eventInfo == this.eventInfo))
        {
            object target;
            if (this.handlerTarget.TryGetTarget(out target))
            {
                return (handler.Target == target) &&
                        (handler.GetMethodInfo() == this.handlerMethod);
            }
        }

        return false;
    }

    public void OnEvent<T>(object sender, T args)
    {
        object instance;
        if (this.handlerTarget.TryGetTarget(out instance))
        {
            this.handlerMethod.Invoke(instance, new object[] { sender, args });
        }
        else
        {
            this.Detach();
        }
    }

    private object CreateHandler()
    {
        Type eventType = this.eventInfo.EventHandlerType;
        ParameterInfo[] parameters = eventType.GetTypeInfo()
                                                .GetDeclaredMethod("Invoke")
                                                .GetParameters();

        return onEventInfo.MakeGenericMethod(parameters[1].ParameterType)
                            .CreateDelegate(eventType, this);
    }
}

Basically the parts of the delegate have been stored in two parts; the method to invoke (stored as a normal reference) and the target to invoke the method on (stored as a weak reference). The tricky part is registering our handler on the event via reflection, made more difficult because events in the core WinRT classes are slightly different to the .NET events (for example, the add method of the event returns an EventRegistrationToken that must be passed in to the remove method; .NET events return void for the add method and require the delegate passed into the add method for the parameter to the remove method). When we get called back we have a quick check to see if our target is still valid; if it isn’t then we unregister from the event (after all, we’ve got nothing to do when it’s invoked in the future!), which allows the GC to clean up the WeakEvent instance (not that it should be that heavy anyway).

Defining MessageDialogs in XAML

I’m a fan of the MVVM pattern and recently needed to present a dialog (actually a MessageDialog in WinRT) to the user if they were about to leave the data entry window but hadn’t saved their changes. I initially thought that the view model would need to create a dialog, however, I thought about it some more and came to the conclusion that actually the view should be responsible for this – the view model only needs to let the view know that it has unsaved changes and provide commands to the view (which will expose them to the user) for it to either save and close or close without saving.

So the next thing I needed was to be able to define a dialog in XAML, as I wanted to bind the buttons on the dialog to the commands in the view model. As well as defining it in the XAML, I wanted to either launch it in response to the user clicking a button or, if the dialog isn’t required (i.e. there are no unsaved changes in my scenario) make the button perform the default action without prompting the user. To do this I’ve used an attached property which, when set on a button, will subscribe to the Click event and show the dialog in the handler, if required, or perform the default action if the PromptUser property is set to false. The resulting XAML looks something like this (note that the MessageDialogTemplate can be moved to a resource, I’ve put it inline here to make the code snippet shorter and easier to follow):

<AppBarButton Icon="Cancel"
              Label="Close">
    <dlg:MessageDialogTemplate.ShowOnClick>
        <dlg:MessageDialogTemplate Content="You have unsaved changes to the document."
                                   ShowDialog="{Binding HasUnsavedChanges}">
            <dlg:DialogCommand Command="{Binding SaveAndClose}"
                               Label="Save changes" />
							   
            <dlg:DialogCommand Command="{Binding Cancel}"
                               Label="Discard changes" />

            <!-- If no command is specified then the button will -->
            <!-- do dismiss the dialog without triggering any action. -->
            <dlg:DialogCommand Label="Cancel" />
        </dlg:MessageDialogTemplate>
    </dlg:MessageDialogTemplate.ShowOnClick>
</AppBarButton>

So, that’s it’s usage. For the above there are two classes required:

namespace DialogHelper
{
    using System.Windows.Input;
    using Windows.UI.Popups;
    using Windows.UI.Xaml;
    using Windows.UI.Xaml.Markup;

    [ContentProperty(Name = "Label")]
    public sealed class DialogCommand : FrameworkElement
    {
        public static readonly DependencyProperty CommandParameterProperty =
            DependencyProperty.Register("CommandParameter", typeof(object), typeof(DialogCommand), new PropertyMetadata(null));

        public static readonly DependencyProperty CommandProperty =
            DependencyProperty.Register("Command", typeof(ICommand), typeof(DialogCommand), new PropertyMetadata(null));

        public static readonly DependencyProperty LabelProperty =
            DependencyProperty.Register("Label", typeof(string), typeof(DialogCommand), new PropertyMetadata(string.Empty));

        public ICommand Command
        {
            get { return (ICommand)this.GetValue(CommandProperty); }
            set { this.SetValue(CommandProperty, value); }
        }

        public object CommandParameter
        {
            get { return this.GetValue(CommandParameterProperty); }
            set { this.SetValue(CommandParameterProperty, value); }
        }

        public string Label
        {
            get { return (string)GetValue(LabelProperty); }
            set { SetValue(LabelProperty, value); }
        }

        internal void Invoke(IUICommand command)
        {
            if (this.Command != null)
            {
                this.Command.Execute(this.CommandParameter);
            }
        }
    }
}

Nothing too special about this class, apart from it inherits from FrameworkElement so that it gets the inheriting data context scaffolding, which means you can use bindings for the commands and they will pick it up from the button the dialog is attached to. Also worth noting is that originally I tried to make the class implement the IUICommand interface, however, because the dialog is running on a different thread to what the dependency properties were created on, there were some exceptions when the MessageDialog would try to read the values from the properties. Instead, as shown in the next class, these commands are translated into UICommands.

namespace DialogHelper
{
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Collections.Specialized;
    using Windows.UI.Popups;
    using Windows.UI.Xaml;
    using Windows.UI.Xaml.Controls;
    using Windows.UI.Xaml.Controls.Primitives;
    using Windows.UI.Xaml.Markup;

    [ContentProperty(Name = "Commands")]
    public sealed class MessageDialogTemplate : Panel
    {
        public static readonly DependencyProperty CancelCommandIndexProperty =
            DependencyProperty.Register("CancelCommandIndex", typeof(int), typeof(MessageDialogTemplate), new PropertyMetadata(-1));

        public static readonly DependencyProperty ContentProperty =
            DependencyProperty.Register("Content", typeof(string), typeof(MessageDialogTemplate), new PropertyMetadata(string.Empty));

        public static readonly DependencyProperty DefaultCommandIndexProperty =
            DependencyProperty.Register("DefaultCommandIndex", typeof(int), typeof(MessageDialogTemplate), new PropertyMetadata(-1));

        public static readonly DependencyProperty PromptUserProperty =
            DependencyProperty.Register("PromptUser", typeof(bool), typeof(MessageDialogTemplate), new PropertyMetadata(true));

        public static readonly DependencyProperty ShowOnClickProperty =
            DependencyProperty.RegisterAttached("ShowOnClick", typeof(MessageDialogTemplate), typeof(MessageDialogTemplate), new PropertyMetadata(null, OnShowOnClickChanged));

        public static readonly DependencyProperty TitleProperty =
            DependencyProperty.Register("Title", typeof(string), typeof(MessageDialogTemplate), new PropertyMetadata(string.Empty));

        private readonly ObservableCollection<DialogCommand> commands =
            new ObservableCollection<DialogCommand>();

        public MessageDialogTemplate()
        {
            this.commands.CollectionChanged += OnCommandsCollectionChanged;
        }

        public int CancelCommandIndex
        {
            get { return (int)this.GetValue(CancelCommandIndexProperty); }
            set { this.SetValue(CancelCommandIndexProperty, value); }
        }

        public IList<DialogCommand> Commands
        {
            get { return this.commands; }
        }

        public string Content
        {
            get { return (string)this.GetValue(ContentProperty); }
            set { this.SetValue(ContentProperty, value); }
        }

        public int DefaultCommandIndex
        {
            get { return (int)this.GetValue(DefaultCommandIndexProperty); }
            set { this.SetValue(DefaultCommandIndexProperty, value); }
        }

        public bool PromptUser
        {
            get { return (bool)this.GetValue(PromptUserProperty); }
            set { this.SetValue(PromptUserProperty, value); }
        }

        public string Title
        {
            get { return (string)this.GetValue(TitleProperty); }
            set { this.SetValue(TitleProperty, value); }
        }

        public static MessageDialogTemplate GetShowOnClick(DependencyObject obj)
        {
            return (MessageDialogTemplate)obj.GetValue(ShowOnClickProperty);
        }

        public static void SetShowOnClick(DependencyObject obj, MessageDialogTemplate value)
        {
            obj.SetValue(ShowOnClickProperty, value);
        }

        private static void OnButtonClick(object sender, RoutedEventArgs e)
        {
            MessageDialogTemplate template = GetShowOnClick(sender as DependencyObject);
            if (template != null)
            {
                template.OnButtonClick();
            }
        }

        private static void OnButtonDataContextChanged(FrameworkElement sender, DataContextChangedEventArgs args)
        {
            MessageDialogTemplate template = GetShowOnClick(sender);
            if (template != null)
            {
                template.DataContext = sender.DataContext;
            }
        }

        private static void OnShowOnClickChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var button = d as ButtonBase;
            if (button != null)
            {
                button.Click += OnButtonClick;
                button.DataContextChanged += OnButtonDataContextChanged;
            }
        }

        private void ExecuteDefaultCommand()
        {
            int index = this.DefaultCommandIndex;
            if (index == -1)
            {
                // Guidlines state that if not specified, the default is the
                // leftmost button.
                index = 0;
            }

            if (index < this.commands.Count)
            {
                DialogCommand command = this.commands[index];
                if ((command != null) && (command.Command != null))
                {
                    command.Command.Execute(command.CommandParameter);
                }
            }
        }

        private void OnCommandsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            this.Children.Clear();
            foreach (DialogCommand command in this.commands)
            {
                this.Children.Add(command);
            }
        }

        private void OnButtonClick()
        {
            if (this.PromptUser)
            {
                this.ShowMessageDialog();
            }
            else
            {
                this.ExecuteDefaultCommand();
            }
        }

        private async void ShowMessageDialog()
        {
            var dialog = new MessageDialog(this.Content, this.Title);

            foreach (DialogCommand command in this.commands)
            {
                dialog.Commands.Add(
                    new UICommand(command.Label, command.Invoke));
            }

            dialog.CancelCommandIndex = (uint)this.CancelCommandIndex;
            dialog.DefaultCommandIndex = (uint)this.DefaultCommandIndex;

            await dialog.ShowAsync();
        }
    }
}

It may seem strange to not bind the DataContext to the DataContext of the button, however, I was bit by the bug where changes to the parent data context are not propagated through the binding (see this blog for more details) – strangely enough changes to the parent’s data context do cause the buttons DataContextChanged event to fire, which makes it even more confusing the binding doesn’t work!?

I’m quite pleased with the result; it’s nice to define the dialog layout in the XAML with the rest of the UI and the view model doesn’t need to raise some event that the view has to listen for (which seems to be the way for it to show a dialog in most examples I’ve seen.)

DataTemplates in WinRT

While I enjoy the simpler interfaces in WinRT, I’ve been spoiled by the power of WPF. One thing I missed recently was the automatic selection of a DataTemplate based on the DataType property; this property isn’t there in WinRT.

The solutions I’ve seen use a custom DataTemplateSelector with various properties for each type. This certainly works but it felt a bit repetitive. Instead, the solution I came up with searches the resources for an item with the same key as the type name and returns that. Here’s the class:

namespace AutoDataTemplate
{
    using Windows.UI.Xaml;
    using Windows.UI.Xaml.Controls;
    using Windows.UI.Xaml.Media;

    public sealed class AutoDataTemplateSelector : DataTemplateSelector
    {
        protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
        {
            if (item == null)
            {
                return null;
            }

            object key = item.GetType().Name;
            return FindResource(key, container as FrameworkElement) as DataTemplate;
        }

        private static object FindResource(object key, FrameworkElement element)
        {
            if (element == null)
            {
                return null;
            }

            object value;
            if (element.Resources.TryGetValue(key, out value))
            {
                return value;
            }

            return FindResource(key, VisualTreeHelper.GetParent(element) as FrameworkElement);
        }
    }
}

Using this class would be something like this:

<Page x:Class="AutoDataTemplate.MainPage"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:adt="using:AutoDataTemplate">

    <Page.Resources>
        <adt:AutoDataTemplateSelector x:Key="AutoSelector" />
        
        <DataTemplate x:Key="ClassType1">
            <TextBlock Foreground="CornflowerBlue"
                       Text="{Binding Value}" />
        </DataTemplate>

        <DataTemplate x:Key="ClassType2">
            <TextBlock Foreground="Firebrick"
                       Text="{Binding DifferentValue}" />
        </DataTemplate>
    </Page.Resources>

    <ListView ItemsSource="{Binding}"
              ItemTemplateSelector="{StaticResource AutoSelector}"
              Padding="40" />
</Page>

Of course there are limitations with this approach, mainly that namespaces cannot be used (i.e. you can’t have the key as local:MyType). This means it is not possible to auto select the template if two types have the same name but live in different namespaces – for my scenario this wasn’t a problem.

Strtod in C# – Part 2: The implementation

The way we’re going to parse the number is from the string is the same way as in “What Every Computer Scientist Should Know About Floating-Point Arithmetic” I linked to last time (note this is for a single precision number, hence nine digits – we’ll need to use more):

First read in the 9 decimal digits as an integer N, ignoring the decimal point. [..] Next find the appropriate power 10P necessary to scale N. This will be a combination of the exponent of the decimal number, together with the position of the (up until now) ignored decimal point. [..] Finally multiply (or divide if P < 0) N and 10|P|.

The style I’ve used to parse the string is a series of static functions that take the string, the current index and return the index of the end of their data, passing any extracted data through an out parameter. In code that looks like this:

private static int SkipWhiteSpace(string str, int index);
private static int ParseSign(string str, int index, out int value);

I could have made the string and index member variables, but if the parsing failed I would need to roll back the index. I also toyed with the idea of using an iterator, but I couldn’t see an advantage. Also, when parsing the significand two values need to be returned to take into account the decimal place. Sure, I could have used a Tuple to accomplish this, put I went for the above to keep everything consistent.

I’m not going to go through each method here (you can download the updated code here) but I’ll go through the main sequence of events.

  • First we validate the arguments. This will be one less worry for the private methods knowing the passed in values are sane.
  • Skip any whitespace, remembering the position of the first non-whitespace character for later.
  • Try to parse a number. This means searching for a sign, skip any leading zeros and then parse the significand. Parsing the significand will give us a number and an exponent, in case the number has a decimal point. If we’ve parsed any digits (including the leading zeros) then we can check for an exponent and adjust the exponent of the significand accordingly. Finally, we can create a double from the sign, significand (stored in a 64-bit integer) and exponent.
  • If we didn’t parse any digits then we need to search for +/- infinity or NaN, after skipping the whitespace.
  • Failing that then we couldn’t get any number so set the end to the starting index and return 0.

It’s actually quite difficult to explain in words, so here’s a code snippet:

public static double Parse(string input, int start, out int end)
{
    if (input == null)
    {
        throw new ArgumentNullException("input");
    }
    if (start < 0)
    {
        throw new ArgumentOutOfRangeException("start", "Value cannot be negative.");
    }
    if (start > input.Length)
    {
        throw new ArgumentOutOfRangeException("start", "Value must be less then input.Length");
    }

    int endOfWhitespace = SkipWhiteSpace(input, start);

    long significand;
    int significandsExponent, sign;
    int startOfDigits = ParseSign(input, endOfWhitespace, out sign);
    int index = SkipLeadingZeros(input, startOfDigits);
    index = ParseSignificand(input, index, out significand, out significandsExponent);

    // Have we parsed a number?
    if ((index - startOfDigits) > 0)
    {
        int exponent;
        end = ParseExponent(input, index, out exponent);
        return MakeDouble(significand * sign, exponent - significandsExponent);
    }

    // Not a number, is it a constant?
    double value;
    end = ParseNamedConstant(input, endOfWhitespace, out value);
    if (end != endOfWhitespace)
    {
        return value;
    }

    // If we're here then we couldn't parse anything.
    end = start;
    return default(double);
}

One thing that caught me out (but picked up in the unit tests) was creating the double from the significand and the exponent when the exponent is less than -308 – there exists a category of floating point numbers that are denormalized so I needed to add a check in the MakeDouble function to handle these, as it was rounding them down to zero.

Strtod in C# – Part 1: The specification

As mentioned, parsing the points in an SVG polygon would be a lot easier (and quicker?) if we had the strtod function in C#. Well, let’s give it a go! Now, dealing with floating point numbers is tricky so I’m probably going to mess it up on some corner cases, so to limit the damage we’re going to create some tests that our function must be able to handle. These tests will also help create our specification, hopefully!

Precision

First of all, how accurate do we have to be? Well, §4.3 states:

a number has the capacity for at least a single-precision floating point number

It also goes on to mention that it’s preferable that double-precision be used for calculations, so we may as well parse to double to aid in calculations, knowing that any value stored in the SVG should fall within a valid range.

So, how many digits are we going to parse? What Every Computer Scientist Should Know About Floating-Point Arithmetic by David Goldberg is by far the best work on trying to understand floating point numbers. I don’t claim to understand it all, however, in the precision section he mentions that 17 digits are enough to recover a double precision binary number. However, that’s not quite correct – 17 significant digits are required, as 12345678901234567 and 000000000012345678901234567 are the same number.

Here’s what we’ll test (also making sure that the whole string is read):

Input Expected
12345678901234567 12345678901234567
000000000012345678901234567 12345678901234567
12345678901234567890 12345678901234567000
1.2345678901234567 1.2345678901234567
0.00000000012345678901234567 0.00000000012345678901234567
1.00000000012345678901234567 1.0000000001234567
1234567890.00000000001234567 1234567890

Underflow/Overflow

What happens when the value is too small (as in very close to zero, not as in a negative number is outside of the valid range) or too large to represent?

System.Double.Parse makes numbers that are too small to be represented by double silently underflow into zero. This also happens when converting a very small double to float. However, if the number is outside the range of double then System.Double.Parse throws a System.OverflowException. This doesn’t make sense to me, especially since casting a big double to float will convert it to infinity. In this situation, strtod returns HUGE_VAL and this is the route I’ll take – numbers that are too big to fit inside the range of a double will be returned as +/- infinity and numbers that are very close to zero that double cannot represent will be truncated to zero.

Therefore, our tests will make sure the following happen (again making sure all input is read):

Input Expected
+4.9406564584124654E-324 4.9406564584124654E-324
+1.7976931348623157E+308 1.7976931348623157E+308
-4.9406564584124654E-324 -4.9406564584124654E-324
-1.7976931348623157E+308 -1.7976931348623157E+308
+1E-325 0
+1E+309 Infinity
-1E-325 0
-1E+309 -Infinity

Infinity/Not a Number

There’s an interesting point to take into consideration when parsing – the SVG specification seems to only allows numbers, yet in XML, INF, -INF and NaN are valid.

When parsing we’ll try to be as flexible as possible, so will allow "Inf", "Infinity" and "NaN" (all case-insensitive).

Valid Formats

The number section of the standard gives the following EBNF grammar for a valid number:

integer ::= [+-]? [0-9]+
number  ::= integer ([Ee] integer)?
            | [+-]? [0-9]* "." [0-9]+ ([Ee] integer)?

What’s interesting about this is that numbers with a trailing decimal point are invalid (i.e 0. doesn’t match the grammar). We’ll assume that’s an oversight and allow it (System.Double.Parse and strtod have no problems with it.) However, we need to be careful that a single decimal point is not parsed.

Testing this is a bit more involved, as strtod will parse as much of the input as it can, so while 0e++0 looks invalid, our function should be able to parse the first zero and then stop when it gets to the e. To test this we therefore need to make sure that our function does not consume the whole string, just the first few characters.

The Code

Think that’s all for now. Here’s the test cases; the actual class will follow later.

Eventually I’d like to allow for different culture settings, but for now I’m concentrating on the SVG spec.