Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unity fails to resolve basic dependency chain

I'm implementing dynamic loading and registration of my assemblies in Unity IoC.

Given these classes:

public interface IA { }
public interface IB { }
public interface IC { }

public class A : IA { }
public class B : IB
{
    public B(IA a) { }
}

public class C : IC
{
    public C(IB b) { }
}

And this configuration:

var assembly = Assembly.LoadFile(@"path\MyAsm.dll");
container.RegisterTypes(
    AllClasses.FromAssemblies(assembly),
    WithMappings.FromAllInterfacesInSameAssembly,
    WithName.Default,
    WithLifetime.Transient);

The code:

var c = container.Resolve(typeof(IC));

Throws:

A first chance exception of type 'Microsoft.Practices.Unity.ResolutionFailedException' occurred in Microsoft.Practices.Unity.dll

Additional information: Resolution of the dependency failed, type = "MyAsm.IC", name = "(none)".

Exception occurred while: while resolving.

Exception is: InvalidOperationException - The type IC does not have an accessible constructor.


At the time of the exception, the container was:

MyAsm.IC,(none)

All of the above code is performed in the same assembly MyAsm. Analyzing the container in debug, the Registrations property lists what seems to be proper collection of mappings of A, B and C to their respective interfaces as well as themselves.

Any ideas?

SOLUTION

After Tyler's response I changed:

var assembly = Assembly.LoadFile(@"path\MyAsm.dll");

to

var assembly = Assembly.LoadFrom(@"path\MyAsm.dll");

which solved the issue. These two methods on Assembly have same argument and same return type and vary just slightly in behavior. Pure evil.

like image 993
Jacek Gorgoń Avatar asked Mar 03 '14 23:03

Jacek Gorgoń


1 Answers

I was able to reproduce the error you are getting.

So you are loading the assembly from a file Assembly.LoadFile(@"path\MyAsm.dll");, and then you are resolving a hard referenced type container.Resolve(typeof(IC));. I believe those types are coming from two different compiled binaries. The types from the binary in @"path\MyAsm.dll" are loaded into the container, but you are attempting to resolve the type of the binary from your application path's bin directory (Referenced assembly CopyLocal is set to True).

Either you need to register the types from the referenced binary that is already loaded in the app domain or you need to resolve the type from the loaded binary using reflection to find the type.

var assembly = AppDomain.CurrentDomain.GetAssemblies().
               SingleOrDefault(asm => asm.GetName().Name == "MyAsm");
...
var c = container.Resolve(typeof(IC));

--or--

var assembly = Assembly.LoadFile(@"path\MyAsm.dll");
...
var c = container.Resolve(assembly.GetType("MyAsm.IC"));
like image 112
TylerOhlsen Avatar answered Oct 17 '22 05:10

TylerOhlsen