MEF does not load all expected components - mef

I have a core MEF implementation that gives me a bad headache...
In each of three separate assemblies I created an IService implementation.
All three classes looks similar like this:
[Export(typeof(IService))]
public class ClassX : IService {}
Now I have an implementaton that tries loading all three of them.
The loader assembly is in the same folder as all three service implementations
The code that loads the 3 parts looks like:
public class ClassLoader
{
[ImportMany(typeof(IService))]
public IEnumerable<IService> Services { get; set; }
public async Task<bool> LoadAsync(CancellationTokenSource cts, string path)
{
var assemblies = Directory.GetFiles(path, "*.dll", SearchOption.TopDirectoryOnly)
.Select(AssemblyLoadContext.Default.LoadFromAssemblyPath)
.Where(s => s.GetTypes().Where(p => typeof(IService).IsAssignableFrom(p)).Any())
.Select(a => new AssemblyCatalog(a)).ToList();
var catalog = new AggregateCatalog();
assemblies.ForEach(a => catalog.Catalogs.Add(a));
var container = new CompositionContainer(catalog, CompositionOptions.DisableSilentRejection);
container.ComposeParts(this);
....
}
}
This code only loads 2 of three assemblies.
My question is, any suggestions why on of them is not loaded?
But maybe more helpfull are their ways to find out why a particular type is not loaded. I hoped that the compositionoption gave me an error, but I didn't in this case.
What are the best debugging possibilities?
Thanks already for sharing any ideas.

Related

Can KeyFilter work through multiple levels?

I have a data access class that has its configuration data as a dependency. I then have a "data consumer" class that has the data access class as its dependency. I want to be able to select the configuration class in the constructor of the consumer.
I have this working in unit tests with the KeyFilter attribute. However, it only works through one layer - I have to eliminate the middle data access class layer. This doesn't work for my actual use case, but I believe it shows I'm using KeyFilter correctly.
Here is a test that passes:
[TestMethod]
public void ChooseCorrectlyThroughInterface()
{
var wrapper = new AutofacWrapper();
wrapper.Register<ITest, Test1>();
wrapper.Register<ITest, Test2>(UseTest2);
wrapper.Register<IConsumer1, Consumer1>();
wrapper.Register<IConsumer2, Consumer2>();
using (wrapper.BeginScope())
{
var c1 = wrapper.Get<IConsumer1>();
Assert.AreEqual("Test1", c1.ToString());
var c2 = wrapper.Get<IConsumer2>();
Assert.AreEqual("Test2", c2.ToString());
}
}
Consumer1's constructor looks like this:
public Consumer1(ITest test)
but Consumer2 uses a KeyFilter:
public Consumer2([KeyFilter(NamedBindingsShould.UseTest2)] ITest test)
My wrapper.Register method looks like this:
if (string.IsNullOrEmpty(name))
{
Builder.RegisterType<TImplementation>()
.As<TInterface>()
.WithAttributeFiltering();
}
else
{
Builder.RegisterType<TImplementation>()
.Named<TInterface>(name)
.WithAttributeFiltering();
}
This all works fine and the test passes. However, the real use case is to add a layer between where the KeyFilter is defined on the constructor and the dependency that needs to vary.
I want to specify two different database config classes:
wrapper.Register<IDatabaseConfigTest, DatabaseConfigDefault>();
wrapper.Register<IDatabaseConfigTest, DatabaseConfigAlternate>(Alternate);
but only one data access class:
wrapper.Register<IDatabaseTest, DatabaseTest>();
with this constructor:
public DatabaseTest(IDatabaseConfigTest config)
and specify the KeyFilter in the data consumer class constructor:
public DataConsumerDefault(IDatabaseTest database)
public DataConsumerAlternate([KeyFilter(NamedBindingsShould.Alternate)] IDatabaseTest database)
I had this working in Ninject with a lot of kung fu (no pun intended), but I'm trying to switch to Autofac and I can't seem to get it to work.
Is this possible in Autofac? Is there a different approach I can use besides KeyFilter? I have a sample test project I can attach or send if needed. I can also provide details as to how I did it in Ninject if that would help.
Soooo...thanks to https://autofaccn.readthedocs.io/en/latest/faq/select-by-context.html?highlight=AttributedMetadataModule%20#option-3-use-keyed-services
I changed my wrapper.Register method to this:
if (string.IsNullOrEmpty(name))
{
Builder.RegisterType<TImplementation>()
.As<TInterface>()
.WithAttributeFiltering();
}
else
{
Builder.RegisterType<TImplementation>()
.Named<TInterface>(name)
.WithParameter(
new ResolvedParameter(
(pi, ctx) => ctx.IsRegisteredWithName(name, pi.ParameterType),
(pi, ctx) => ctx.ResolveNamed(name, pi.ParameterType)))
.WithAttributeFiltering();
}
and it worked!
Thank you documentation.

EF Code First, IoC and DbConnection

I'm using Entity Framework Code First. I want to be able to inject a System.Data.Common.DbConnection object when instantiating the context that derives from System.Data.Entity.DbContext. This is so that I can pass different types of connections depending on what environment the code is running in, i.e. use System.Data.SqlClient (SQL Server) in development, System.Data.SQLite when unit testing and something else in production. The pertinent parts of Context looks like this:
public class Context : DbContext
{
public Context(DbConnection dbConnection)
: base(dbConnection, true)
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
Database.SetInitializer(new MigrateDatabaseToLatestVersion<Context, Configuration>());
base.OnModelCreating(modelBuilder);
}
public DbSet<Test> Tests { get; set; }
}
That gives me the following error: The target context 'Services.Persistence.Context' is not constructible. Add a default constructor or provide an implementation of IDbContextFactory. I think this happens during model initialization when Entity Framework apparently feels it needs to new up it's own Context, independent of the IoC pattern I'm trying to achieve. The lack of a default constructor is by design. The IDbContextFactory interface is just as useless - it has to have a default constructor too.
Is Entity Framework Code First completely wedded to the idea of setting up it's config by reading a connectionstring from a config file (or alternatively getting the connectionstring passed directly) or can one work around this?
UPDATE, here's the Windsor config:
container.Register(Component
.For<DbConnection>()
.UsingFactoryMethod(() =>
new SqlConnection("Data Source=(localdb)\\v11.0;Database=ThatProject;MultipleActiveResultSets=true"))
.LifeStyle.Transient);
container.Register(Component
.For<Context>()
.UsingFactoryMethod(k => new Context(k.Resolve<DbConnection>()))
.LifeStyle.PerWebRequest);
container.Register(Component
.For<IRepository>()
.UsingFactoryMethod(k => new Repository(k.Resolve<Context>()))
.LifeStyle.PerWebRequest);
I'm pretty sure your issue is nothing to do with EF but I'm not really a user of Windsor so i cant tell you for sure what your config issue is. What I have done is to reproduce a similar configuration with ninject which works exactly as you would expect, see below:
class Program
{
static void Main(string[] args)
{
IKernel kernel = new StandardKernel();
kernel.Bind<DbConnection>().ToMethod((ctx) =>{return new SqlConnection("Data Source=(localdb)\\v11.0;Database=ThatProject;MultipleActiveResultSets=true");});
kernel.Bind<Context>().ToSelf();//not really needed
kernel.Bind<TestRepository>().ToSelf();//not really needed
kernel.Get<TestRepository>();
}
}
public class Context : DbContext
{
public Context(DbConnection dbConnection)
: base(dbConnection, true){}
public DbSet<Test> Tests { get; set; }
}
public class TestRepository
{
public TestRepository(Context c)
{
c.Tests.Add(new Test());
c.SaveChanges();
var all = c.Tests;
}
}
public class Test
{
public int Id { get; set; }
}
This means that EF isn't trying to do any funkiness with context creation (as a non-empty constructor works fine for me).
From your Windsor config I would expect you need to do something like the following however im not too sure of the exact syntax:
container.Register(Component
.For<DbConnection>()
.UsingFactoryMethod(() =>
new SqlConnection("Data Source=(localdb)\\v11.0;Database=ThatProject;MultipleActiveResultSets=true"))
.LifeStyle.Transient);
container.Register(Component
.For<Context>()
.ImplementedBySelf()//this probably isn't the correct syntax
.LifeStyle.PerWebRequest);//per request is good, i have some details around why this is good practice if you are interested
container.Register(Component
.For<IRepository>()
.ImplementedBy<ConcreteRepository>()//you arent really calling a method and creating the object yourself you are letting Windsor create the object and sort out the dependancy tree
.LifeStyle.PerWebRequest);

MEF Composition .NET 4.0

Thanks in advance for your assistance. I have the following exported part:
[Export (typeof(INewComponent))] // orignally tried just [Export} here and importing NewComponent below
public class NewComponent : INewComponent
{
// does stuff including an import
}
The Console test program imports the above:
public class Program
{
[Import] // have tried variations on importing "NewComponent NewComponent" etc
public INewComponent NewComponent
{
get;
set;
}
public static void Main(string[] args)
{
var p = new Program();
var catalog = new AssemblyCatalog(typeof(Program).Assembly);
var container = new CompositionContainer(catalog);
container.ComposeParts(p);
}
The Composition fails with these CompositionExceptions (I removed the namespace to protect the guilty :)):
1) No valid exports were found that match the constraint
'((exportDefinition.ContractName == "INewComponent") AndAlso
(exportDefinition.Metadata.ContainsKey("ExportTypeIdentity") AndAlso
"INewComponent".Equals(exportDefinition.Metadata.get_Item("ExportTypeIdentity"))))',
invalid exports may have been rejected.
The Composition works successfully if I do the composition in the main program like this:
public class Program
{
public static void Main(string[] args)
{
INewComponent newComponent = new NewComponent();
var catalog = new AssemblyCatalog(typeof(Program).Assembly);
var container = new CompositionContainer(catalog);
container.ComposeParts(newComponent);
}
}
Thank You
Is your Exported part contained in the same Assembly as Program? If it is in a separate DLL, you need to include that Assembly in your catalog as well, like this:
var aggregateCatalog = new AggregateCatalog();
aggregateCatalog.Catalogs.Add(new AssemblyCatalog(typeof(Program).Assembly));
aggregateCatalog.Catalogs.Add(new AssemblyCatalog(typeof(NewComponent).Assembly));
var container = new CompositionContainer(aggregateCatalog);
// etc...
If that's doesn't work, then there is a nice open source tool called Visual MEFx that can help you analyze your catalog. Here is a short article about setting it up:
Getting Started With Visual MEFx
In your NewComponent class you wrote this:
// does stuff including an import
If there is a problem with that unshown import, then MEF will complain about the Program.NewComponent import instead of the actual deeper cause. This is called "stable composition". Stable composition can be useful, but it also complicates the debugging of a failed composition.
You can follow the instructions in the MEF documentation about Diagnosing Composition Errors to home in on the actual cause.
In a small program, you can also try to call container.GetExportedValue<ISomeExport>() for a few exports until you find the one that is causing problems.

Data Driven IoC

I am writing a program that uses IoC(Windsor v3.0) at startup to load all assemblies in a directory, if implementing an interface/service, into a repository for the core of the application. I am, however, a newcomer to Windsor. My app polls a DB table and when it finds a row that needs to be processed, it checks the name of the service to process the record and requests it from the repository. I can load all the modules into the dictionary and then into the repository via configuration as in this post. Good and well, but I need it to be more dynamic.
How I envision it (pseudo-code):
List<string> enabledServices = GetServicesFromDb();
IDictionary<string, IModule> dict = new IDictionary<string, IModule>();
//Load the assemblies (This works currently!)
_container.Register(AllTypes
.FromAssemblyInDirectory(new AssemblyFilter("Modules"))
.BasedOn<IModule>());
// Build dictionary
foreach(string service in enabledServices)
{
foreach(?? asmble in _container.assemblies)
{
if(asmble.Id == service)
dict.Add(service, asmble);
}
}
// Register the repository from constructed dictionary
_container.Register(
Component
.For<IModuleRepository>()
.ImplementedBy<IntegrationRepository>()
.Parameters(new { modules = dict})
);
The repository:
public class IntegrationRepository : IModuleRepository
{
private readonly IDictionary<string, IModule> _modules;
public IntegrationRepository(IDictionary<string, IModule> modules)
{
_modules = modules;
}
public IModule GetModule(string moduleName)
{
return _modules.ContainsKey(moduleName) ? _modules[moduleName] : null;
}
}
IModule looks like this:
public interface IModule : IDisposable
{
string Id { get; }
string Description { get; }
bool Enabled { get; set; }
bool Validate();
string EmailSubject { get; }
}
All modules:
Implement "IModule" interface
Reside in the "Modules" subfolder
Share a common namespace
I don't have enough experience with Windsor to know how to iterate through the container or if its possible, and _container.ResolveAll(); doesn't seem to work... at least the way I have it in my mind.
My thoughts come from this example which alludes to passing the object in if the object is already created. And this which is similar. I also saw some interesting things on the DictionaryAdapterFactory() but not confident enough to know how to use it
Is something like this possible? Any ideas?
instead of all this you can just store your container globally and you can resolve by full name your modules everywhere
_container.Resolve<IModule>(serviceFullName)
you can register all available services to your container and then create a provider that returns only the services that are enabled in the database. Your components then should of course only access these services through the provider.

Converting From Castle Windsor To StructureMap In An MVC2 Project

I am learning about best practices in MVC2 and I am knocking off a copy of the "Who Can Help Me" project (http://whocanhelpme.codeplex.com/) off Codeplex. In it, they use Castle Windsor for their DI container. One "learning" task I am trying to do is convert this subsystem in this project to use StructureMap.
Basically, at Application_Start(), the code news up a Windsor container. Then, it goes through multiple assemblies, using MEF, in ComponentRegistrar.cs:
public static class ComponentRegistrar
{
public static void Register(IContainer container)
{
var catalog = new CatalogBuilder()
.ForAssembly(typeof(IComponentRegistrarMarker).Assembly)
.ForMvcAssembly(Assembly.GetExecutingAssembly())
.ForMvcAssembliesInDirectory(HttpRuntime.BinDirectory, "CPOP*.dll") // Won't work in Partial trust
.Build();
var compositionContainer = new CompositionContainer(catalog);
compositionContainer
.GetExports<IComponentRegistrar>()
.Each(e => e.Value.Register(container));
}
}
and any class in any assembly that has an IComponentRegistrar interface will get its Register() method run.
For example, the controller registrar's Register() method implementation basically is:
public void Register(IContainer container)
{
Assembly.GetAssembly(typeof(ControllersRegistrarMarker)).GetExportedTypes()
.Where(IsController)
.Each(type => container.AddComponentLifeStyle(
type.Name.ToLower(),
type,
LifestyleType.Transient ));
}
private static bool IsController(Type type)
{
return typeof(IController).IsAssignableFrom(type);
}
Hopefully, I am not butchering WCHM too much. I am wondering how does one do this with StructureMap? I'm assuming that I use Configure() since Initialize() resets the container on each call? Or, is tit a completely different approach? Do I need the MEF-based assembly scan, used to find all registrars and run each Register(), or is there something similar in StructureMap's Scan()?
Have a look at StructureMap's registries (http://structuremap.github.com/structuremap/RegistryDSL.htm). To control the lifecycle use something like:
For<ISomething>().Use<Something>().LifecycleIs(new SingletonLifecycle());
(Transient is the default).
When you bootstrap the container you can say:
ObjectFactory.Initialize(c => c.Scan(s => {
s.WithDefaultConventions();
s.LookForRegistries();
}
Feel dirty, answering my own question, but I did the following:
public class ControllerRegistrar : IComponentRegistrar
{
public void Register(IContainer container)
{
container.Configure(x =>
{
x.Scan(scanner =>
{
scanner.Assembly(Assembly.GetExecutingAssembly());
scanner.AddAllTypesOf<IController>().NameBy(type => type.Name.Replace("Controller", ""));
});
});
}
}
I am not 100% sure this is right, but it works. Pulled it primarily from the "Registering Types by Name" section of this StructureMap doc page.