2

I'm trying to override the default Unity Container behavior for the Enterprise Library so that I can use my MEF container. There are a few resources with explanations of how to do this but I'm just not getting it:

There is also this post on SO but the code does not compile because LogWriter is protected. I assume this referred to an old version:

What I understand is that I need to use the CommonServiceLocator for my MEF container and then attach this to the Enterprise Library container. Here's what I have for my container configurator:

public class MefContainerConfigurator : IContainerConfigurator, IServiceLocator
{
    [Import] private CatalogExportProvider provider;

    public object GetService(Type serviceType)
    {
            throw new NotImplementedException();   
    }

    public object GetInstance(Type serviceType)
    {
        return provider.GetExportedValue<Type>();
    }

    public object GetInstance(Type serviceType, string key)
    {
        throw new NotImplementedException();
    }

    public IEnumerable<object> GetAllInstances(Type serviceType)
    {
        throw new NotImplementedException();
    }

    public TService GetInstance<TService>()
    {
        return provider.GetExportedValue<TService>();
    }

    public TService GetInstance<TService>(string key)
    {
        return provider.GetExportedValue<TService>(key);
    }

    public IEnumerable<TService> GetAllInstances<TService>()
    {
        return provider.GetExportedValues<TService>();
    }

    public void RegisterAll(IConfigurationSource configurationSource, ITypeRegistrationsProvider rootProvider)
    {
        throw new NotImplementedException();
    }
}

And in my bootstrapper:

var configurator = new MefContainerConfigurator();
// Does this line read the Enterprise Library configuration from the app.config?
IConfigurationSource cs = new SystemConfigurationSource();

EnterpriseLibraryContainer.ConfigureContainer(configurator, cs);

I think maybe I need to make use of the LogWriterImpl and ExceptionManagerImpl classes as these have constructors which accept configuration. My questions at this point would be:

  • How do I retrieve the configuration from the IConfigurationSource and feed it into the constructors for the LogWriterImpl and ExceptionManagerImpl constructors?
  • EnterpriseLibraryContainer.ConfigureContainer calls RegisterAll in my MefContainerConfigurator. Is this where I'm supposed to register all of the enterprise library types into the container?
  • The methods from the IServiceLocator interface that I have left as NotImplemented; I couldn't find a way to use these to return objects from my container. Am I supposed to leave them as not implemented and use the generic methods instead?

Edit

I still cannot get this totally right. Based on @Chris Tavares answer, I wrote my RegisterAll method in the MefContainerConfigurator to iterate through the TypeRegistrations and add them to a container. I cannot for the life of me figure out how to merge these to my AggregateContainer that is created in my Bootstrapper class so that I can actually use these exports outside of the ContainerConfigurator:

public void RegisterAll(IConfigurationSource configurationSource, ITypeRegistrationsProvider rootProvider)
{
    var registrations = rootProvider.GetRegistrations(configurationSource);

    foreach (var type in registrations)
    {
        var builder = new RegistrationBuilder();

        builder.ForType(type.ServiceType).Export();

        var cat = new AssemblyCatalog(type.ServiceType.Assembly, builder);
        var container = new CompositionContainer(cat);
        container.ComposeParts(this);
    }
}

ConfigureAggregateCatalog in Prism bootstrapper:

protected override void ConfigureAggregateCatalog()
{
    AggregateCatalog.Catalogs.Add(new AssemblyCatalog(typeof(RegionNames).Assembly));
    // Module assemblies
    AggregateCatalog.Catalogs.Add(new AssemblyCatalog(typeof(DataEntryModule).Assembly));
    AggregateCatalog.Catalogs.Add(new AssemblyCatalog(typeof(ReportingModule).Assembly));
    AggregateCatalog.Catalogs.Add(new AssemblyCatalog(typeof(StatusBarModule).Assembly));
    AggregateCatalog.Catalogs.Add(new AssemblyCatalog(typeof(SplashScreenModule).Assembly));
    AggregateCatalog.Catalogs.Add(new AssemblyCatalog(typeof(WelcomeModule).Assembly));
    AggregateCatalog.Catalogs.Add(new AssemblyCatalog(typeof(AdministrationModule).Assembly));

    AggregateCatalog.Catalogs.Add(new AssemblyCatalog(typeof(Bootstrapper).Assembly));
}
4

1 回答 1

1

您的容器配置器非常不完整。您有一种方法可以实现:RegisterAll,但您没有实现它。

您不必从 config 中读取原始配置信息;相反,当您调用 EnterpriseLibraryContianer.ConfigureContainer 时,Entlib 将旋转配置源,挑选出所有重要的位,并为您提供一系列 TypeRegistration 对象。那些家伙给你类型映射,以及构造函数依赖等。基本上所有你需要在你的容器中注册依赖的东西(在这种情况下,MEF)。

所以基本上你需要做的就是编写代码,将抽象的 TypeRegistration 对象转换为 MEF 的正确配置。

Unity 在这方面并不特别。它也有一个配置器,并且遵循完全相同的过程,因此您可以查看 entlib 代码作为您需要做的各种事情的示例。

我根本不知道 MEF api,所以很遗憾无法帮助您进行具体实施。

于 2013-02-23T01:27:38.403 回答