有没有办法可以将Autofac用作Catel的主要容器? 我已经看到有对Unity,Ninject,MEF,Windsor和Unity的支持,但没有提到Autofac集成。
答案 0 :(得分:3)
我们还没有为Autofac创建帮助器,也没有计划编写一个帮助器。
您有以下选择:
1)自己编写Helper类(参见其他示例)并注册,然后ServiceLocator可以同步它
2)在Catel的最新预发行版(3.7预发行版)中,我们引入了IDependencyResolver。您可以在Autofac容器上实现此接口,并在ServiceLocator中注册该接口。请注意,我们没有完全支持,因此可能会产生副作用。
3)在Catel中使用ServiceLocator
在2013-09-14编辑
4)如果您对最新版本的Catel(每晚构建)感兴趣,现在可以用您的实现替换默认服务定位器:
答案 1 :(得分:2)
这是我对Catel 3.8和Autofac的解决方案(也适用于其他第三方容器)
我为IDependencyResolver
编写了一个由Autofac容器和IServiceLocator
实现支持的实现。前者包含应用程序第三方IoC配置和逻辑。后者用于获取Catels模块的所有类型和实例注册,并将它们转发给Autofac。
基本策略是
所以这是我对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}}。