MEF从Silverlight中的Castle Kernel导入

时间:2011-07-29 16:34:43

标签: c# silverlight silverlight-4.0 mef castle

我目前正在我的项目中使用MEF,但是,遗留组件使用Castle来导出其所有组件。

我希望能够在创建新对象时从此内核导入,以及从Xap获取导出。

这可能吗?你能告诉我一些示例代码吗?

2 个答案:

答案 0 :(得分:2)

MEF旨在尽可能灵活,其中一个秘密隐藏但真正优秀的功能是能够定义新的ExportProvider实例,允许您插入其他组件。我之前通过在带有MEF项目的ASP.NET MVC中使用Common Service Locator项目来讨论这个问题(参见第3部分here)。

CSL是一种很好的灵活方法,因为许多现有的IoC容器都有许多特定的CSL实现,例如Castle,Autofac,Ninject,Unity等。

可以找到另一个很好的例子here,它展示了一种略有不同但基本相似的方法。

答案 1 :(得分:1)

正如Matthew所说,做到这一点的方法是使用ExportProvider

另一个例子是here(它演示了Xaml的导出)。 以下是我最终解决问题的方法。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.ComponentModel.Composition.Primitives;
using System.Linq;
using Castle.MicroKernel;
using Castle.MicroKernel.Registration;
using Castle.Windsor;

namespace MEFCastleBridge
{
    public class CastleExportProvider : ExportProvider
    {
        WindsorContainer _container;
        private readonly Dictionary<ExportDefinition, List<Export>> _exports =
            new Dictionary<ExportDefinition, List<Export>>();
        private readonly object _sync = new object();

        public CastleExportProvider(WindsorContainer container)
        {
            _container = container;
            var handlers = _container.Kernel.GetAssignableHandlers(typeof(object));
            foreach (var handler in handlers)
            {
                RegisterCastleComponent(handler);
            }
            _container.Kernel.ComponentRegistered += ComponentRegistered;
        }

        protected override IEnumerable<Export> GetExportsCore(
            ImportDefinition definition, AtomicComposition atomicComposition)
        {
            var contractDefinition = definition as ContractBasedImportDefinition;
            var retVal = Enumerable.Empty<Export>();
            if (contractDefinition != null)
            {
                string contractName = contractDefinition.ContractName;
                if (!string.IsNullOrEmpty(contractName))
                {
                    var exports =
                       from e in _exports
                       where string.Compare(e.Key.ContractName, contractName, StringComparison.OrdinalIgnoreCase) == 0
                       select e.Value;

                    if (exports.Count() > 0)
                    {
                        retVal = exports.First();
                    }
                }
            }

            return retVal;
        }

        void RegisterCastleComponent(IHandler handler)
        {
            var type = handler.Service;
            var contractName = type.ToString();
            lock (_sync)
            {
                var found = from e in _exports
                            where string.Compare(e.Key.ContractName, 
                                contractName, StringComparison.OrdinalIgnoreCase) == 0
                            select e;

                if (found.Count() == 0)
                {
                    var metadata = new Dictionary<string, object>();
                    var definition = new ExportDefinition(contractName, metadata);
                    _exports.Add(definition, new List<Export>());
                }

                var wrapper = new Export(contractName, () => _container.Resolve(type));
                found.First().Value.Add(wrapper);
            }
        }

        void ComponentRegistered(string key, IHandler handler)
        {
            RegisterCastleComponent(handler);
        }
    }

    public interface IMyComponent
    {
        string TheString { get; }
    }

    public class RegisteredComponent : IMyComponent
    {
        public string TheString { get { return "RegisteredComponent"; } }
    }

    [Export(typeof(IMyComponent))]
    public class ExportedComponent : IMyComponent
    {
        public string TheString { get { return "ExportedComponent"; } }
    }

    public class ExportExample
    {
        // Will contain an instance of RegisteredComponent and ExportedComponent
        [ImportMany]
        public List<IMyComponent> Components { get; set; }

        public ExportExample()
        {
            // Create a Windsor container and add a type.
            var container = new WindsorContainer();
            container.Register(Component.For<IMyComponent>().ImplementedBy<MyComponent>().LifeStyle.Singleton);

            // Add the Export Provider, in addition to the DeploymentCatalog
            var compContainer = new CompositionContainer(new DeploymentCatalog(), new CastleExportProvider(container));
            // Should only be called once, before any attempt to SatisfyImports.
            CompositionHost.Initialize(compContainer);
            CompositionInitializer.SatisfyImports(this);

            Test = string.Join(", ", Components.Select(c => c.DoSomething));
        }

        public string Test { get; set; }
    }
}