用于WCF项目的Ideablade鸡尾酒组合容器



我最近将正在开发的一个应用程序从Cocktail 1.4升级到了Cocktail 2.6(Punch)。我已经为wpf项目调整了我的引导程序类,现在加载时没有任何问题。但是,在我的WCF/Web项目上,我在尝试调用Composition.GetInstance:时收到一个运行时异常,其中包含以下错误

"You must first set a valid CompositionProvider by using Composition.SetProvider."

在深入研究了这个问题之后,当您的引导程序从CocktailMefBootstrapper继承时,似乎会自动配置组合容器。我目前根本没有用于非wpf项目的引导程序类。在升级之前,我所要做的就是调用Composition类上的configure方法来配置Composition容器,但它似乎已经被弃用:

Composition.Configure();

我注意到您也可以调用Composition.SetProvider(),但是我有点不确定如何准确地满足方法签名。DevForce Punch文档指出,引导程序类的通用类型应该是视图模型,并且服务项目中没有视图/视图模型。这让我不知所措,因为我不想从这些WCF项目中榨取鸡尾酒。对于Cocktail(Punch)2.6中的项目,是否还有一种方法可以在没有引导程序的情况下使用Cocktail的合成容器?

更新

我在DevForce论坛上发现了这个。因此,我似乎应该学习如何配置多线程ICompositionProvider并调用Composition.SetProvider(),如上所述。有什么建议实现这一点的文章吗?

在深入研究Punch的源代码并查看了实现ICompositionProvider的Idealade的MefCompositionContainer之后,我创建了自己的IComposition Provider线程安全实现。下面是我使用的代码。基本上,这与Idealade的MefCompositionContainer的代码相同,可以在他们的存储库中找到。唯一的变化是,我将一个bool标志true传递到CompositionContainer的构造函数中。MSDN列出了使容器线程安全的利弊

internal partial class ThreadSafeCompositionProvider : ICompositionProvider
{
    static ThreadSafeCompositionProvider()
    {
        CompositionHost.IgnorePatterns.Add("Caliburn.Micro*");
        CompositionHost.IgnorePatterns.Add("Windows.UI.Interactivity*");
        CompositionHost.IgnorePatterns.Add("Cocktail.Utils*");
        CompositionHost.IgnorePatterns.Add("Cocktail.Compat*");
        CompositionHost.IgnorePatterns.Add("Cocktail.dll");
        CompositionHost.IgnorePatterns.Add("Cocktail.SL.dll");
        CompositionHost.IgnorePatterns.Add("Cocktail.WinRT.dll");
    }
    public IEnumerable<Assembly> GetProbeAssemblies()
    {
        IEnumerable<Assembly> probeAssemblies = CompositionHost.Instance.ProbeAssemblies;
        var t = GetType();
        // Add Cocktail assembly
        probeAssemblies = probeAssemblies.Concat(GetType().GetAssembly());
        return probeAssemblies.Distinct(x => x);
    }
    private List<Assembly> _probeAssemblies;
    private AggregateCatalog _defaultCatalog;
    private ComposablePartCatalog _catalog;
    private CompositionContainer _container;
    public ComposablePartCatalog Catalog
    {
        get { return _catalog ?? DefaultCatalog; }
    }
    public ComposablePartCatalog DefaultCatalog
    {
        get
        {
            if (_defaultCatalog == null)
            {
                _probeAssemblies = GetProbeAssemblies().ToList();
                var mainCatalog = new AggregateCatalog(_probeAssemblies.Select(x => new AssemblyCatalog(x)));
                _defaultCatalog = new AggregateCatalog(mainCatalog);
                CompositionHost.Recomposed += new EventHandler<RecomposedEventArgs>(OnRecomposed)
                    .MakeWeak(x => CompositionHost.Recomposed -= x);
            }
            return _defaultCatalog;
        }
    }
    internal void OnRecomposed(object sender, RecomposedEventArgs args)
    {
        if (args.HasError) return;
        var newAssemblies = GetProbeAssemblies()
            .Where(x => !_probeAssemblies.Contains(x))
            .ToList();
        if (newAssemblies.Any())
        {
            var catalog = new AggregateCatalog(newAssemblies.Select(x => new AssemblyCatalog(x)));
            _defaultCatalog.Catalogs.Add(catalog);
            _probeAssemblies.AddRange(newAssemblies);
        }
        // Notify clients of the recomposition
        var handlers = Recomposed;
        if (handlers != null)
            handlers(sender, args);
    }

    public CompositionContainer Container
    {
        get { return _container ?? (_container = new CompositionContainer(Catalog, true)); }
    }

    public Lazy<T> GetInstance<T>() where T : class
    {
        var exports = GetExportsCore(typeof(T), null).ToList();
        if (!exports.Any())
            throw new Exception(string.Format("Could Not Locate Any Instances Of Contract", typeof(T).FullName));
        return new Lazy<T>(() => (T)exports.First().Value);
    }
    public T TryGetInstance<T>() where T : class
    {
        if (!IsTypeRegistered<T>())
            return null;
        return GetInstance<T>().Value;
    }
    public IEnumerable<T> GetInstances<T>() where T : class
    {
        var exports = GetExportsCore(typeof(T), null);
        return exports.Select(x => (T)x.Value);
    }
    public Lazy<object> GetInstance(Type serviceType, string contractName)
    {
        var exports = GetExportsCore(serviceType, contractName).ToList();
        if (!exports.Any())
            throw new Exception(string.Format("Could Not Locate Any Instances Of Contract",
                                              serviceType != null ? serviceType.ToString() : contractName));
        return new Lazy<object>(() => exports.First().Value);
    }
    public object TryGetInstance(Type serviceType, string contractName)
    {
        var exports = GetExportsCore(serviceType, contractName).ToList();
        if (!exports.Any())
            return null;
        return exports.First().Value;
    }
    public IEnumerable<object> GetInstances(Type serviceType, string contractName)
    {
        var exports = GetExportsCore(serviceType, contractName);
        return exports.Select(x => x.Value);
    }
    public ICompositionFactory<T> GetInstanceFactory<T>() where T : class
    {
        var factory = new ThreadSafeCompositionFactory<T>();
        Container.SatisfyImportsOnce(factory);
        if (factory.ExportFactory == null)
            throw new CompositionException(string.Format("No export found.", typeof(T)));
        return factory;
    }
    public ICompositionFactory<T> TryGetInstanceFactory<T>() where T : class
    {
        var factory = new ThreadSafeCompositionFactory<T>();
        Container.SatisfyImportsOnce(factory);
        if (factory.ExportFactory == null)
            return null;
        return factory;
    }
    public void BuildUp(object instance)
    {
        // Skip if in design mode.
        if (DesignTime.InDesignMode())
            return;
        Container.SatisfyImportsOnce(instance);
    }
    public bool IsRecomposing { get; internal set; }
    public event EventHandler<RecomposedEventArgs> Recomposed;
    internal bool IsTypeRegistered<T>() where T : class
    {
        return Container.GetExports<T>().Any();
    }
    public void Configure(CompositionBatch compositionBatch = null, ComposablePartCatalog catalog = null)
    {
        _catalog = catalog;
        var batch = compositionBatch ?? new CompositionBatch();
        if (!IsTypeRegistered<IEventAggregator>())
            batch.AddExportedValue<IEventAggregator>(new EventAggregator());
        Compose(batch);
    }
    public void Compose(CompositionBatch compositionBatch)
    {
        if (compositionBatch == null)
            throw new ArgumentNullException("compositionBatch");
        Container.Compose(compositionBatch);
    }
    private IEnumerable<Lazy<object>> GetExportsCore(Type serviceType, string key)
    {
        return Container.GetExports(serviceType, null, key);
    }
}

在设置该类之后,我在启动期间添加了一个配置,以实例化我的新线程安全组合提供程序,并将其设置为Punch的composition类的提供程序:

        if (createThreadSafeCompositionContainer)
        {             
            var threadSafeContainer = new ThreadSafeCompositionProvider();
            Composition.SetProvider(threadSafeContainer);
        }

看起来很有魅力!

最新更新