我如何使用Autofac作为Catel的主要容器?

时间:2013-09-10 20:29:39

标签: autofac catel

有没有办法可以将Autofac用作Catel的主要容器? 我已经看到有对Unity,Ninject,MEF,Windsor和Unity的支持,但没有提到Autofac集成。

2 个答案:

答案 0 :(得分:3)

我们还没有为Autofac创建帮助器,也没有计划编写一个帮助器。

您有以下选择:

1)自己编写Helper类(参见其他示例)并注册,然后ServiceLocator可以同步它

2)在Catel的最新预发行版(3.7预发行版)中,我们引入了IDependencyResolver。您可以在Autofac容器上实现此接口,并在ServiceLocator中注册该接口。请注意,我们没有完全支持,因此可能会产生副作用。

3)在Catel中使用ServiceLocator

在2013-09-14编辑

4)如果您对最新版本的Catel(每晚构建)感兴趣,现在可以用您的实现替换默认服务定位器:

问题详情:https://catelproject.atlassian.net/browse/CTL-175

文档:https://catelproject.atlassian.net/wiki/pages/viewpage.action?pageId=622682#IoC(ServiceLocatorandTypeFactory)-Replacingthedefaultcomponents

答案 1 :(得分:2)

这是我对Catel 3.8和Autofac的解决方案(也适用于其他第三方容器) 我为IDependencyResolver编写了一个由Autofac容器和IServiceLocator实现支持的实现。前者包含应用程序第三方IoC配置和逻辑。后者用于获取Catels模块的所有类型和实例注册,并将它们转发给Autofac。

基本策略是

  1. 创建和配置第三方容器
  2. 使用它来实现(部分定制)Catel IoC组件并将其引入Catels IoC配置
  3. 让Catel使用之前创建的(自定义)实现进行类型和实例注册,并将它们转发到第三方容器
  4. 所以这是我对IServiceLocator的实现:

    internal class CustomServiceLocator : IServiceLocator
        {
            private readonly CustomDependencyResolver _dependencyResolver;
    
            public CustomServiceLocator(CustomDependencyResolver dependencyResolver)
            {
                _dependencyResolver = dependencyResolver;
            }
    
            public object GetService(Type serviceType)
            {
                throw new NotImplementedException();
            }
    
            public RegistrationInfo GetRegistrationInfo(Type serviceType, object tag = null)
            {
                throw new NotImplementedException();
            }
    
            public bool IsTypeRegistered(Type serviceType, object tag = null)
            {
                return _dependencyResolver.CanResolve(serviceType, tag);
            }
    
            public bool IsTypeRegisteredAsSingleton(Type serviceType, object tag = null)
            {
                throw new NotImplementedException();
            }
    
            public void RegisterInstance(Type serviceType, object instance, object tag = null)
            {
                var builder = new ContainerBuilder();
                IRegistrationBuilder<object, SimpleActivatorData, SingleRegistrationStyle> registrationBuilder = builder.RegisterInstance(instance);
    
                if (tag != null)
                {
                    registrationBuilder.Keyed(tag, serviceType);
                }
    
                _dependencyResolver.UpdateContainer(builder);
            }
    
            public void RegisterType(Type serviceType, Type serviceImplementationType, object tag = null, RegistrationType registrationType = RegistrationType.Singleton,
                bool registerIfAlreadyRegistered = true)
            {
                var builder = new ContainerBuilder();
                IRegistrationBuilder<object, ConcreteReflectionActivatorData, SingleRegistrationStyle> registrationBuilder = builder.RegisterType(serviceImplementationType).As(serviceType);
    
                if (tag != null)
                {
                    registrationBuilder.Keyed(tag, serviceType);
                }
    
                switch (registrationType)
                {
                    case RegistrationType.Singleton:
                        registrationBuilder.SingleInstance();
                        break;
                    case RegistrationType.Transient:
                        registrationBuilder.InstancePerDependency();
                        break;
                    default:
                        registrationBuilder.InstancePerDependency();
                        break;
                }
    
                _dependencyResolver.UpdateContainer(builder);
                TypeRegistered(this, new TypeRegisteredEventArgs(serviceType, serviceImplementationType, tag, registrationType));
            }
    
            public object ResolveType(Type serviceType, object tag = null)
            {
                // Must be implemented. Catels ViewModelBase resolves the DependencyResolver in ctor using the ServiceLocator...Why???
                return _dependencyResolver.Resolve(serviceType, tag);
            }
    
            public IEnumerable<object> ResolveTypes(Type serviceType)
            {
                throw new NotImplementedException();
            }
    
            public void RemoveInstance(Type serviceType, object tag = null)
            {
                throw new NotImplementedException();
            }
    
            public void RemoveAllInstances(Type serviceType)
            {
                throw new NotImplementedException();
            }
    
            public void RemoveAllInstances(object tag = null)
            {
                throw new NotImplementedException();
            }
    
            public bool IsExternalContainerSupported(object externalContainer)
            {
                throw new NotImplementedException();
            }
    
            public void RegisterExternalContainer(object externalContainer)
            {
                throw new NotImplementedException();
            }
    
            public void RegisterExternalContainerHelper(IExternalContainerHelper externalContainerHelper)
            {
                throw new NotImplementedException();
            }
    
            public void ExportInstancesToExternalContainers()
            {
                throw new NotImplementedException();
            }
    
            public void ExportToExternalContainers()
            {
                throw new NotImplementedException();
            }
    
            public bool AreAllTypesRegistered(params Type[] types)
            {
                return _dependencyResolver.CanResolveAll(types);
            }
    
            public object[] ResolveAllTypes(params Type[] types)
            {
                return _dependencyResolver.ResolveAll(types);
            }
    
            public bool AutomaticallyKeepContainersSynchronized { get; set; }
            public bool CanResolveNonAbstractTypesWithoutRegistration { get; set; }
            public bool SupportDependencyInjection { get; set; }
            public bool AutoRegisterTypesViaAttributes { get; set; }
            public bool IgnoreRuntimeIncorrectUsageOfRegisterAttribute { get; set; }
            public event EventHandler<MissingTypeEventArgs> MissingType;
            public event EventHandler<TypeRegisteredEventArgs> TypeRegistered;
        }
    

    这里是IDepencyResolver的实现。

    internal class CustomDependencyResolver : IDependencyResolver
        {
            private readonly IContainer _container;
    
            public CustomDependencyResolver()
            {
                var builder = new ContainerBuilder();
                builder.RegisterAssemblyTypes(AppDomain.CurrentDomain.GetAssemblies());
                builder.RegisterInstance(this).SingleInstance(); // dependency of CustomServiceLocator
                builder.RegisterInstance(this).As<IDependencyResolver>().SingleInstance(); // Dependency of ViewModelBase. Catels ViewModelBase resolves the DependencyResolver in ctor using the ServiceLocator...Why???
                builder.RegisterType<CustomServiceLocator>().As<IServiceLocator>().SingleInstance(); // dependency of TypeFactory (subscribes to TypeRegistered event to clear its cache)
                builder.RegisterType<TypeFactory>().As<ITypeFactory>().SingleInstance(); // dependency of ViewModelFactory
    
                _container = builder.Build();
            }
    
            public bool CanResolve(Type type, object tag = null)
            {
                return _container.IsRegistered(type);
            }
    
            public bool CanResolveAll(Type[] types)
            {
                return types.All(type => _container.IsRegistered(type));
            }
    
            public object Resolve(Type type, object tag = null)
            {
                object obj;
                if (tag == null)
                {
                    if (_container.TryResolve(type, out obj))
                        return obj;
                }
                else
                {
                    if (_container.TryResolveKeyed(tag, type, out obj))
                        return obj;
                }
    
                throw new Exception(string.Format("Could not locate any instances of contract {0}.", tag ?? type.Name));
            }
    
            public object[] ResolveAll(Type[] types, object tag = null)
            {
                var objects = new ArrayList();
    
                if (tag == null)
                {
                    foreach (Type type in types)
                    {
                        object obj;
                        if (_container.TryResolve(type, out obj))
                        {
                            objects.Add(obj);
                        }
                        else
                        {
                            throw new Exception(string.Format("Could not locate any instances of contract {0}.", type.Name));
                        }
                    }
                }
                else
                {
                    foreach (Type type in types)
                    {
                        object obj;
                        if (_container.TryResolveKeyed(tag, type, out obj))
                        {
                            objects.Add(obj);
                        }
                        else
                        {
                            throw new Exception(string.Format("Could not locate any instances of contract {0}.", tag));
                        }
                    }
                }
    
                return objects.ToArray();
            }
    
            public void UpdateContainer(ContainerBuilder builder)
            {
                builder.Update(_container);
            }
        }
    

    在启动时将所有内容放在一起:

        public partial class App : Application
        {
            /// <summary>
            /// Raises the <see cref="E:System.Windows.Application.Startup"/> event.
            /// </summary>
            /// <param name="e">A <see cref="T:System.Windows.StartupEventArgs"/> that contains the event data.</param>
            protected override void OnStartup(StartupEventArgs e)
            {
    #if DEBUG
                Catel.Logging.LogManager.AddDebugListener();
    #endif
    
                StyleHelper.CreateStyleForwardersForDefaultStyles();
    
                // create the DependencyResolver and do Catel IoC configuration
                CustomDependencyResolver dependencyResolver = new CustomDependencyResolver();
                DependencyResolverManager.Default.DefaultDependencyResolver = dependencyResolver;
                IoCConfiguration.DefaultDependencyResolver = dependencyResolver;
                IoCConfiguration.DefaultServiceLocator = dependencyResolver.Resolve<IServiceLocator>();
                IoCConfiguration.DefaultTypeFactory = dependencyResolver.Resolve<ITypeFactory>();
    
                // let Catel register its dependencies
                Catel.Core.ModuleInitializer.Initialize();
                Catel.MVVM.ModuleInitializer.Initialize();
    
                base.OnStartup(e);
            }
        }
    

    Tradoffs和副作用:在我看来,Catels IoC的实现有点模糊。例如有时,ServiceLocator用于解析DependencyResolver,有时则用于解决TypeFactory。我试图找出最常用的内部使用方法,并用我的解决方案覆盖它们。如果在应用程序启动后向Autofacs容器注册了类型,并且未通知TypeFactory清除其缓存(我没有分析CustomDependencyResolver本身),则可能会出现副作用。我建议CustomServiceLocator中的TypeRegistered事件的实现,由TypeFactory订阅以将其转发到{{1}}。