autofac/Autofac

Instantiated services not disposed on exception during IStartable

已關閉

#1,392 建立於 2023年8月29日

 (1 則留言) (2 個反應) (0 位負責人)C# (827 個分叉)batch import
bughelp wanted

倉庫指標

星標
 (4,327 顆星)
PR 合併指標
 (平均合併 3小時 24分鐘) (30 天內合併 10 個 PR)

描述

From stackoverflow: https://stackoverflow.com/questions/76991305/autofac-dispose-of-created-services-not-called-when-exception-is-thrown-by-late

I have the following, minimal example to reproduce an issue of my real life application:

public class ServiceA : IStartable, IDisposable {
    public required ServiceB ServiceB { get; set; }
    
    public void Start() {
        ServiceB.Connect();
    }

    public void Dispose() {
        Console.WriteLine("ServiceA disposed");
    }
}

public class ServiceB : IDisposable {
    public void Connect() {
        throw new TimeoutException();
    }
    
    public void Dispose() {
        Console.WriteLine("ServiceB disposed");
    }
}

and a console application:

var builder = new ContainerBuilder();

builder.RegisterType(typeof(ServiceA)).AsSelf().As<IStartable>().SingleInstance();
builder.RegisterType(typeof(ServiceB)).AsSelf().InstancePerDependency();

var container = builder.Build();

Console.ReadKey();

container.Dispose();

Console.ReadKey();

From dependency chain ServiceB is a dependency of ServiceA and, therfore, is instanciated first on Build(). During Start() of ServiceA, Connect() on ServiceB is called which throws an Exception. The Exception is forwared to Build() which fails and the container is not created.

My expectation reading Autofac docs

Automatic Disposal To take advantage of automatic deterministic disposal, your component must implement IDisposable. You can then register your component as needed and at the end of each lifetime scope in which the component is resolved, the Dispose() method on the component will be called.

would be, that Dipose() on created ServiceB is called. This is not the case. ServiceB lives somewhere in my application and I cannot dispose it as IContainer was not created.

ChatGPT suggest to catch the exception and call Dispose() on IContainer later. This would mean, I need to check if Connect() on ServiceB was successfull (property bool IsConnected) and if not, I call Dispose().

Of course, this would solve my issue. But again, my expecation was, that Autofac is handling this for me via LifetimeScope.

貢獻者指南