I am using MEF successfully with CSLA to inject my data access layer ... this allows me to do mocking without hitting the database. Working great ... thank you CSLAContrib!
So I have the following projects:
Up to this point ... my tests pass with fly colors! Now I added 2 more projects:
This where my tests start breaking down ... for some reason the data access in the data project is not being load automatically. I can manually assign the container, like I do in the test project, but my concerns are:
Has anyone else ran into these issues? In some case I wish I could just "tell" the IOC what to load, maybe a configuration setting.
Any help would be much appreciated!
This is the error I get ...
The composition remains unchanged. The changes were rejected because of the following error(s): The composition produced a single composition error. The root cause is provided below. Review the CompositionException.Errors property for more detailed information.
1) No valid exports were found that match the constraint '((exportDefinition.ContractName == "MyProject.Business.Repository.ICustomerDataFactory") AndAlso (exportDefinition.Metadata.ContainsKey("ExportTypeIdentity") AndAlso "MyProject.Business.Repository.ICustomerDataFactory".Equals(exportDefinition.Metadata.get_Item("ExportTypeIdentity"))))', invalid exports may have been rejected.
Resulting in: Cannot set import 'MyProject.Business.Customer.DataFactory (ContractName="MyProject.Business.Repository.ICustomerDataFactory")' on part 'MyProject.Business.Customer'.
Element: MyProject.Business.Customer.DataFactory (ContractName="MyProject.Business.Repository.ICustomerDataFactory") --> MyProject.Business.Customerrn"} System.Exception {System.ComponentModel.Composition.ChangeRejectedException}
There's a load of different ways to load Exports into the container (ex: folders, assembly names, explicitly).
I assume that the IoC container is intialized OK but some/all Exports are not being registered.
1. Verify that the assemblies containing your exports are present in the folder where your tests are running.
2. Check which Exports gets loaded into the IoC container.
I'll do this ...
I did create a Windows Forms application and referenced the CSLAContrib.MEF, MyProject.Business and MyProject.Data -- same references as the wcf service -- and everything works.
Look at the Hosting part documentation here
http://msdn.microsoft.com/en-us/library/system.componentmodel.composition.hosting.aspx
This shows the possible classes to use for loading Exports.
When the MEFBusinessBase calls the inject the _container is NOT NULL, which it should be ... no? and is when I run it from my tests that do not interact with the WCF Service.
Looks like when it first runs it is null, but no DLLs are loaded ... maybe because I am making a project reference to the data and business from the service?
Once I am done with my testing I have to restart IIS otherwise the _container is still considered initialized.
How would you explicitly tell it what assembly to load? Is it already built in to the CSLAContrib.MEF library?
The dlls do exist in the bin directory, but for some reason they are not being registered ... wondering if it has something to do with it being a web application with .svc at one level and the dlls in the bin directory.
It has to be a WEB issue ... I created a WebMvc application to work with the business and data layers just like the WCF service AND the Windows Forms application. The only one that works is the WIndows Forms application.
Hi Matt,
Try and change the initialization of IoC to this code (will add assemblies bin folder if present)
public static CompositionContainer Container
{
get
{
//create and configure container if one does not yet exist
if (_container == null)
{
lock (_syncRoot)
{
if (_container == null)
{
Debug.Write("Start configuring MEF Container");
//create container
var catalog = new AggregateCatalog();
//catalog.Catalogs.Add(new DirectoryCatalog(Assembly.GetCallingAssembly().Location));
catalog.Catalogs.Add(new DirectoryCatalog("."));
var dirInfo = new System.IO.DirectoryInfo(@"bin");
if (dirInfo.Exists)
catalog.Catalogs.Add(new DirectoryCatalog(@".\bin\."));
catalog.Catalogs.Add(new AssemblyCatalog(Assembly.GetExecutingAssembly()));
_container = new CompositionContainer(catalog);
_container.ComposeParts();
Debug.Write("End configuring MEF Container");
}
}
}
return _container;
}
}
Hi Jonny ... that didn't seem to work ... it doesn't seem to be able to find the root directory, it goes to C:\. So I added a setting in my config file for a "Plugins" directory ... that seems to work, just not as elegant as I would have liked it to be.
/// <summary>
/// Gets the container.
/// </summary>
public static CompositionContainer Container
{
get
{
//create and configure container if one does not yet exist
if (_container == null)
{
lock (_syncRoot)
{
if (_container == null)
{
//create container
var catalog = new AggregateCatalog();
catalog.Catalogs.Add(new DirectoryCatalog("."));
var dirInfo = new DirectoryInfo(ConfigurationManager.AppSettings["PluginsFolder"]);
if (dirInfo.Exists)
{
catalog.Catalogs.Add(new DirectoryCatalog(
string.Format("{0}.", ConfigurationManager.AppSettings["PluginsFolder"])));
}
catalog.Catalogs.Add(new AssemblyCatalog(Assembly.GetExecutingAssembly()));
_container = new CompositionContainer(catalog);
_container.ComposeParts();
}
}
}
return _container;
}
}
Copyright (c) Marimer LLC