When creating a StructureMap container, I typically do something like this:
var container = new Container(registry => {
registry.AddRegistry<MyRegistry>();
});
Where
public class MyRegistry : Registry {
public MyRegistry() {
Scan(x => {
x.Assembly("My.Assembly.Name");
x.RegisterConcreteTypesAgainstTheFirstInterface();
}
}
}
However, this has resulted in quite many registry.AddRegistry lines in a bootstrapper file, which is then copied into many projects. I would like to be able to call a method taking a constructed container and adding a registry to it, so I can modularize libraries.
I came up with this:
public static void Setup(ref Container container) {
container.PluginGraph.ImportRegistry(typeof(MyRegistry));
}
This works, in that the registry is properly added to the container (seen by calling container.WhatDoIHave() before and after), but it seems the actual mappings are not done - ie the interface IFoo is not registered to concrete class Foo that both are defined in My.Assembly.Name.
What is the difference in doing ImportRegistry and AddRegistry? Can my Setup method be fixed?
Did you try Container.Configure()? It exists to configure a container after it has already been initialized.
Related
How do I configure dependency injection in ASP.NET Core to return a certain instance depending on the type it's being injected into?
Let's say I have a simple interface,
public interface IHello
{
string SayHello();
}
And two different implementations:
public class Hello : IHello
{
public string SayHello() => "Hello...";
}
public class Hey : IHello
{
public string SayHello() => "HEY!";
}
And finally I have a few classes that all depend on an instance of IHello:
public class Class1
{
public Class1(IHello hello)
{
}
}
public class Class2
{
public Class2(IHello hello)
{
}
}
Now, in ConfigureServices I would do something like this:
services.AddSingleton<IHello, Hello>();
to configure any class depending on IHello to always get the same instance of Hello.
BUT: What I really want is for Class1 to always get the same singleton instance of Hey and all other classes should just get an instance of Hello. It could look like this in ConfigureServices (doesn't work, obviously):
services.AddSingleton<IHello, Hello>();
services.AddSingleton<IHello, Hey, Class1>(); // Doesn't work, but would be neat if it did...
Here's a simple approach. It lacks a certain elegance, but it will do what you need:
public static void Register(IServiceCollection serviceCollection)
{
serviceCollection.AddSingleton<Hello>();
serviceCollection.AddSingleton<Hey>();
serviceCollection.AddSingleton<ClassThatDependsOnIHello1>(serviceProvider =>
new ClassThatDependsOnIHello1(serviceProvider.GetService<Hello>()));
serviceCollection.AddSingleton<ClassThatDependsOnIHello2>(serviceProvider =>
new ClassThatDependsOnIHello2(serviceProvider.GetService<Hey>()));
}
There are two classes that depend on IHello. The registration for each of them includes a function. That function resolves either Hello or Hey from the service provider and passes it to the constructor of each respective class. That way you get control over which implementation gets passed to which class.
(It's beside the point that the service provider hasn't been built yet. The function you're providing will be executed later, and the service provider passed to it will be the one that has been built from the service collection.)
A downside to this is that now your DI registration explicitly calls your constructors. That can be a nuisance because if the constructors change (maybe you inject other dependencies) then you'll have to edit this code. That's not great, but it's not uncommon.
Plan B would be to do as Microsoft suggests and use another container.
Autofac
First, add the Autofac.Extensions.DependencyInjection NuGet package. This references Autofac and also provides the extensions needed to add an Autofac container to a service collection.
I've arranged this to focus on the way dependencies get registered with Autofac. It's similar to IServiceCollection and IServiceProvider. You create a ContainerBuilder, register dependencies, and then build a Container from it:
static void RegisterDependencies(this ContainerBuilder containerBuilder)
{
containerBuilder.RegisterType<Hello>().Named<IHello>("Hello");
containerBuilder.RegisterType<Hey>().Named<IHello>("Hey");
containerBuilder.RegisterType<ClassThatDependsOnIHello1>().WithParameter(
new ResolvedParameter((parameter, context) => parameter.ParameterType == typeof(IHello),
(parameter, context) => context.ResolveNamed<IHello>("Hello")
));
containerBuilder.RegisterType<ClassThatDependsOnIHello2>().WithParameter(
new ResolvedParameter((parameter, context) => parameter.ParameterType == typeof(IHello),
(parameter, context) => context.ResolveNamed<IHello>("Hey")
));
}
That's not really pretty either, but it sidesteps the problem of calling the constructors.
First it registers two implementations of IHello and gives them names.
Then it registers the two classes that depend on IHello. WithParameter(new ResolvedParameter()) uses two functions:
The first function determines whether a given parameter is the one we want to resolve. So in each case we're saying, "If the parameter to resolve is IHello, then resolve it using the next function."
It then resolves IHello by specifying which named registration to use.
I'm not excited by how complicated that is, but it does mean that if those classes have other dependencies injected, they'll be resolved normally. You can resolve ClassThatDependsOnIHello1 without actually calling its constructor.
You can also do it without the names:
static void RegisterDependencies(this ContainerBuilder containerBuilder)
{
containerBuilder.RegisterType<Hello>();
containerBuilder.RegisterType<Hey>();
containerBuilder.RegisterType<ClassThatDependsOnIHello1>().WithParameter(
new ResolvedParameter((parameter, context) => parameter.ParameterType == typeof(IHello),
(parameter, context) => context.Resolve<Hello>()
));
containerBuilder.RegisterType<ClassThatDependsOnIHello2>().WithParameter(
new ResolvedParameter((parameter, context) => parameter.ParameterType == typeof(IHello),
(parameter, context) => context.Resolve<Hey>()
));
containerBuilder.RegisterType<SomethingElse>().As<ISomethingElse>();
}
We can clean that up some with an method that simplifies creating that ResolvedParameter because that's so hideous.
public static ResolvedParameter CreateResolvedParameter<TDependency, TImplementation>()
where TDependency : class
where TImplementation : TDependency
{
return new ResolvedParameter((parameter, context) => parameter.ParameterType == typeof(TDependency),
(parameter, context) => context.Resolve<TImplementation>());
}
Now the previous registration becomes:
containerBuilder.RegisterType<ClassThatDependsOnIHello1>().WithParameter(
CreateResolvedParameter<IHello, Hello>());
containerBuilder.RegisterType<ClassThatDependsOnIHello2>().WithParameter(
CreateResolvedParameter<IHello, Hey>());
Better!
That leaves the details of how you integrate it with your application, and that varies with your application. Here's Autofac's documentation which provides more detail.
For testing purposes you can do this:
public static IServiceProvider CreateServiceProvider()
{
var containerBuilder = new ContainerBuilder();
containerBuilder.RegisterDependencies();
var container = containerBuilder.Build();
return new AutofacServiceProvider(container);
}
I like to write unit tests for this sort of thing. This method will create an IServiceProvider from the Autofac container, and then you can test resolving things from the container to make sure they get resolved as expected.
If you prefer another container, see if it has similar integrations to use it with Microsoft's container. You might find one you like better.
Windsor
Here's a similar example using Castle.Windsor.MsDependencyInjection.
public static class WindsorRegistrations
{
public static IServiceProvider CreateServiceProvider(IServiceCollection serviceCollection)
{
var container = new WindsorContainer();
container.RegisterDependencies();
return WindsorRegistrationHelper.CreateServiceProvider(container, serviceCollection);
}
public static void RegisterDependencies(this IWindsorContainer container)
{
container.Register(
Component.For<Hello>(),
Component.For<Hey>(),
Component.For<ClassThatDependsOnIHello1>()
.DependsOn(Dependency.OnComponent<IHello, Hello>()),
Component.For<ClassThatDependsOnIHello2>()
.DependsOn(Dependency.OnComponent<IHello, Hey>())
);
}
}
There are two things I like about this:
It's so much easier to read! When resolving ClassThatDependsOnIHello2, fulfill the dependency on IHello with Hey. Simple.
This - WindsorRegistrationHelper.CreateServiceProvider(container, serviceCollection) - allows you to register dependencies with the IServiceCollection and include them in the service provider. So if you have existing code that registers lots of dependencies with IServiceCollection you can still use it. You can register other dependencies with Windsor. Then CreateServiceProvider mixes them all together. (Maybe Autofac has a way to do that too. I don't know.)
I am configuring AutoMapper to map domain objects from / to the view model ones in a Asp.Net MVC5 application with Autofac 4.3, Autofac.Owin 4, Autofac.Mvc5 4, AutoFac.Mvc5.Owin 4 and AutoMapper 5.2.
I did decide to create one AutoMapper profile per domain entity like the followin leaving only the constructor with no parameters because I want to set the profile's name.
Note: this code is in assembly A.
public partial class DoctorsMappingProfile : Profile
{
#region Constructors
public DoctorsMappingProfile() : base(typeof(DoctorsMappingProfile).FullName)
{
// Code of mapping removed because it is not part of the problem
}
#endregion Constructors
}
To register AutoMapper and the profiles I followed this and this guides well explained by the user mpetito there and that it works as the user has checked here. My code in the Startup partial class is this:
Note1: this code is in assembly B which references assembly A.
Note2: I perfom assembly scanning of registered assemblies, then I pass as paramerter the array of scanned assemblies to the method RegisterAssemblyTypes of ContainerBuilder
public partial class Startup
{
#region Methods
public void ConfigureAutoFacContainer(IAppBuilder app)
{
var builder = new ContainerBuilder();
builder.RegisterControllers(typeof(MvcApplication).Assembly);
builder.RegisterFilterProvider();
builder.RegisterSource(new ViewRegistrationSource());
// TODO: Logger!
var assemblies = BuildManager.GetReferencedAssemblies().Cast<Assembly>().ToArray();
this.ConfigureAutoMapper(builder, assemblies);
// TODO: Modules!
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
app.UseAutofacMiddleware(container);
app.UseAutofacMvc();
}
private void ConfigureAutoMapper(ContainerBuilder builder, Assembly[] registeredAssemblies)
{
//register your profiles, or skip this if you don't want them in your container
builder.RegisterAssemblyTypes(registeredAssemblies).AssignableTo(typeof(Profile)).As<Profile>(); //.UsingConstructor(typeof(string));
//register your configuration as a single instance
builder.Register(ctx => new MapperConfiguration(cfg =>
{
//add your profiles (either resolve from container or however else you acquire them)
foreach (var profile in ctx.Resolve<IEnumerable<Profile>>())
{
cfg.AddProfile(profile);
}
})).AsSelf().SingleInstance();
//register your mapper
builder.Register(ctx => ctx.Resolve<MapperConfiguration>()
.CreateMapper(ctx.Resolve))
.As<IMapper>()
.InstancePerLifetimeScope();
}
#endregion Methods
}
When de application runs and try to resolve the profile the following exception happens:
Autofac.Core.DependencyResolutionException
None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'AutoMapper.Configuration.MapperConfigurationExpression+NamedProfile' can be invoked with the available services and parameters: Cannot resolve parameter 'System.String profileName' of constructor 'Void .ctor(System.String, System.Action`1[AutoMapper.IProfileExpression])'.
the line of the error is the foreach loop when the context attempts to resolve the Profile:
foreach (var profile in ctx.Resolve<IEnumerable<Profile>>())
I believe it its due to the Autofac default constructor location convention it is looking for the constructor with most parameters, which is in case of the AutoMapper.Profile class:
protected Profile(string profileName, Action<IProfileExpression> configurationAction)
{
}
To fix this I replaced the line that looks for profiles, the first line of code in in ConfigureAutoMapper, forcing it to use the constructor with no parameters:
builder.RegisterAssemblyTypes(registeredAssemblies).AssignableTo(typeof(Profile)).As<Profile>().UsingConstructor();
but still it does not work.
Solutions / workaround I have found:
If I replace the class Profile by my DoctorsMappingProfile in method ConfigureAutoMapper it works but doing this will invalidate the assembly scanning for profiles.
Finally I managed it to work by creating a base abstract class inheriting from AutoMapper.Profile and referencing it in my ConfigureAutoMapper method of the Startup class, this way I can perform assembly scanning for that class' descendants...
Note: this code is in Assembly C
public abstract class G2AutoMapperProfile : Profile
{
#region Constructors
protected G2AutoMapperProfile()
{
}
protected G2AutoMapperProfile(string profileName) : base(profileName)
{
}
#endregion Constructors
}
Note: And this code is in assembly A
public partial class DoctorsMappingProfile : G2AutoMapperProfile //Profile
{
#region Constructors
public DoctorsMappingProfile() : base(typeof(DoctorsMappingProfile).FullName)
{
//removed because it is not part of the problem
}
#endregion Constructors
}
and finally, this is the code of ConfigureAutoMapper in assembly B, that works:
private void ConfigureAutoMapper(ContainerBuilder builder, Assembly[] registeredAssemblies)
{
//register your profiles, or skip this if you don't want them in your container
builder.RegisterAssemblyTypes(registeredAssemblies).AssignableTo(typeof(G2AutoMapperProfile)).As<G2AutoMapperProfile>();
//register your configuration as a single instance
builder.Register(ctx => new MapperConfiguration(cfg =>
{
//add your profiles (either resolve from container or however else you acquire them)
foreach (var profile in ctx.Resolve<IEnumerable<G2AutoMapperProfile>>())
{
cfg.AddProfile(profile);
}
})).AsSelf().SingleInstance();
//register your mapper
builder.Register(ctx => ctx.Resolve<MapperConfiguration>()
.CreateMapper(ctx.Resolve))
.As<IMapper>()
.InstancePerLifetimeScope();
}
... but still I don't understand why the original code is not working for me.
First, there's no need for you to explicitly call the protected constructor of Profile in your DoctorsMappingProfile. The reason is that the profileName you pass is the one used by default by AutoMapper as we can see here.
Also, regarding the first way you try to register your profiles in the Autofac container:
builder
.RegisterAssemblyTypes(registeredAssemblies)
.AssignableTo(typeof(Profile))
.As<Profile>()
.UsingConstructor(typeof(string));
This means that you explicitly ask Autofac to create instance of your Profile classes by using the constructor that has exactly one parameter that is of type string. The problem with that is Autofac has no idea what string it has to use in the constructor.
It's also wrong since you created a parameter-less constructor which in turn calls the parameterized constructor.
I'm not sure what calling UsingConstructor with no parameters does, but in my opinion, you'd be better off leaving Autofac choose the best constructor for you, especially when the defaut parameter-less one is the one you want it to use.
My feeling is reinforced by looking at the solution/workaround you provided. What you effectively did is:
create a base class that mimics exactly what Profile has, that is, a default parameter-less constructor and a constructor that takes a string
register the profiles in the Autofac container by not using UsingConstructor
So I'm quite sure that by:
getting rid of your custom base class
having your profiles inherit from Profile again
registering your profiles without using UsingConstructor
you should be fine.
If I put Lazy in constructor of my object, and X is not registered in container I got dependency resolution exception.
Why am I getting this exception? I dislike it, because I cannot choose component at runtime. Example usecase:
class Controller
{
public Controller(Lazy<A> a, Lazy<B> b) { /* (...) */ }
Lazy<A> a;
Lazy<B> b;
public IActionResult Get(){
if(someConfig)
return Json(a.Value.Execute());
else
return Json(b.Value.Execute());
}
}
To do so I need to register both components A an B. My program fails even if B is never used. I would like to have B be optional, and still managed by autofac.
This is even bigger issue if I have list of components, and want only one to be used. For example:
class Controller
{
Controller(IEnumerable<Component> components) { /* (...) */ }
IActionResult Get()
{
return components.First(n => n.Name == configuredComponent).Execute();
}
}
I am no longer getting exception is something is not registered, however still everything is constructed. Also it would be awkward to use.
If you add a reference to a Lazy<T> component, Autofac has to know (basically) how to create the internal function that will run should you want to resolve it, even if you don't resolve it.
Basically, it needs to be able to create this in memory:
var lazy = new Lazy<T>(() => scope.Resolve<T>());
Autofac requires all of the things you want to resolve to be registered. It doesn't let you register things on the fly - it must be explicit. So the thing you're trying to do won't work (as you saw).
Instead, use a single interface and two different implementations of that interface. Change the registration based on your configuration value.
var builder = new ContainerBuilder();
if(someConfig)
{
builder.RegisterType<A>().As<IService>();
}
else
{
builder.RegisterType<B>().As<IService>();
}
Then in your controller, inject the interface rather than the concrete class.
public MyController(Lazy<IService> service)
There are also other options you could do, like use metadata for components or keyed services. For example, you could add some metadata based on your configuration and resolve using that.
builder.RegisterType<A>()
.As<IService>()
.WithMetadata("Name", "a");
builder.RegisterType<B>()
.As<IService>()
.WithMetadata("Name", "b");
In the controller, you'd get a dictionary of them:
public MyController(IEnumerable<Meta<IService>> services)
{
var service = services.First(s => s.Metadata["Name"].Equals(someConfig);
}
That's a very short example, but the docs show a lot more.
In any case, the interface is really going to be your key to success. If you're just using concrete classes, they'll have to be registered whether you use them or not.
There are several questions on Stack Overflow that are similar but not exactly what I'm looking for. I would like to do Ninject binding based on a runtime condition, that isn't pre-known on startup. The other questions on Stack Overflow for dynamic binding revolve around binding based on a config file or some such - I need to it to happen conditionally based on a database value while processing the data for a particular entity. E.g.,
public class Partner
{
public int PartnerID { get; set; }
public string ExportImplementationAssembly { get; set; }
}
public interface IExport
{
void ExportData(DataTable data);
}
Elsewhere, I have 2 dlls that implement IExport
public PartnerAExport : IExport
{
private readonly _db;
public PartnerAExport(PAEntities db)
{
_db = db;
}
public void ExportData(DataTable data)
{
// export parter A's data...
}
}
Then for partner B;
public PartnerBExport : IExport
{
private readonly _db;
public PartnerBExport(PAEntities db)
{
_db = db;
}
public void ExportData(DataTable data)
{
// export parter B's data...
}
}
Current Ninject binding is;
public class NinjectWebBindingsModule : NinjectModule
{
public override void Load()
{
Bind<PADBEntities>().ToSelf();
Kernel.Bind(s => s.FromAssembliesMatching("PartnerAdapter.*.dll")
.SelectAllClasses()
.BindDefaultInterfaces()
);
}
}
So how do I set up the bindings such that I can do;
foreach (Partner partner in _db.Partners)
{
// pseudocode...
IExport exportModule = ninject.Resolve<IExport>(partner.ExportImplementationAssembly);
exportModule.ExportData(_db.GetPartnerData(partner.PartnerID));
}
Is this possible? It seems like it should be but I can't quite figure how to go about it. The existing binding configuration above works fine for static bindings but I need something I can resolve at runtime. Is the above possible or am I just going to have to bypass Ninject and load the plugins using old-school reflection? If so, how can I use that method to resolve any constructor arguments via Ninject as with the statically bound objects?
UPDATE: I've updated my code with BatteryBackupUnit's solution such that I now have the following;
Bind<PADBEntities>().ToSelf().InRequestScope();
Kernel.Bind(s => s.FromAssembliesMatching("PartnerAdapter.*.dll")
.SelectAllClasses()
.BindDefaultInterfaces()
.Configure(c => c.InRequestScope())
);
Kernel.Bind(s => s.FromAssembliesMatching("PartnerAdapter.Modules.*.dll")
.SelectAllClasses()
.InheritedFrom<IExportService>()
.BindSelection((type, baseTypes) => new[] { typeof(IExportService) })
);
Kernel.Bind<IExportServiceDictionary>().To<ExportServiceDictionary>().InSingletonScope();
ExportServiceDictionary dictionary = KernelInstance.Get<ExportServiceDictionary>();
Instantiating the export implementations within 2 test modules works and instantiates the PADBEntites context just fine. However, all other bindings in my services layer now no longer work for the rest of the system. Likewise, I cannot bind the export layer if I change PADBEntities variable/ctor argument to an ISomeEntityService component. It seems I'm missing one last step in configuring the bindings to get this work. Any thoughts?
Error: "Error activating ISomeEntityService. No matching bindings are available and the type is not self-bindable"
Update 2: Eventually got this working with a bit of trial and error using BatteryBackupUnit's solution though I'm not too happy with the hoops to jump thought. Any other more concise solution is welcome.
I changed the original convention binding of;
Kernel.Bind(s => s.FromAssembliesMatching("PartnerAdapter.*.dll")
.SelectAllClasses()
.BindDefaultInterfaces()
);
to the much more verbose and explicit;
Bind<IActionService>().To<ActionService>().InRequestScope();
Bind<IAuditedActionService>().To<AuditedActionService>().InRequestScope();
Bind<ICallService>().To<CallService>().InRequestScope();
Bind<ICompanyService>().To<CompanyService>().InRequestScope();
//...and so on for 30+ lines
Not my favorite solution but it works with explicit and convention based binding but not with two conventions. Can anyone see where I'm going wrong with the binding?
Update 3: Disregard the issue with the bindings in Update 2. It appears that I've found a bug in Ninject relating to having multiple binding modules in a referenced library. A change in module A, even though never hit via breakpoint will break a project explicitly using a different module B. Go figure.
It's important to note that while the actual "condition match" is a runtime condition, you actually know the possible set of matches in advance (at least on startup when building the container) - which is evidenced by the use of the conventions. This is what the conditional / contextual bindings are about (described in the Ninject WIKI and covered in several questions). So you actually don't need to do the binding at an arbitrary runtime-time, rather you just have to do the resolution/selection at an arbitrary time (resolution can actually be done in advance => fail early).
Here's a possible solution, which features:
creation of all bindings on startup
fail early: verification of bindings on startup (through instanciation of all bound IExports)
selection of IExport at an arbitrary runtime
.
internal interface IExportDictionary
{
IExport Get(string key);
}
internal class ExportDictionary : IExportDictionary
{
private readonly Dictionary<string, IExport> dictionary;
public ExportDictionary(IEnumerable<IExport> exports)
{
dictionary = new Dictionary<string, IExport>();
foreach (IExport export in exports)
{
dictionary.Add(export.GetType().Assembly.FullName, export);
}
}
public IExport Get(string key)
{
return dictionary[key];
}
}
Composition root:
// this is just going to bind the IExports.
// If other types need to be bound, go ahead and adapt this or add other bindings.
kernel.Bind(s => s.FromAssembliesMatching("PartnerAdapter.*.dll")
.SelectAllClasses()
.InheritedFrom<IExport>()
.BindSelection((type, baseTypes) => new[] { typeof(IExport) }));
kernel.Bind<IExportDictionary>().To<ExportDictionary>().InSingletonScope();
// create the dictionary immediately after the kernel is initialized.
// do this in the "composition root".
// why? creation of the dictionary will lead to creation of all `IExport`
// that means if one cannot be created because a binding is missing (or such)
// it will fail here (=> fail early).
var exportDictionary = kernel.Get<IExportDictionary>();
Now IExportDictionary can be injected into any component and just used like "required":
foreach (Partner partner in _db.Partners)
{
// pseudocode...
IExport exportModule = exportDictionary.Get(partner.ExportImplementationAssembly);
exportModule.ExportData(_db.GetPartnerData(partner.PartnerID));
}
I would like to do Ninject binding based on a runtime condition, that isn't pre-known on startup.
Prevent making runtime decisions during building of the object graphs. This complicates your configuration and makes your configuration hard to verify. Ideally, your object graphs should be fixed and should not change shape at runtime.
Instead, make the runtime decision at... runtime, by moving this into a proxy class for IExport. How such proxy exactly looks like, depends on your exact situation, but here's an example:
public sealed class ExportProxy : IExport
{
private readonly IExport export1;
private readonly IExport export2;
public ExportProxy(IExport export1, IExport export2) {
this.export1 = export1;
this.export2 = export2;
}
void IExport.ExportData(Partner partner) {
IExport exportModule = GetExportModule(partner.ExportImplementationAssembly);
exportModule.ExportData(partner);
}
private IExport GetExportModule(ImplementationAssembly assembly) {
if (assembly.Name = "A") return this.export1;
if (assembly.Name = "B") return this.export2;
throw new InvalidOperationException(assembly.Name);
}
}
Or perhaps you're dealing with a set of dynamically determined assemblies. In that case you can supply the proxy with a export provider delegate. For instance:
public sealed class ExportProxy : IExport
{
private readonly Func<ImplementationAssembly, IExport> exportProvider;
public ExportProxy(Func<ImplementationAssembly, IExport> exportProvider) {
this.exportProvider = exportProvider;
}
void IExport.ExportData(Partner partner) {
IExport exportModule = this.exportProvider(partner.ExportImplementationAssembly);
exportModule.ExportData(partner);
}
}
By supplying the proxy with a Func<,> you can still make the decision at the place where you register your ExportProxy (the composition root) where you can query the system for assemblies. This way you can register the IExport implementations up front in the container, which improves verifiability of the configuration. If you registered all IExport implementations using a key, you can do the following simple registration for the ExportProxy
kernel.Bind<IExport>().ToInstance(new ExportProxy(
assembly => kernel.Get<IExport>(assembly.Name)));
Let's say I have 5 separate assemblies with the following (assume the class name is different in each):
[Export(typeof(IService))]
public class Service: IService
{
// ...
}
And I have a class that will be a composite of these in my main assembly
public class CompositeService : IService
{
public CompositeService(IEnumerable<IService> services)
{
// ...
}
}
What I would like to do is have the Unity container resolve the CompositeService for the IService and have the MefContrib extension for Unity go and find the 5 other exports and inject them into CompositeService's constructor.
The problem is that you can't have N instances for a nameless unityContainer.RegisterType<IService> nor can you for named instances if they all have the same name.
I think I'm missing something simple in the combination of the 2 technologies (Unity + MEF) via the third (MefContrib) but can't seem to pick up on what it is.
Is this possible or is there a workaround? Eventually, I'm going for full bi-directional dependency injection and dynamic component discovery.
I think what is likely the best approach is to flip this around. Instead of trying to register your components via Unity, you actually leave the discovery of these parts to MEF. MEFContrib includes an Unity integration mechanism that allows your MEF composed parts to be injected into Unity components. This was original detailed at Piotr WŁodek's blog, whereby he also gives you a sample. Essentialy, the way it works is you can use a series of extension methods on your UnityContainer to register your catalogs. Internally, it will create the appropriate extension and wire up your container.
Here is a quick and dirty example, we'll create some interfaces:
public interface IUnityComponent
{
IEnumerable<IMefComponent> MefComponents { get; }
}
public interface IMefComponent
{
string Name { get; }
}
And then some sample parts which we'll export (via MEF):
[Export(typeof(IMefComponent))]
public class MefComponent1 : IMefComponent
{
public string Name { get { return "MEF Component 1"; } }
}
[Export(typeof(IMefComponent))]
public class MefComponent2 : IMefComponent
{
public string Name { get { return "MEF Component 2"; } }
}
Now, we'll create another part (this will be created via Unity):
public class UnityComponent : IUnityComponent
{
public UnityComponent(IEnumerable<IMefComponent> mefComponents)
{
// mefComponents should be provided from your MEF container.
MefComponents = mefComponents;
}
public IEnumerable<IMefComponent> MefComponents { get; private set; }
}
To wire it all up, we simply need to use the RegisterCatalog extension method on your UnityContainer (import MefContrib.Integration.Unity after you've added a reference to MEFContrib):
var container = new UnityContainer();
// Register the catalog - this handles MEF integration.
container.RegisterCatalog(new DirectoryCatalog("."));
// Register our Unity components.
container.RegisterType<IUnityComponent, UnityComponent>(new ContainerControlledLifetimeManager());
Now you should be able to grab the instance and enumerate the MEF-provided parts:
// Grab an instance of our component.
var instance = container.Resolve<IUnityComponent>();
foreach (var mefComponent in instance.MefComponents)
{
Console.WriteLine(mefComponent.Name);
}
note: 100% untested.
Just tried the same solution from Matthew here and it is working ok, Unity is picking up the exports from MEF and injecting them into the constructor (which accepts an IEnumerable<>).
Don't know if it can help you, but including both MefContrib and MefContrib.Integration.Unity can help: for a while I only had the latter included and encountered similar errors.
As a side note, keep in mind that all the registrations in Unity (coming from MEF exports) will be "nameless" so if you try ResolveAll<> you will get an empty collection and if you try Resolve<> you will get an exception if there is more than 1 implementation registered.