2

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

4

2 回答 2

3

我们还没有为 Autofac 创建一个助手,也不打算编写一个。

您有以下选择:

1)自己写Helper类(例子见其他)并注册,ServiceLocator就可以同步了

2) 在最新的 Catel 预发布版(3.7 预发布版)中,我们引入了 IDependencyResolver。您可以在 Autofac 容器上实现此接口并将其注册到 ServiceLocator。请注意,尽管我们对此没有完全支持,因此它可能会导致副作用。

3)在Catel中使用ServiceLocator

编辑于 2013-09-14

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

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

文档:https ://catelproject.atlassian.net/wiki/pages/viewpage.action?pageId=622682#IoC(ServiceLocatorandTypeFactory)-替换默认组件

于 2013-09-11T15:26:41.450 回答
1

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

基本策略是

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

所以这是我的实现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);
        }
    }

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

于 2013-12-08T20:13:02.830 回答