Tags

, , , , , ,


Today I came across an interesting StackOverflow question.

A developer wrote an ICommand implementation in a .NET Portable Subset library, and tried to include this in a WPF project.

This resulted in MSBuild asking him to include System.Windows v2.0.5.0

At first this seems wrong, since ICommand now lives under the System assembly. So I used ILDasm to look at the Manifest of his generated assembly, and find a reference to System.Windows v2.0.5.0

Portable Class Manifest

Portable Class Manifest

The first reaction of the community was to complain and say that there should be a TypeForwarder for ICommand in System.Windows, yet this is not totally correct, since they were thinking of System.Windows v4.0.0.0, not v2.0.5.0.

..and in fact, if you disassemble System.Windows v4.0.0.0, you do find a correctly implemented TypeForwarder for ICommand.

ICommand TypeForwarder

ICommand TypeForwarder

But the problem is, that since the manifest declares v2.0.5.0, MSBuild goes to look for ICommand in System.Windows, finds that it is not referenced, and complains.

This is correct behaviour.

The Solution

The solution to this is a bit tricky, and requires one to understand how MSBuild pieces things together.

First of all, although if we ‘Add Reference’, Visual Studio only shows us assemblies targeting our framework, this does not mean that we cannot directly reference older assemblies.

So, the first step, is to find v2.0.5.0 of System.Windows (you can find it in the .NET Portable folder), and copy it to our local lib folder.

Why do we do this? Simple, because if we are targeting .NET v4 or other, we cannot assume that the user has all the other assemblies already.

Once we do this, we can add a direct reference to System.Windows v2.0.5.0

But lo and behold, MSBuild is still not happy… now he complains that we have TWO ICommand implementations, one in System v4.0.0.0 and one in System.Windows v2.0.5.0, and both under the same namespace.

So what do we do?

MSBuild has a concept of ‘aliases’.  Every assembly falls under one or more aliases, and by default, all assemblies fall under the ‘global’ alias.

So what we do to solve this, is that we remove System.Windows from the global alias, and give it a custom alias… like so:

  • Select the System.Windows reference in your project, and select properties (or hit F4)
  • In the ‘Alias’ property, remove ‘global’, and add a custom alias, ex. ‘SomeAlias’
Add an alias to your assembly

Add an alias to your assembly

  • Next, reference your type using this alias… this telling MSBuild that you want THIS implementation, and not the one in System
    • do this by defining the ‘extern alias SomeAlias’ outside your class, and referencing it directly… like so
Using extern alias

Using extern alias

And voila, problem solved, we can now compile happily (although it looks like ReSharper does not know about aliases, and will complain)

For reference, the StackOverflow post can be found here.

 

Advertisements