ทำความเข้าใจแนวคิดขอบเขตอายุการใช้งานใน Autofac

ขออภัยฉันเพิ่งเรียนรู้ Autofac ฉันมีปัญหาในการทำความเข้าใจ Lifetime scope ใน Autofac โปรดช่วยตรวจสอบด้านล่าง

สมมติว่าเรามีรหัสด้านล่าง

using(var scope = container.BeginLifetimeScope())
{
  // Resolve services from a scope that is a child
  // of the root container.
  var service = scope.Resolve<IService>();

  // You can also create nested scopes...
  using(var unitOfWorkScope = scope.BeginLifetimeScope())
  {
    var anotherService = unitOfWorkScope.Resolve<IOther>();
  }
}

ตามเอกสาร ใส่ Lifetime scopes are disposable and they track component disposal.

หมายความว่า service ใช้แล้วทิ้งและ GC สามารถรีไซเคิลได้หลังจากระบุคำสั่ง using(var scope = container.BeginLifetimeScope()) เสร็จแล้วใช่หรือไม่

และมันจะเป็นเช่นนั้นกับ anotherService ในขอบเขตที่ซ้อนกันหรือไม่ ?

ฉันจะเป็นพยานด้วยการทดลองบางอย่างได้อย่างไร?

ขอบคุณ.


person Joe.wang    schedule 14.12.2016    source แหล่งที่มา


คำตอบ (1)


ฉันคิดว่าคุณต้องเข้าใจก่อนว่า Autofac อนุญาตให้ลงทะเบียนส่วนประกอบที่มีอายุการใช้งานต่างกัน:

  • อายุการใช้งานชั่วคราวผ่าน InstancePerDependency ซึ่งหมายความว่าคอนเทนเนอร์จะสร้างอินสแตนซ์ใหม่ทุกครั้งที่ขอให้แก้ไขส่วนประกอบ
  • ต่อขอบเขตอายุการใช้งาน ผ่าน InstancePerLifetimeScope ซึ่งหมายความว่าคอนเทนเนอร์จะแก้ไขเป็นอินสแตนซ์เดียวกันของส่วนประกอบในขอบเขตอายุการใช้งานที่ระบุ
  • ซิงเกิลตัน ผ่าน SingleInstance ในกรณีนี้ คอนเทนเนอร์จะสร้างอินสแตนซ์ได้มากที่สุด 1 รายการ

แล้วการติดตามการกำจัดส่วนประกอบหมายถึงอะไร?

หมายความว่าทุกขอบเขตอายุการใช้งานจะติดตามส่วนประกอบที่เป็นเจ้าของ เมื่อมีการกำจัดขอบเขตอายุการใช้งาน ส่วนประกอบทุกชิ้นที่เป็นกรรมสิทธิ์ซึ่งใช้แล้วทิ้ง - เช่น การดำเนินการ IDisposable - จะถูกกำจัดทิ้ง

แล้วส่วนประกอบของฉันจะถูกกำจัดเมื่อใด?

ย้อนกลับไปข้อแรกก็ขึ้นอยู่กับว่าเคยลงทะเบียนด้วยอายุไหน

  • หากส่วนประกอบได้รับการลงทะเบียนด้วยอายุการใช้งานชั่วคราว อินสแตนซ์ทั้งหมด จะถูกกำจัดเมื่อมีการกำจัดขอบเขตอายุการใช้งานที่เป็นเจ้าของ

  • หากได้รับการลงทะเบียนเป็นขอบเขตต่ออายุการใช้งาน หนึ่งอินสแตนซ์ จะถูกกำจัดเมื่อขอบเขตอายุการใช้งานที่เป็นเจ้าของถูกกำจัด

  • หากส่วนประกอบได้รับการลงทะเบียนเป็นซิงเกิลตัน อินสแตนซ์จะเป็นเจ้าของโดยขอบเขตอายุการใช้งานรูท และจะถูกกำจัดเมื่อมีการกำจัดขอบเขตอายุการใช้งานรูทนั้นเท่านั้น

รหัสสนับสนุนบางส่วน

public class TransientService : IDisposable
{
    private static int _instanceCount = 0;
    private readonly int _instanceNumber;

    public TransientService()
    {
        _instanceCount++;
        _instanceNumber = _instanceCount;

        Console.WriteLine($"Just created TransientService #{_instanceNumber}");
    }

    public void Dispose()
    {
        Console.WriteLine($"Disposing TransientService #{_instanceNumber}");
    }
}

public class LifetimeScopeService : IDisposable
{
    private static int _instanceCount = 0;
    private readonly int _instanceNumber;

    public LifetimeScopeService()
    {
        _instanceCount++;
        _instanceNumber = _instanceCount;

        Console.WriteLine($"Just created LifetimeScopeService #{_instanceNumber}");
    }

    public void Dispose()
    {
        Console.WriteLine($"Disposing LifetimeScopeService #{_instanceNumber}");
    }
}

public class SingletonService : IDisposable
{
    private static int _instanceCount = 0;
    private readonly int _instanceNumber;

    public SingletonService()
    {
        _instanceCount++;
        _instanceNumber = _instanceCount;

        Console.WriteLine($"Just created SingletonService #{_instanceNumber}");
    }

    public void Dispose()
    {
        Console.WriteLine($"Disposing SingletonService #{_instanceNumber}");
    }
}

class Program
{
    static void Main(string[] args)
    {
        var builder = new ContainerBuilder();

        builder
            .RegisterType<TransientService>()
            .AsSelf()
            .InstancePerDependency();

        builder
            .RegisterType<LifetimeScopeService>()
            .AsSelf()
            .InstancePerLifetimeScope();

        builder
            .RegisterType<SingletonService>()
            .AsSelf()
            .SingleInstance();

        using (var container = builder.Build())
        {
            Console.WriteLine("Created the root scope");

            var rootTransientService = container.Resolve<TransientService>();
            var rootLifetimeScopeService = container.Resolve<LifetimeScopeService>();
            var rootSingletonService = container.Resolve<SingletonService>();

            var rootTransientServiceTwo = container.Resolve<TransientService>();
            var rootLifetimeScopeServiceTwo = container.Resolve<LifetimeScopeService>();
            var rootSingletonServiceTwo = container.Resolve<SingletonService>();

            using (var outerLifetimeScope = container.BeginLifetimeScope())
            {
                Console.WriteLine("Created the outer lifetime scope");

                var outerTransientService = outerLifetimeScope.Resolve<TransientService>();
                var outerLifetimeScopeService = outerLifetimeScope.Resolve<LifetimeScopeService>();
                var outerSingletonService = outerLifetimeScope.Resolve<SingletonService>();

                var outerTransientServiceTwo = outerLifetimeScope.Resolve<TransientService>();
                var outerLifetimeScopeServiceTwo = outerLifetimeScope.Resolve<LifetimeScopeService>();
                var outerSingletonServiceTwo = outerLifetimeScope.Resolve<SingletonService>();

                using (var innerLifetimeScope = container.BeginLifetimeScope())
                {
                    Console.WriteLine("Created the inner lifetime scope");

                    var innerTransientService = innerLifetimeScope.Resolve<TransientService>();
                    var innerLifetimeScopeService = innerLifetimeScope.Resolve<LifetimeScopeService>();
                    var innerSingletonService = innerLifetimeScope.Resolve<SingletonService>();

                    var innerTransientServiceTwo = innerLifetimeScope.Resolve<TransientService>();
                    var innerLifetimeScopeServiceTwo = innerLifetimeScope.Resolve<LifetimeScopeService>();
                    var innerSingletonServiceTwo = innerLifetimeScope.Resolve<SingletonService>();
                }

                Console.WriteLine("Disposed the inner lifetime scope");
            }

            Console.WriteLine("Disposed the outer lifetime scope");
        }

        Console.WriteLine("Disposed the root scope");

        Console.ReadLine();
    }
}

3 บริการ หนึ่งรายการต่อหนึ่งอายุการใช้งานที่ Autofac รองรับ โปรแกรมนี้ง่ายมาก เรามีขอบเขตอายุการใช้งานรูท ขอบเขตอายุการใช้งานภายนอก และขอบเขตอายุการใช้งานภายใน

ขอบเขตอายุการใช้งานแต่ละรายการจะแก้ไข 2 อินสแตนซ์ของแต่ละบริการ ดังนั้นแต่ละบริการจะได้รับการแก้ไข 6 ครั้ง นี่คือผลลัพธ์:

Created the root scope

    Just created TransientService #1
    Just created LifetimeScopeService #1
    Just created SingletonService #1
    Just created TransientService #2

        Created the outer lifetime scope

            Just created TransientService #3
            Just created LifetimeScopeService #2
            Just created TransientService #4

                Created the inner lifetime scope

                    Just created TransientService #5
                    Just created LifetimeScopeService #3
                    Just created TransientService #6

                    Disposing TransientService #6
                    Disposing LifetimeScopeService #3
                    Disposing TransientService #5

                Disposed the inner lifetime scope

            Disposing TransientService #4
            Disposing LifetimeScopeService #2
            Disposing TransientService #3

        Disposed the outer lifetime scope

    Disposing TransientService #2
    Disposing SingletonService #1
    Disposing LifetimeScopeService #1
    Disposing TransientService #1

Disposed the root scope

ข้อสังเกตบางประการ โปรดจำไว้เสมอว่าบริการทั้งหมดได้รับการแก้ไขแล้ว 6 ครั้งด้วยขอบเขตอายุการใช้งานที่แตกต่างกัน 3

  • เราลงเอยด้วย TransientService 6 อินสแตนซ์ ซึ่งตรงกับการลงทะเบียนที่เราทำกับคอนเทนเนอร์ ตามหลักการกำจัด แต่ละขอบเขตอายุการใช้งานจะกำจัดอินสแตนซ์ 2 ตัวเมื่อตัวมันเองถูกกำจัด

  • สร้าง LifetimeScopeService เพียง 3 รายการเท่านั้น แม้ว่าแต่ละขอบเขตอายุการใช้งานจะแก้ไขบริการนี้สองครั้ง Autofac จะส่งคืนอินสแตนซ์เดียวกันในครั้งที่สองที่ได้รับการแก้ไขภายในขอบเขตอายุการใช้งานเดียวกันเสมอ แต่ละอินสแตนซ์จะถูกกำจัดตามขอบเขตอายุการใช้งานที่เป็นเจ้าของ

  • มี SingletonService เพียง 1 อินสแตนซ์ตลอดทั้งแอปพลิเคชัน ไม่มีขอบเขตขอบเขตอายุการใช้งานที่นี่เนื่องจากขอบเขตอายุการใช้งานทั้ง 3 ได้รับการแก้ไขเป็นอินสแตนซ์เดียวกันของบริการ ซึ่งจะถูกกำจัดเมื่อมีการกำจัดขอบเขตระดับราก

แก้ไข: เยื้องเอาต์พุตเพื่อให้อ่านง่ายขึ้น และทำให้ลำดับชั้นชัดเจนยิ่งขึ้น

person Mickaël Derriey    schedule 14.12.2016
comment
ขออภัยที่มาช้า. อธิบายได้ดีและเป็นตัวอย่างที่ดี+1 ชื่นชมมาก ขอบคุณมาก. - person Joe.wang; 16.07.2017
comment
@Mickael Derriey เป็นเรื่องดีที่จะประกาศอายุการใช้งานชั่วคราวหากเรามีคำขอ 100,000 รายการ - person Saineshwar; 21.08.2019
comment
ไม่แน่ใจว่าคุณหมายถึงอะไร คุณช่วยอธิบายเพิ่มเติมได้ไหม - person Mickaël Derriey; 21.08.2019
comment
ขอบคุณ. ฉันจำเป็นต้องทดสอบสมมติฐานของฉันเกี่ยวกับ SingleInstance() เมื่อลงทะเบียนในขอบเขตลูก และสิ่งนี้ช่วยฉันประหยัดเวลาได้มาก หากคุณไม่ว่าอะไร ฉันใส่ไว้ใน GitHub: github.com /rhyous/Autofac.Examples/tree/master/src/ - person Rhyous; 17.12.2019