autofac / Autofac

An addictive .NET IoC container
https://autofac.org
MIT License
4.44k stars 836 forks source link

Decorators does not follow ExternallyOwned - problem with lifetime scope on decorator with `IDisposable` implementation #1402

Open fr4gles opened 8 months ago

fr4gles commented 8 months ago

Describe the Bug

According to documentation: You cannot specify a lifetime scope on a decorator. The lifetime of a decorator is tied to the lifetime of the thing it decorates. but it is not working when thing it decorates implements IDisposable

Steps to Reproduce

using Autofac;

Console.WriteLine("Hello, World!");

var builder = new ContainerBuilder();

builder.RegisterType<Parser>().As<IParser>().ExternallyOwned().InstancePerLifetimeScope();
builder.RegisterDecorator<ParserDecorator, IParser>(); // according to docs cant be marked as ExternallyOwned but has same lifetime as IParser

using var container = builder.Build(); // <== using --> Dispose() is called on ParserDecorator decorator even if IParser is ExternallyOwned
using var parser = container.Resolve<IParser>(); // <== using --> Dispose() is called on IParser
parser.Parse();

// Output (please notice Dispose() called twice):
/* 
Hello, World!
Before Parse
Parsing...
Parsed
After Parse
Disposed ParserDecorator
Disposed Parser
Disposed ParserDecorator
Disposed Parser
*/

public interface IParser : IDisposable
{
    void Parse();
}

public class Parser : IParser
{
    public void Parse()
    {
        Console.WriteLine("Parsing...");
        Console.WriteLine("Parsed");
    }

    public void Dispose()
    {
        Console.WriteLine("Disposed Parser");
    }
}

public class ParserDecorator : IParser
{
    private readonly IParser _parser;

    public ParserDecorator(IParser parser)
    {
        _parser = parser;
    }

    public void Parse()
    {
        Console.WriteLine("Before Parse");
        _parser.Parse();
        Console.WriteLine("After Parse");
    }

    public void Dispose()
    {
        Console.WriteLine("Disposed ParserDecorator");
        _parser.Dispose();
    }
}

Expected Behavior

Decorators follows "externally owned" state on "thing" it decorates.

Dependency Versions

Autofac: 7.1.0

Tags

autofac decorator externally owned idisposable