Есть ли способ использовать Autofac в качестве основного контейнера для Catel? Я видел, что есть поддержка Unity, Ninject, MEF, Windsor и Unity, но нет упоминания об интеграции Autofac.Как использовать Autofac в качестве основного контейнера в Catel?
ответ
Мы не создали помощника для Autofac, и мы не планируем его писать.
У вас есть следующие варианты:
1) Написать вспомогательный класс самостоятельно (см других для примера) и зарегистрировать его, то ServiceLocator может синхронизировать его
2) В последней предварительной версии Catel (3.7 preerelease) мы ввели IDependencyResolver. Вы можете реализовать этот интерфейс в своем контейнере Autofac и зарегистрировать его в ServiceLocator. Обратите внимание, что у нас нет полной поддержки для этого, так что это может вызвать побочные эффекты.
3) Используйте в Catel поиска сервиса
редактировать на 2013-09-14
4) Если вы заинтересованы в последней версии Catel (ночные сборки), теперь вы можете заменить локатор по умолчанию службы с реализацией:
детали выпуск: https://catelproject.atlassian.net/browse/CTL-175
Вот мое решение для Catel 3.8 и Autofac (должно работать и для других сторонних контейнеров).
Я написал реализацию для IDependencyResolver
с поддержкой контейнера Autofac и реализации для IServiceLocator
. Первая содержит приложения сторонней конфигурации IOC и логики. Последний используется для захвата всех типов и экземпляров регистраций модулей Catels и перед ними в Autofac.
Основная стратегия
- Создание и настройка 3 участника контейнер
- Используйте его создать экземпляр (частично настроенный) компоненты Катель IoC и ввести их в Catels конфигурации IoC
- Пусть Катель сделать его тип и регистрацию экземпляра с использованием ранее созданных (настроенных) реализаций и препроводить их в стороннем контейнере
Итак, вот моя идея ментации для 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
, иногда наоборот. Я попытался выяснить наиболее распространенные внутренние способы и прикрыть их своим решением. Возможный побочный эффект может произойти, если тип зарегистрирован в контейнере Autofacs после запуска приложения, а TypeFactory
не уведомляется об очистке кеша (я не проанализировал сам TypeFactory
). Я предлагаю реализацию для события TypeRegistered в CustomDependencyResolver
, подписанное CustomServiceLocator
, чтобы отложить его до TypeFactory
.
Только что заметил, что вы включили этот сценарий. Используя этот метод, я собираюсь использовать Autofac. (4). Благодаря! – Damian
Интерфейс IServiceLocator довольно востребован, есть ли какие-либо указания относительно того, как реализовать интерфейс или какие-либо примеры реализации? – Damian
Вот почему мы представили IDependencyResolver, который должен облегчить работу. В 3.8 все коды будут использовать DependencyResolver вместо ServiceLocator для получения своих зависимостей, чтобы вам было проще реализовать (нет необходимости реализовывать весь IServiceLocator). –