Search code examples
c#autofac

ExternallyOwned() doesn't work on Assembly Scanning level?


I have the following classes inside the Assembly AutofacDotMemory

public interface IOutput:IDisposable
{
    void Write(string content);
}


public class ConsoleOutput : IOutput
{
    public void Write(string content)
    {
        Console.WriteLine(content);
    }

    public void Dispose()
    {
        // TODO release managed resources here
    }
}


public interface IDateWriter:IDisposable
{
    void WriteDate();
}



public class TodayWriter : IDateWriter
{
    private IOutput _output;
    public TodayWriter( IOutput output)
    {
        this._output = output;
    }

    public void WriteDate()
    {
        this._output.Write(DateTime.Today.ToShortDateString());
    }

    public void Dispose()
    {
        // TODO release managed resources here
    }
}

And in my another test assembly I've also referred to Autofac and I try to use ExternallyOwned at assembly scanning level, with the following test code:

    [Test]
    public void ExternallyOwnedTest()
    {
        var builder = new ContainerBuilder();


        builder.RegisterAssemblyTypes(typeof(IDateWriter).Assembly)
            .ExternallyOwned();

        builder.RegisterType<ConsoleOutput>().As<IOutput>();
        builder.RegisterType<TodayWriter>().As<IDateWriter>();


        var container = builder.Build();

        var registration = container.ComponentRegistry.TryGetRegistration(new TypedService(typeof(IDateWriter)), out var foundRegistration);

        TestContext.WriteLine(registration);

        var isExternallyOwned = registration && foundRegistration.Ownership == InstanceOwnership.ExternallyOwned;

        Assert.IsTrue(isExternallyOwned, $"{nameof(TodayWriter)} is not externally owned");
        container.Dispose();
    }

And the test fails because TodayWriter is not ExternallyOwned.

But if I change the registration code to the below, so that it's done on per registration type basis:

 var builder = new ContainerBuilder();
    
    builder.RegisterType<ConsoleOutput>().As<IOutput>();
    builder.RegisterType<TodayWriter>().As<IDateWriter>().ExternallyOwned(); //now this works
    
    
    var container = builder.Build();
    
    var registration = container.ComponentRegistry.TryGetRegistration(new TypedService(typeof(IDateWriter)), out var foundRegistration);
    
   TestContext.WriteLine(registration);
    
   var isExternallyOwned = registration && foundRegistration.Ownership == InstanceOwnership.ExternallyOwned;
    
    Assert.IsTrue(isExternallyOwned, $"{nameof(TodayWriter)} is not externally owned");
    container.Dispose();

And now this test passes because TodayWriter is externally owned.

How to ensure that all of the types in a given assembly ( or at least the majority of the types, subjected to a Where filter condition) is registered as ExternallyOwned? I don't want to go through all of the registered type and add an ExternallyOwned keyword there.


Solution

  • In your test...

            builder.RegisterAssemblyTypes(typeof(IDateWriter).Assembly)
                .ExternallyOwned();
    
            builder.RegisterType<ConsoleOutput>().As<IOutput>();
            builder.RegisterType<TodayWriter>().As<IDateWriter>();
    

    You registered TodayWriter twice. Once through the assembly scanning, once manually.

    In the assembly scanning it got registered as ExternallyOwned. But then you overrode that and registered it as normal, which is not ExternallyOwned. In registrations, last in wins.