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

Ideablade's Cocktail Composition Container for WCF projects

我最近将我正在开发的应用程序从 Cocktail 1.4 升级到 Cocktail 2.6 (Punch)。我已经为 wpf 项目调整了引导程序 class,现在可以正常加载了。但是,在我的 WCF/Web 项目中,我在尝试调用 Composition.GetInstance:

时收到运行时异常和以下错误
"You must first set a valid CompositionProvider by using Composition.SetProvider."

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

Composition.Configure();

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

更新

我找到了 this on the DevForce forums。所以看来我应该学习如何配置多线程 ICompositionProvider 并调用 Composition.SetProvider() 如上所述。有没有推荐的文章来实现这一目标?

在深入了解 Punch 的源代码并查看 Ideablade 的实现 ICompositionProvider 的 MefCompositionContainer 之后,我创建了自己的 ICompositionProvider 线程安全实现。下面是我使用的代码。基本上,它与 Ideablade 的 MefCompositionContainer 的代码相同,可在此处找到 in their repository. The only change is that I am passing a bool flag of true into the CompositionContainer's constructor. MSDN lists the pros and cons of making the container thread safe

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);
    }
}

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

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

看起来工作起来很有魅力!