Autofac Modules Imported with MEF not being Loaded - mef

I have a number of assemblies, each supplying their dependencies to Autofac through the use of a class that extends Autofac.Module. I have decorated each of these as a MEF export, e.g:
[Export(typeof(IModule))]
public class ContainerModule : Module
{
protected override void Load(ContainerBuilder builder)
{
base.Load(builder);
}
}
As part of client application startup, I gather together all of these modules, e.g:
var builder = new ContainerBuilder();
var path = "Path to application Bin directory";
var catalog = new DirectoryCatalog(path, "MyApp*.dll");
builder.RegisterComposablePartCatalog(catalog);
container = builder.Build();
When looking at the catalog, I can see all the modules from all the assemblies are present.
The question I have is how do I then instruct Autofac to call the Load method on each of the loaded modules?
I'm thinking some usage of builder.RegisterAssemblyModules but haven't (yet) had a eureka moment of how to tie that into the catalog.
Thanks!
r.

You probably won't be able to do what you want in this way.
By registering the part catalog with the modules in it, you're registering them as components, similar to any other dependency. The only way to get them back out would be to build the container and resolve IEnumerable<IModule>> but then calling Load won't register the stuff in the modules because the container's already built.
If you want the modules to contribute their registrations to the container, you have to register them with the ContainerBuilder directly, not through the MEF integration.

Related

Autofac - dynamic Resolve based on registered provider

I'm having problems finding proper solution for my problem, namely:
Let's consider workflow:
Application starts
Main components are registered in Autofac
Application loads plugin assembly and registers modules within it
Container is being build
Plugin handling logic is run
Plugin can add its own controllers. To properly handle that I had to prepare interface which will provide me types of custom controllers:
interface ICustomControllerProvider
{
IEnumerable<Type> GetControllerTypes();
}
Based on the above my app knows how to integrate specified types as controllers.
All controllers are also defined as services, so Autofac deals with their creation, and so...
Problem:
I want to avoid specifying custom controller type twice
public PluginControllerProvider : ICustomControllerProvider
{
public IEnumerable<Type> GetControllerTypes()
{
// 1st type specification
// controller types are specified here, so they could be integrated with app
yield return typeof(ControllerX);
yield return typeof(ControllerY);
}
}
public class PluginModule : Module
{
protected override void Load(ContainerBuilder builder)
    {
builder.RegisterType<PluginControllerProvider>().As<ICustomControllerProvider>();
// 2nd type specification
// controllers have to be register in module as well
builder.RegisterType<ControllerX>();
builder.RegisterType<ControllerY>();
}
}
Is there any way how ControllerX and ControllerY could be managed by Autofac, where I specified them only in PluginControllerProvider?
I tried achieving that by providing custom registration source and resolving ICustomControllerProvider, however I cannot resolve ICustomControllerProvider based on arguments provided by IEnumerable<IComponentRegistration> RegistrationsFor(Service service, Func<Service, IEnumerable<ServiceRegistration>> registrationAccessor) from IRegistrationSource
Autofac does not offer the ability to inject a list of types registered with Autofac. You'll have to get that yourself by working with the lifetime scope registry.
Before I get into how you might solve this, I should probably note:
Listing the types registered is not a normal thing from a DI perspective. It'd be like listing all the controllers in your MVC application - you don't normally need to do that, and if you did, you'd likely need to build a whole metadata structure on top of it like the ApiExplorer that was built to do that on top of ASP.NET Core. That structure wouldn't be supported or involved with the DI system because you're querying about the system, not injecting live instances into the system.
If you are relying on DI to resolve controllers, you probably don't need a whole separate controller provider. Once you know what type you need for the request, you'd just resolve it.
All that's to say, while I'll answer the question, the way the design here is posed may be something you'd want to look at. What you're doing, trying to involve DI with listing metadata about the app... seems somewhat backwards (you'd feed the DI container based on the list of types, not get the list of types from the DI container).
But let's just go with it. Given:
There are controllers registered with Autofac
The controllers have no common base class or interface
There's no attributes on the controllers you could query
What I'd do is register all the controllers with some metadata. You need something to be able to locate the controllers in the list of all the types in the container.
builder.RegisterType<ControllerX>().WithMetadata("controller", true);
builder.RegisterType<ControllerY>().WithMetadata("controller", true);
Now in the plugin controller, you need to inject an ILifetimeScope because you have to query the list of stuff registered. The ILifetimeScope that gets injected into the controller will be the same scope from which the plugin controller itself was resolved.
You can use the injected scope to query things in the component registry tagged with your metadata.
public class PluginControllerProvider : ICustomControllerProvider
{
private readonly Type[] _controllerTypes;
public PluginController(ILifetimeScope scope)
{
_controllerTypes = scope
.ComponentRegistry
.Registrations
.Where(r => r.Metadata.ContainsKey("controller"))
.Select(r => r.Activator.LimitType)
.ToArray();
}
public IEnumerable<Type> GetControllerTypes()
{
return _controllerTypes;
}
}
Now, disclaimers:
If you are registering more controllers in child lifetime scopes (e.g., during a BeginLifetimeScope() call), you will need a controller provider from that scope or it won't get all the controller types. The provider needs to come from the scope that has all the registrations.
If you're using registration sources (like the AnyConcreteTypeNotAlreadyRegisteredSource), this won't capture things that come from the registration sources. It'll only capture things that come from direct registrations of a type (or lambda) on a ContainerBuilder.
But it should work.

Resolution of ILifetimeService fails in autofac 4.6.2

We're refactoring an older system to use DI. Sadly, some of the "core" components that are used all over everywhere have injection unfriendly constructors (descriptions, for example), so we have to use ServiceLocator to create them. Refactoring them is very impractical at this time.
We're trying to create the unfriendly classes by injecting ILifetimeScope into the appropriate place, but are getting the following exception:
No constructors on type 'Autofac.Core.Registration.ScopeRestrictedRegistry' can be found with the constructor finder 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder'.
If I cheat and use the "Update" method on the ContainerBuilder and then register the container as the LifetimeScope, the resolution works successfully, however, given that Update is obsolete, it's not something I want to do.
Can anyone help?
Edit: I'm not doing anything special. Build up is standard:
builder.RegisterAssemblyTypes(assembly).AsImplementedInterfaces();
this.Container = builder.Build();
builder = new ContainerBuilder();
builder.RegisterInstance(this.Container);
builder.RegisterInstance(this.Container).As<ILifetimeScope>();
builder.Update(this.Container);
Without these lines
builder = new ContainerBuilder();
builder.RegisterInstance(this.Container);
builder.RegisterInstance(this.Container).As<ILifetimeScope>();
builder.Update(this.Container);
any class with an ILifetimeScope dependency fails with the error above.
public class MyClass : IMyClass
{
public MyClass(ILifetimeScope scope)
{
...
}
}
I'm actually thinking that this is a bug in the Autofac Framework, so I'm hoping that someone from the team will be able to tell me more.
ILifetimeScope is supposed to automatically be available.

Using MEF inside a class library

OK, so inside a class library, is it a good idea NOT to use MEF?
Here is an example:
ISomeInterface
5 Implementations of ISomeInterface
Once class that imports all ISomeInterface and uses them.
Again, this is all inside a single dll. Since it is in a DLL, there is no bootstrapping of MEF to create the catalog, and it seems a bit much to build a catalog just to use it once.
Am just learning MEF and how to use it.
Greg
After reading up a bit more on this, it looks like there is no reason that MEF can't be used inside a DLL for it's own parts creation. When I asked this question, I was thinking that the Importing would be mainly inside a Main() or App() type of function to compose the entire app. But if composing needs to be done on a major part that gets exported to the app, it can still use MEF to compose itself in the constructor, like this:
//An aggregate catalog that combines multiple catalogs
var catalog = new AggregateCatalog();
//Adds all the parts found in the same assembly as the Program class
catalog.Catalogs.Add(new AssemblyCatalog(typeof(Program).Assembly));
//Create the CompositionContainer with the parts in the catalog
_container = new CompositionContainer(catalog);
//Fill the imports of this object
try
{
this._container.ComposeParts(this);
}
catch (CompositionException compositionException)
{
}

How to do resolving using Unity in a mutli-project solution

In a new WPF project (VS2010) i 'm using Unity 2 for the first time.
In this project i use the following structure:
Solution
WPF Project
Class Library1
Class Library2
Class Library 3 ....
Registering the different types using Unity is done in WPF Project using the following snippet:
IUnityContainer container = new UnityContainer()
.RegisterType<IObjectContext, ObjectContextAdapter>()
.RegisterType<IConnectionStringProvider, ConnectionStringProvider>()
.RegisterType(typeof(IRepository<>), typeof(Repository<>));
Let's say now that i would like to get the Repository<Orders> constructor-injected resolved in Class Library1.
Apparently the container is not known in the other projects!
How would i do that?
I mostly agree with Chris' answer, but I think config files are icky (especially for Unity) so here's a solution that will allow you to use runtime config w/o circular references. We're going to do this with registries.
Create an Infrastructure project that will contain IConfigureUnity.
public interface IConfigureUnity
{
public void Configure(UnityContainer container);
}
Each of your class library projects will be responsible for implementing this interface to register it's own classes.
public class RegistryForSomeClassLibrary : IConfigureUnity
{
public void Configure(UnityContainer container)
{
container
.RegisterType<IObjectContext, ObjectContextAdapter>()
.RegisterType<IConnectionStringProvider, ConnectionStringProvider>()
.RegisterType(typeof(IRepository<>), typeof(Repository<>));
}
}
Then in your WPF project you'll need to create the container and apply these registries.
var container = new UnityContainer();
new RegistryForSomeClassLibrary().Configure(container);
new RegistryForAnotherClassLibrary().Configure(container);
Now you have a fully configured container instance w/o any config files.
To have multiple projects make use of the same UnityContainer in this scenario, you need a "common" project that contains your UnityContainer and exposes it such that all other projects can access it.
i.e.
WPF Project
Class Library 1
Class Library 2
Class Library 3
Common Library (UnityContainer lives here)
To avoid circular project dependencies, I'd recommend using Unity design-time configuration via a configuration file instead of run-time configuration (as you have in your example). Otherwise your Common Library will have to reference the projects that contain all of the types it resolves and those projects, in turn, would be dependent on the Common Library (since that is presumably where you would expose the UnityContainer instance). You may be able to get it to work using run-time configuration, but I have not tried that; I do know that the design-time configuration works as I have done a few projects using a model exactly like this.

With Autofac what would be the advantages and disadvantages

I've read about Autofac that it's fast. I've seen the coding involved and it's pretty neat. But I'm not quite sure how to use it. I've used StructureMap, and it has a static ObjectFactory. Ninject has the Kernel, but in Autofac's Google pages they recommend doing something like this :
using( var resolver = builder.Build() ){
var whatINeed = resolver.Resolve<INeedThisService>();
}
It's a WinForms app, so I got an Invalid Object state from doing the above, so I switched to having a global IContainer, and did it this way
using( var resolver = Program.Container.CreateInnerContainer() )
{
var whatINeed = resolver.Resolve<INeedThisService>();
}
I've used it about 3 or 5 times. But is that efficient? Or should I just do something like
var whatINeed = Program.Resolve<INeedThisService>()
and under the covers
internal static TServervice Resolver<TService>(){
if(_container == null ) _container = builder.Build();
return _container.Resolve<TService>();
}
Which would you use, and why? Also is there a penalty for working with CreateInnerContainer()?
I am not an AutoFac expert but do have experience with other Ioc containers. I thought this question would give me a reason to try AutoFac.
Designs based on Ioc containers should strive to isolate all code from having access to the container except at the entry point or host level. I created the following example using AutoFac and WinForms to show how a form could access a service via it's constructor.
I'm not quite sure why you thought you needed the inner container. Perhaps you could comment and I can provide a more detailed response.
static class Program
{
[STAThread]
static void Main()
{
var builder = new ContainerBuilder();
builder.Register<TheService>().As<INeedThisService>();
builder.Register(f => new Form1(f.Resolve<INeedThisService>())).As<Form1>();
using (var container = builder.Build())
{
Application.Run(container.Resolve<Form1>());
}
}
}
public interface INeedThisService { }
public class TheService : INeedThisService
{
public TheService() { Console.WriteLine("ctor ThisService"); }
}
public partial class Form1 : Form
{
public Form1(INeedThisService service)
{
Console.WriteLine("ctor Form1");
InitializeComponent();
}
}
1) From the examples you gave I could make an assumption that you are trying to use IOC container primarily as service locator. Although almost all containers support it, main usage would be Dependency Injection. That means you should avoid calling Resolve method at all and let container inject all dependencies for you. The differences between two of them (Service Locator and Dependency Injection) is beyond this topic.
2) If you still want to use it as service locator you can just use root container (Program.Container in your case) without creating inner containers. The sequence would be:
Create ContainerBuilder
Register you components in the builder
Create root container: builder.Build()
Access root container to resolve component instances
3) Container hierarchies can be useful in the scenarios where you need singleton behaviour in different scopes:
Global \ Session \ Request (Web applications)
Application \ Plugin (Desktop plugin-based applications)
BTW Autofac encourage people to use tagged contexts to solve such problems:
As Mark Lindell pointed out, you don't generally need to access the container directly in an Autofac application.
The recommended approach is to access it once, as Mark has done, when the application starts up.
Other components that subsequently need to create objects can declare a constructor parameter of type IContext, which Autofac will automatically inject.
An alternative, that does not require any dependency on the Autofac assembly, is to use Generated Factories as described at: http://code.google.com/p/autofac/wiki/DelegateFactories
Hope this helps!