2015-05-18 4 views
4

Я опубликовал общий основной вопрос, когда дело доходит до IDisposable объектов и используя Autofac здесь: Dependency Injection and IDisposable. К сожалению, я не учитывал один конкретный сценарий в нашем проекте, и это действительно отдельный вопрос, который стоит сам по себе, поэтому зададим его здесь:Autofac, IDisposable и ручное вызов .Resolve при определенных обстоятельствах

У меня есть объект репозитория, который управляет жизнью объекта сеанса внутри него , Таким образом, объект репозитория является IDisposable и разрушает сеанс (репозиторий вводится с фабричным делегатом при конструировании, создает сеанс во время первого использования и уничтожает сеанс в IDisposable, если сеанс не является нулевым). В отношении ссылки на вопрос StackOverflow выше я понимаю, что любой объект, который вводится с моим объектом репозитория, не должен реализовывать IDisposable, поскольку Autofac будет обрабатывать удаление моих репозиториев, если он их впрыскивает.

В упомянутой потоке StackOverflow я начал очищать использование IDisposable от моих объектов, пока не наткнулся на класс NotificationPublisher, показанный ниже. Есть несколько таких мест, где классы вводятся с внедрением IComponentContext, который действует как завод. Разрешение происходит вручную в функции, потому что кодовая база не знает, какой обработчик нужно вводить до времени выполнения.

public class NotificationPublisher : INotificationPublisher 
{ 
    private readonly IComponentContext _container; 
    private readonly INotificationManager _notificationManager; 

    public NotificationPublisher(IComponentContext container, 
     INotificationManager notificationManager) 
    { 
     _container = container; 
     _notificationManager = notificationManager; 
    } 

    public IEnumerable<IAlertSubscription> Publish(Account account, 
     INotificationInitiator owner, INotificationEntity entity, 
     Int32 severity, CheckCycleContext monitoringContext) 
    { 
     var alertSubscriptions = 
      _notificationManager.GetAlertSubscriptions(account, owner, severity); 

     foreach (var alertSubscription in alertSubscriptions) 
     { 
      var destination = alertSubscription.GetConsumer(); 

      Type handlerType = typeof (INotificationHandler<,>) 
       .MakeGenericType(entity.GetType(), destination.GetType()); 

      using (var handler = 
       (INotificationCustomHandler)_container.ResolveOptional(handlerType)) 
      { 
       if (handler == null) continue; 

       try 
       { 
        Retry.Execute(() => (handler).Send(entity, destination), 3, 500); 
        monitoringContext.Record(CheckCycleContext.CycleSeverity.Information, 
         string.Format("NotificationPublisher.Publish:{0}/{1}", 
          entity.GetType().Name, destination.GetType().Name), "Success"); 
       } 
       catch (Exception ex) 
       { 
        monitoringContext.Record(CheckCycleContext.CycleSeverity.Error, 
         string.Format("NotificationPublisher.Publish:{0}/{1}", 
          entity.GetType().Name, destination.GetType().Name), ex.Message, ex, 
           new {entity, destination}); 
       } 
      } 
     } 
     return alertSubscriptions; 
    } 
} 

Я предполагаю, что, поскольку INotificationCustomHandler вручную разрешается, необходимо вручную утилизировать с утверждением использованием, becuase реализации INotificationCustomHandler впрыскивают с реализациями IManager, который вводится с реализациями IRepository.

Таким образом, в этой ситуации мне нужно распространять IDisposable всюду по моей кодовой базе, которая противоречит тому, что я предложил в предыдущем SO-вопросе.

Как вручную разрешать объекты с помощью заводов, если это необходимо, и при этом разрешить использование Autofac?

ответ

2

Когда Autofac решить компонент, который реализует IDisposable этот один будет связан с областью, который был настроен при регистрации его. Когда эта область будет удалена, все связанные компоненты также будут удалены. См. http://autofac.readthedocs.org/en/latest/lifetime/disposal.html для получения дополнительной информации.

В вашем случае, если INotificationCustomHandler зарегистрирован как InstancePerDependency (по умолчанию) или InstancePerLifetimeScope, INotificationCustomHandler разрешаемых _container, будет захоронен, когда _container будет расположен слишком.

Если это то, что вы хотите, вам не нужно звонить .Dispose на эти компоненты.

Если вы хотите вручную управлять временем жизни ваших объектов, вы можете создать свою собственную сферу жизни.

using(ILifetimeScope scope = this._container.BeginLifetimeScope()) 
{ 
    var handler = (INotificationCustomHandler)scope.ResolveOptional(handlerType); 
    if(handler != null) 
    { 
     Retry.Execute(() => handler.Send(entity, destination)); 
    } 
} // handler will be disposed here if needed 

вы также должны взглянуть на owned instance, который действует как мини-завод.

if(!container.ComponentRegistry.IsRegistered(new TypedService(handlerType))) 
{ 
    continue; 
} 

Type handlerFactoryType = typeof(Func<>).MakeGenericType(
          typeof(Owned<>).MakeGenericType(handlerType)); 
var handlerFactory = (Func<Owned<INotificationCustomHandler>>)container 
          .Resolve(handlerFactoryType); 

using(Owned<INotificationCustomHandler> ownedHandler = handlerFactory()) 
{ 
    INotificationCustomHandler handler = ownedHandler.Value; 
    Retry.Execute(() => handler.Send(entity, destination), 3, 500); 
} // handler will be disposed here 
Смежные вопросы