Reputation: 2675
I have a Caliburn Micro's bootstrapper and I use the MEF as IoC. One of interfaces implementors can throw exception from it's constructor. So, when I do the following:
CompositionBatch batch = new CompositionBatch();
batch.AddExportedValue<IFrProvider>(new ShtrihFr());
Then I get exception at application startup, but I want to get it at the time of resolvation. How to accomplish that with MEF?
Update 1.
Here what I did:
[Export(typeof (LoadingViewModel))]
public class LoadingViewModel {
public LoadingViewModel() {}
[Import]
private readonly IFrProvider frProvider;
}
[Export(typeof(IFrProvider))]
public class ShtrihFr : IFrProvider {
[ImportingConstructor]
public ShtrihFr(int password = 1) {
}
}
So when I do the following:
protected override object GetInstance(Type serviceType, string key) {
string contract = string.IsNullOrEmpty(key) ? AttributedModelServices.GetContractName(serviceType) : key;
IEnumerable<object> exports = container.GetExportedValues<object>(contract);
var exportedList = exports as IList<object> ?? exports.ToList();
if (exportedList.Any())
return exportedList.First();
throw new Exception(string.Format("Could not locate any instances of contract {0}.", contract));
}
exportedList count is 0. It can't find the implementation. I cheked that the container has amidts it's parts the ShtrihFr implementation. How to solve the problem?
Update 2. For debugging purpose I did added the following to the beggining of GetInstance method:
if (serviceType.FullName == "Microtech.Hardware.IFrProvider") {
var export = container.GetExport<IFrProvider>();
var frProvider = export.Value;
}
At line container.GetExport I get ImportCardinalityMismatchException. No exports were found that match the constraint...
Upvotes: 1
Views: 287
Reputation: 5299
One way to achieve this is the following. On application startup create Catalog
that contains all composable parts of your application and initialize the CompositionContainer
. Here is the code.
var catalog = new DirectoryCatalog(path to the directory that contains your dlls, "*.dll");
var compositionContainer = new CompositionContainer(catalog);
compositionContainer.ComposeParts();
Next mark your ShtrihFr
class with Export
attribute:
[Export(typeof(IFrProvider))]
public class ShtrihFr : IFrProvider
{
public ShtrihFr()
{
throw new NotImplementedException("Not Implemented");
}
}
This way the CompositionContainer
through the DirectoryCatalog
will only get list of composable parts and their contracts. Actual instances will not be created, so you won't get exception on application startup.
When you need instance of the ShtrihFr
class, you can use one of the following lines:
var part = compositionContainer.GetExportedValue<IFrProvider>();
The above line will throw exception if the constructor throws exception, which is the case now.
var part = compositionContainer.GetExport<IFrProvider>();
The above line will not throw exception when executed, but to get the actual instance you will need to access the Value
property of the part
variable, which will throw exception.
Update 1:
Add default constructor to the ShtrihFr
class, so it look like this:
[Export(typeof(IFrProvider))]
public class ShtrihFr : IFrProvider
{
public ShtrihFr(int password = 1)
{
}
[ImportingConstructor]
public ShtrihFr(int password = 1)
{
}
}
And instead of using the overridden GetInstance
method, use something like this, if you need collection of exported parts:
public IEnumerable<T> GetInstances<T>(Type constraint = null)
{
if (constraint == null)
return compositionContainer.GetExportedValues<T>();
return compositionContainer.GetExportedValues<T>(AttributedModelServices.GetContractName(constraint));
}
or something like this, if you need single exported part:
public T GetInstance<T>(Type constraint = null)
{
if (constraint == null)
return compositionContainer.GetExportedValue<T>();
return compositionContainer.GetExportedValue<T>(AttributedModelServices.GetContractName(constraint));
}
In both methods, the type parametar T
is the type of the exported part you want to instantiate. The constraint
parameter passed to both methods is additional constraint that is optional and if needed is applied to the Export
attribute of the classes.
Upvotes: 1