【问题标题】:Ideablade's Cocktail Composition Container for WCF projectsIdeablade 用于 WCF 项目的鸡尾酒组合容器
【发布时间】:2015-12-02 20:44:08
【问题描述】:

我最近将我正在开发的应用程序从 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.Configure();

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

更新

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

【问题讨论】:

  • 查看github.com/IdeaBlade/Punch 的 Punch 源代码,特别是 MefCompositionProvider。它使用的 MEF CompositionContainer 当前是单线程的,但其构造函数上的标志将使其成为多线程。
  • 谢谢金。我昨天实际上浏览了源代码并想出了一个解决方案。我会在下面发帖

标签: ioc-container devforce


【解决方案1】:

在挖掘了 Punch 的源代码并查看了实现 ICompositionProvider 的 Ideablade 的 MefCompositionContainer 之后,我创建了自己的 ICompositionProvider 线程安全实现。下面是我使用的代码。基本上,它与 Ideablade 的 MefCompositionContainer 的代码相同,可以在此处找到 in their repository。唯一的变化是我将一个 bool 标志传递给了 CompositionContainer 的构造函数。 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);
    }
}

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

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

看起来就像一个魅力!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-01-20
    • 2019-01-09
    • 1970-01-01
    • 2018-10-18
    • 2016-07-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多