0

I have a single application that loads dynamicaly the three following solutions:

 - SolutionA which references
                 X.dll version 3
                 Z.dll version 1 which references
                                       X.dll version 1

 - SolutionB which references
                 X.dll version 2

 - SolutionC which references
                 X.dll version 1

.

X.dll contains some XAML (depending on the DLL version I change the text, the background and the foreground) :

<UserControl x:Class="X.MainWindow"
             Background="DodgerBlue">
    <UserControl.Content>
        <Label Foreground="Black" Content="version 1" />
    </UserControl.Content>
</UserControl>

.

Z.dll also contains some XAML that uses X.dll :

<UserControl x:Class="Z.ZMainWindow">
    <StackPanel>
        <X:MainWindow />
    </StackPanel>
</UserControl>

.

SolutionA displays X version 3 and Z version 1 (which displays X version 1)

SolutionB displays X version 2

SolutionC displays X version 1

.

What I want is to always use the Higher version of the Assembly, which mean that SolutionA, SolutionB and SolutionC must always use X.dll in version 3.

Here is the code I use for AssemblyResolve:

private static Assembly OnAssemblyResolveWithDllPaths(object sender, ResolveEventArgs args)
{
    try
    {
        AssemblyName parsedName = new AssemblyName(args.Name);
        Version currentVersion = parsedName.Version;
        string currentName = parsedName.Name;
        string currentCulture = parsedName.CultureName;
        byte[] currentPublicKeyToken = parsedName.GetPublicKeyToken();
        string assemblyPath = string.Empty;

        if (loadedAssemblies.FirstOrDefault(a => a == args.Name) != null)
        {
            // Assembly has already been loaded
            return null;
        }

        List<string> possibleAssembliesPaths = m_dllPaths.Where(d => d.Contains(parsedName.Name)).ToList();

        if (possibleAssembliesPaths != null && possibleAssembliesPaths.Count > 0)
        {
            if (possibleAssembliesPaths.Count == 1)
            {
                assemblyPath = possibleAssembliesPaths[0];
            }
            else
            {
                foreach (string possibleAssembly in possibleAssembliesPaths)
                {
                    if (File.Exists(possibleAssembly))
                    {
                        AssemblyName possibleAssemblyName = AssemblyName.GetAssemblyName(possibleAssembly);
                        Version possibleVersion = possibleAssemblyName.Version;
                        string possibleName = possibleAssemblyName.Name;
                        string possibleCulture = possibleAssemblyName.CultureName;
                        byte[] possiblePublicKeyToken = possibleAssemblyName.GetPublicKeyToken();

                        if (currentName == possibleName 
                            && currentCulture == possibleCulture 
                            && currentPublicKeyToken.SequenceEqual(possiblePublicKeyToken) 
                            && currentVersion < possibleVersion)
                        {
                            assemblyPath = possibleAssembly;
                            currentVersion = possibleAssemblyName.Version;
                            currentName = possibleAssemblyName.Name;
                            currentCulture = possibleAssemblyName.CultureName;
                            currentPublicKeyToken = possibleAssemblyName.GetPublicKeyToken();
                        }
                    }
                }
            }

            if (!string.IsNullOrEmpty(assemblyPath))
            {
                loadedAssemblies.Add(args.Name);
                return Assembly.LoadFrom(assemblyPath);
            }
        }
    }
    catch
    {
        return null;
    }

    return null;
}

.

Everything works perfectly until in name my controls

i.e. (in Z.dll) : <Label Foreground="Black" Content="version 1" /> becomes <Label Foreground="Black" Content="version 1" x:Name="LabelV1" />

and (in X.dll) : <X:MainWindow x:Name="XMainWindow" /> becomes <X:MainWindow x:Name="XMainWindow" />

At this points, SolutionA has an exception and is not displayed when SolutionA is loaded before SolutionC (SolutionB is never a problem and as soon as SolutionC is loaded before SolutionA, everything works perfectly).

What I see, when I am attached to AppDomain.CurrentDomain.AssemblyLoad += CurrentDomain_AssemblyLoad is that the XAMLs automaticaly loads the Assembly they need :

SolutionC's XAML loads X in version 1
SolutionA's XAML loads X in version 3
SolutionA's XAML loads Z in version 1

Then I see the following exception in the xaml.cs:

An exception of type 'System.Exception' occurred in PresentationFramework.dll but was not handled in user code
Additional information: The component 'X.MainWindow' does not have a resource identified by the URI '/X;component/mainwindow.xaml'.

and the following one in the xaml:

Exception thrown: 'System.Windows.Markup.XamlParseException' in PresentationFramework.dll
Additional information: 'The invocation of the constructor on type 'X.MainWindow' that matches the specified binding constraints threw an exception.' Line number '10' and line position '10'.

.

Do you have leads to avoid the issue ?

  • Can't you use the [`/configuration/runtime/assemblyBinding/dependentAssembly`](https://msdn.microsoft.com/en-us/library/7wd6ex19.aspx) entry in your app.config? – Rubens Farias Sep 30 '15 at 12:18
  • The example above is a minor one, because the main application loads many other solutions (a lot) dynamically and the Assemblys that are loaded in different verions are countless (maybe a hundred). In this example there is only two nestings but in the whole application I can have more than 10 of those. Would it still be possible to use the /configuration/runtime/assemblyBinding/dependentAssembly automatically (via the code and not manually everytime a new version comes out) ? – Raphael Serievic Sep 30 '15 at 15:23

0 Answers0