【问题标题】:Autofac, IDisposable and manually calling .Resolve in certain circumstancesAutofac、IDisposable 和手动调用 .Resolve 在某些情况下
【发布时间】:2015-05-18 02:13:11
【问题描述】:

关于 IDisposable 对象并在此处使用 Autofac,我已经发布了一个一般准则问题:Dependency Injection and IDisposable。不幸的是,我没有考虑我们项目中的一个特定场景,这确实是一个独立的问题,所以在这里提出:

我有一个 Repository 对象,用于管理其中的会话对象的生命周期。因此,Repository 对象是 IDisposable 并销毁会话(Repository 在构造时注入工厂委托,在第一次使用期间实例化会话,如果会话不为空,则在 IDisposable 中销毁会话)。根据上面对 StackOverflow 问题的引用,我了解任何使用我的 Repository 对象注入的对象都不应该实现 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 是手动解析的,因此必须使用 using 语句手动处理它,因为 INotificationCustomHandler 的实现注入了 IManager 的实现,而 IManager 的实现注入了 IRepository 的实现。

因此,在这种情况下,我需要在整个代码库中传播 IDisposable,这与我在之前的 SO 问题中提出的建议背道而驰。

如何在需要时通过工厂手动解析对象,而让 Autofac 处理处置?

【问题讨论】:

    标签: c# dependency-injection autofac idisposable


    【解决方案1】:

    Autofac 解析实现IDisposable 的组件时,该组件将与您注册时配置的范围链接。当这个范围被释放时,所有链接的组件也将被释放。请参阅http://autofac.readthedocs.org/en/latest/lifetime/disposal.html 了解更多信息。

    在您的情况下,如果INotificationCustomHandler 注册为InstancePerDependency(默认)或InstancePerLifetimeScope,则由_container 解析的INotificationCustomHandler 将在_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 
    

    【讨论】:

    • 如果组件不是一次性的会怎样?
    • @Bondolin Owned 在您调用 dispose 时就像一个 LifeTimeScope,它将释放创建的生命周期范围,并且与此范围相关的所有资源都将被释放。这个问题的完整答案可能太长了,无法发表评论。如果您想了解更多信息,可以创建一个新问题
    • 已经做过 (stackoverflow.com/questions/60213990/…) -- 如果你想投入 2 美分,我会很感激反馈
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-02
    • 2013-05-21
    相关资源
    最近更新 更多