Autofac,IDisposable和手动呼叫。在某些情况下解决

时间:2015-05-18 02:13:12

标签: c# dependency-injection autofac idisposable

我在IDisposable对象和使用Autofac时发布了一般指南问题:Dependency Injection and IDisposable。不幸的是,我没有考虑到我们项目中的一个特定场景,而且它本身就是一个单独的问题,因此会在这里提出问题:

我有一个Repository对象来管理其中的会话对象的生命周期。因此,Repository对象是IDisposable并且销毁会话(Repository在构造时注入工厂委托,在第一次使用期间实例化会话,并且如果session不为null则在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的实现,这些实现注入了IRepository的实现。 / p>

因此,在这种情况下,我需要在整个代码库中传播IDisposable,这违反了之前的SO问题中的建议。

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

1 个答案:

答案 0 :(得分:2)

Autofac 解析实现IDisposable的组件时,此组件将与您在注册​​时配置的范围链接。当处理此范围时,所有链接的组件也将被处理。有关详细信息,请参阅http://autofac.readthedocs.org/en/latest/lifetime/disposal.html

在您的情况下,如果INotificationCustomHandler注册为InstancePerDependency(默认)或InstancePerLifetimeScopeINotificationCustomHandler_container解决,则会在{_container时处理1}}也将被处理掉。

如果这是您想要的,则不必在这些组件上致电.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 
相关问题