How to force WPF to use resource URIs that use assembly strong name? Argh!

Viewed 7719

O.k, this is really irritating, I had noticed previously that the code generated by WPF for loading XAML resources did not appear to use strong names and therefore may be problematic for scenarios where you need to support side by side versions of WPF assemblies.

This has turned out to be the case, and it's now causing me problems - I have a plug-in system which is supposed to support side by side installation of plugins which differ only in their version numbers (their assembly versions). This of course can be supported by .NET since assemblies are determined to have different identities even if they have the same DLL filename, provided that they are strongly named and either have a different public/private key OR have a different assembly version number.

Now, if we look at the code generated for windows and usercontrols by visual studio, we see in the auto-generated file the following:

/// <summary>
/// InitializeComponent
/// </summary>
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
public void InitializeComponent() {
    if (_contentLoaded) {
        return;
    }
    _contentLoaded = true;
    System.Uri resourceLocater = new System.Uri("/Sensormatic.AMK1000.Panel;component/views/servicepanelui.xaml", System.UriKind.Relative);

    #line 1 "..\..\..\Views\ServicePanelUI.xaml"
    System.Windows.Application.LoadComponent(this, resourceLocater);

    #line default
    #line hidden
}

Notice the line where the resource locater is created - it is using a relative URI which does not specify the strong name or the version of the assembly which contains the xaml resource.

I thought maybe LoadComponent would check the calling assembly's identity and use it's public key and version details or perhaps check the identity of the assembly which contains the type for the 'this' parameter.

It appears this is not the case - if you have two assemblies with different version numbers (but the same filename) then you can get an IOException with the message "Cannot locate resource X" (for above example "Cannot locate resource 'views/servicepanelui.xaml'.

Worse, I'm pretty sure that this is also going to mean that assemblies with the same filename but different public/private key, i.e. from different publishers, will also result in this error.

So, does anyone know how to get around this? How to make WPF strong name compliant.

Note, as far as I'm concerned this is a WPF bug. You shouldn't have to use Appdomain isolation just to avoid this.

7 Answers

We also had the same problem, but we had to set the assembly version for some specific projects in our solution only.

Because I liked the idea of setting the version number for the build like user195275 recommended, I did some research of how do do it for a single csproj file.

So in combination with the following thread How to read the assemblyversion from assemblyInfo.cs? We came up with the following solution:

<Target Name="BeforeBuild">
    <ReadLinesFromFile File="$(MSBuildProjectDirectory)\Properties\AssemblyInfo.cs">
        <Output TaskParameter="Lines"
                ItemName="ItemsFromFile"/>
    </ReadLinesFromFile>

    <PropertyGroup>
        <Pattern>\[assembly: AssemblyVersion\(.(\d+)\.(\d+)\.(\d+)\.(\d+)</Pattern>
        <In>@(ItemsFromFile)</In>
        <Out>$([System.Text.RegularExpressions.Regex]::Match($(In), $(Pattern)))</Out>
    </PropertyGroup>

    <CreateProperty Value="$(Out.Remove(0, 28))">
        <Output TaskParameter="Value" PropertyName="AssemblyVersion"/>
    </CreateProperty>
</Target>

what it does: It parses the version number out of the AssemblyInfo.cs and set it as Property as in Aaron Martens answer. Which leads to a single point of maintenance for the version number for us.

Related