Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reflecting over assemblies causes Unity to require Microsoft.Practices.ServiceLocation

We typically only reference Microsoft.Practices.Unity.dll in our applications. We're only using basic capabilities, and this works fine. In one application, the act of using reflection is causing Unity to require another DLL.

For example, create a console app and reference only Microsoft.Practices.Unity (file version 2.0.414.0). Enter the following code and run it:

class Program
{
    static void Main()
    {
        using (var container = new UnityContainer())
        {
            container.RegisterType<IDoSomething, ConcreteDoSomething>();

            var thing = container.Resolve<IDoSomething>();

            thing.DoSomething();
            Console.WriteLine();

            LoadSchemaLoaders();
        }
    }

    public static void LoadSchemaLoaders()
    {
        var type = typeof(ISchemaLoader);

        try
        {
            // Get all loaded assemblies, including Unity.
            // Get all of the types.
            // Filter for types that ISchemaLoader (custom type) can be assigned from.

            var types = AppDomain.CurrentDomain.GetAssemblies()
                .SelectMany(s => s.GetTypes())
                .Where(c => type.IsAssignableFrom(c) && c.IsClass && !c.IsAbstract && !c.IsGenericParameter);

            Console.WriteLine("Got here...");

            types.FirstOrDefault();
        }
        catch (ReflectionTypeLoadException ex)
        {
            Console.WriteLine(ex.Message);

            foreach (Exception exSub in ex.LoaderExceptions)
            {
                Console.WriteLine(exSub.Message);
            }
        }
    }
}

public interface IDoSomething
{
    void DoSomething();
}

public class ConcreteDoSomething : IDoSomething
{
    public void DoSomething()
    {
        Console.WriteLine("Something!");
    }
}

public interface ISchemaLoader {}

On my machine, the output is:

Something!

Got here...
Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information.
Could not load file or assembly 'Microsoft.Practices.ServiceLocation, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The system cannot find the file specified.

Now comment out the line

LoadSchemaLoaders();

Run it again and it works.

This is a simplified version of production code. The production code is actually dynamically loading custom types that implement an interface. As soon as we introduced Unity, the code threw an exception. But Unity types can't implement our interface!

I don't understand how simply reflecting over the assembly is causing the core Unity assembly to require another dependency.

like image 773
TrueWill Avatar asked Apr 06 '12 22:04

TrueWill


Video Answer


1 Answers

A type in the Unity assembly from an interface defined in Microsoft.Practices.ServiceLocation (probably IServiceLocator).

The compiler doesn't require your application to reference that dll directly...but reflecting over the System.Type object will try to load the dll referenced by Unity.

The reason this only happens when you reflect over the assembly is because Unity probably doesn't load the type that references Microsoft.Practices.ServiceLocation under normal circumstances.

As a work-around, you could enclose your Assembly.GetTypes() call in a try/catch block.

Alternatively, if you put the Microsoft.Practices.ServiceLocation dll in a location where your application can find it, that should resolve the issue as well.

like image 169
Jeff Avatar answered Sep 23 '22 02:09

Jeff