Prism assembly reference failure: System.Windows.Interactivity

Ryan Norbauer picture Ryan Norbauer · Mar 10, 2012 · Viewed 21.2k times · Source

I have C#/WPF Prism (v4.0) app that has a persistent problem loading/resolving the System.Windows.Interactivity dll that comes with the Prism library. I've been working for three days straight trying to debug/solve this problem. I've learned a ton about .Net assembly resolution, but no luck so far on my problem, so I thought I'd turn to the StackOverflow community in a desperate plea for help. :)

I have a module running as part of a larger Prism app, which needs to reference System.Windows.Interactivity in order to add behaviors. Thus I have a XAML user control specifying the namespace as follows:

<UserControl x:Class="MyApp.Modules.SourcesModule.myView"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity">

And then I am trying to set a behavior on a child element of that UserControl as follows:

<ListBox Name="myListBox">
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="SelectionChanged">
            <i:InvokeCommandAction Command="{Binding SomeCommandOrOther}"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>
</ListBox>

Oddly, the project builds fine, and when typing in the associate code-behind file and I can even get Intellisense auto-completion for objects in the System.Windows.Interactivity namespace.

However, at runtime only, I get a XamlParseException on the above ListBox element.

Could not load file or assembly 'System.Windows.Interactivity, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The system cannot find the file specified. 

The InnerException is of the type System.IO.FileNotFoundException

"Could not load file or assembly 'System.Windows.Interactivity, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The system cannot find the file specified.":"System.Windows.Interactivity, PublicKeyToken=31bf3856ad364e35"

...which, as I have learned from reading about assembly resolutions, usually suggests a problem resolving a strongly-named assembly rather than merely an inability to find the dll on disk (as the exception type would suggest).

The Fusion log information is as follows, including warning about partial binding for the assembly in question:

=== Pre-bind state information ===
LOG: User = aricebo-array\me
LOG: DisplayName = System.Windows.Interactivity, PublicKeyToken=31bf3856ad364e35
 (Partial)
WRN: Partial binding information was supplied for an assembly:
WRN: Assembly Name: System.Windows.Interactivity, PublicKeyToken=31bf3856ad364e35 | Domain ID: 1
WRN: A partial bind occurs when only part of the assembly display name is provided.
WRN: This might result in the binder loading an incorrect assembly.
WRN: It is recommended to provide a fully specified textual identity for the assembly,
WRN: that consists of the simple name, version, culture, and public key token.
WRN: See whitepaper http://go.microsoft.com/fwlink/?LinkId=109270 for more information and common solutions to this issue.
LOG: Appbase = file:///C:/Users/me/Documents/Development Projects/Desktop apps/Prism/MyApp/Src/MyApp/bin/Debug/
LOG: Initial PrivatePath = NULL
Calling assembly : PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35.
===
LOG: This bind starts in default load context.
LOG: No application configuration file found.
LOG: Using host configuration file: 
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework\v4.0.30319\config\machine.config.
LOG: Policy not being applied to reference at this time (private, custom, partial, or location-based assembly bind).
LOG: Attempting download of new URL file:///C:/Users/me/Documents/Development Projects/Desktop apps/Prism/MyApp/Src/MyApp/bin/Debug/System.Windows.Interactivity.DLL.
LOG: Attempting download of new URL file:///C:/Users/me/Documents/Development Projects/Desktop apps/Prism/MyApp/Src/MyApp/bin/Debug/System.Windows.Interactivity/System.Windows.Interactivity.DLL.
LOG: Attempting download of new URL file:///C:/Users/me/Documents/Development Projects/Desktop apps/Prism/MyApp/Src/MyApp/bin/Debug/System.Windows.Interactivity.EXE.
LOG: Attempting download of new URL file:///C:/Users/me/Documents/Development Projects/Desktop apps/Prism/MyApp/Src/MyApp/bin/Debug/System.Windows.Interactivity/System.Windows.Interactivity.EXE.

Interestingly, if I look at my built project using the IL disassembler (ildasm.exe), System.Windows.Interactivity is not listed in the manifest as one of the referenced assemblies, though the other referenced Prism dlls show up there just fine. For example:

.assembly extern Microsoft.Practices.Prism
{
  .publickeytoken = (31 BF 38 56 AD 36 4E 35 )                         // 1.8V.6N5
  .ver 4:0:0:0
}
.assembly extern Microsoft.Practices.Unity
{
  .publickeytoken = (31 BF 38 56 AD 36 4E 35 )                         // 1.8V.6N5
  .ver 2:0:414:0
}

This problem is similar to the one mentioned in this other StackOverflow question: Referencing the correct System.Windows.Interactivity dll from Prism application. However, I am following the prescribed solution mentioned there (i.e., using the Prism version of System.Windows.Interactivity), to no avail. Just for fun, I have also tried using the System.Windows.Interactivity dlls that come with both the Expression Blend 3 and 4 SDKs (separately of course), but no luck with those either.

I'm not doing anything differently in how I've loaded the System.Windows.Interactivity dll from how I've loaded all the other dlls that come with the Prism library (they all reside in a /lib folder in my solution, and I've added them using the "Add reference" > "Browse" menu in Visual Studio 2010 and pointing to those dlls on disk sitting all together in one directory.)

Any leads on where to turn next would be most appreciated! Many thanks.

Answer

Ryan Norbauer picture Ryan Norbauer · Mar 11, 2012

At last, I found the answer!

When DLLs in Prism modules are referenced, the .NET assembly resolution mechanism looks for the referenced assemblies in the /bin folder of the hosting application (i.e., the one with the Shell and Bootstrapper) rather than in the module's bin directory (assuming you have set up your modules as separate projects in the solution, as I have).

By coincidence, my hosting application happened to reference all the other Prism DLLs, so when the modules referenced those, it just found them in the hosting application's bin directory. However, my hosting application never referenced System.Windows.Interactivity, so adding it just to my module meant there was no such DLL to be found in the hosting applications /bin directory. The DLL is in fact being copied to the /bin directory of the module, but some quirk of the way assembly resolution works with Prism applications means that the app never checks for assemblies in that folder.

So, in short: referenced assemblies in Prism applications apparently need to reside in the /bin folder of the hosting application.

I'm going to look at some means of using configuration to make this work more cleanly and intelligently, but the core of the problem has at least been uncovered.