Sometime back I had blogged about AppDomains in WPF and also later updated this with another blog which mentioned the usage of Dispatcher to shutdown the AppDomain.
Recently in a project where we had to use AppDomain to launch a WPF application, we ran into issues when we had the application refer to external assembly for say some of the controls it was using. Confused? Let's take an example. I have a WPF application DummyApp.exe and a WPF User Control assembly WpfControlLibrary.dll. Now DummyApp uses user controls from this WpfControlLibrary.dll in some of its XAMLs. Finally, I launch this DummyApp.exe from my another WPF application (call it Tester.exe) in a new AppDomain.
When I do this, i get a System.Windows.Markup.XamlParseException with message as - "Cannot find type 'WpfControlLibrary.UserControl1'. The assembly used when compiling might be different than that used when loading and the type is missing. Error at object 'grid1' in markup file 'DummyApp;component/window1.xaml' Line 8 Position 10.", where grid1 is the Grid control in a XAML in the DummyApp's window1.xaml file. The WpfControlLibrary.dll is however present in the same folder as is DummyApp.exe.
Searching online we found this on the WPF Forums (and also here). This is a pretty old issue but also has some recent updates. Looks like the issue still exists. The solutions that are mentioned there
1. Ensure assembly version isn't using the 1.0.* syntax, wasn't valid for me, since the assembly version was already set to 22.214.171.124
2. Add a reference to the WpfControlLibrary.dll in Tester.exe, didn't make sense since we would be using this Tester.exe to launch any external WPF application. We can't go about adding references to all such assemblies.
3. Another option was to just copy the WpfControlLibrary.dll to the path where the Tester.exe was running from. This was something I could do, but then isn't an elegant solution.
However points 2 and 3 clearly point to the fact that the issue is related to not being able to load the WpfControlLibrary.dll and hence the failure to load the UserControl1. The failure to load the assembly will happen if the assembly is not found in the path that is being used for assembly probing and hence copying it locally to the Tester.exe's path confirms that, that really is the case. So the summary is that the new AppDomain that is created is using the same path as that is for Tester.exe and hence the loading of other assemblies fail, even though they are present in the same path as DummyApp.exe.
Checking the documentation on AppDomain.CreateDomain, we realized that there is a flavor of contructor that takes in the a parameter to set the appbasepath, which is essentially the path that the assembly resolved uses to probe for assemblies. This path can also be setup by using the AppDomainSetup class and passed as a parameter when creating the appdomain. So that's what we finally did as below and the DummyApp.exe loaded without any more issues.
AppDomainSetup setup = new AppDomainSetup();
setup.ApplicationBase = @"D:\VS2008\WPF\DummyApp\bin\Debug";
ad = AppDomain.CreateDomain("test", null, setup);
We also found this where is clearly says that ApplicationBase is the most important property one should set before working with AppDomains. No wonder, reading documentation upfront helps minimize errors later !