2013-09-10 1 views

ответ

3

Мы не создали помощника для 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

Документация: https://catelproject.atlassian.net/wiki/pages/viewpage.action?pageId=622682#IoC(ServiceLocatorandTypeFactory)-Replacingthedefaultcomponents

+0

Только что заметил, что вы включили этот сценарий. Используя этот метод, я собираюсь использовать Autofac. (4). Благодаря! – Damian

+0

Интерфейс IServiceLocator довольно востребован, есть ли какие-либо указания относительно того, как реализовать интерфейс или какие-либо примеры реализации? – Damian

+0

Вот почему мы представили IDependencyResolver, который должен облегчить работу. В 3.8 все коды будут использовать DependencyResolver вместо ServiceLocator для получения своих зависимостей, чтобы вам было проще реализовать (нет необходимости реализовывать весь IServiceLocator). –

2

Вот мое решение для Catel 3.8 и Autofac (должно работать и для других сторонних контейнеров).
Я написал реализацию для IDependencyResolver с поддержкой контейнера Autofac и реализации для IServiceLocator. Первая содержит приложения сторонней конфигурации IOC и логики. Последний используется для захвата всех типов и экземпляров регистраций модулей Catels и перед ними в Autofac.

Основная стратегия

  1. Создание и настройка 3 участника контейнер
  2. Используйте его создать экземпляр (частично настроенный) компоненты Катель IoC и ввести их в Catels конфигурации IoC
  3. Пусть Катель сделать его тип и регистрацию экземпляра с использованием ранее созданных (настроенных) реализаций и препроводить их в стороннем контейнере

Итак, вот моя идея ментации для 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.