【UnityContainer】Lifetime 1
Tags: dotnetframework, csharp, aspnet, unitycontainer
Published: 2020-10-18 15:21:20

## Intro
When I use DI with ASP.NET Core app, I choose "Microsoft.Extensions.DependencyInjection".

It has three types of lifetime of instance.

* Transient
* Scoped
* Singleton

[Dependency injection in ASP.NET Core | Microsoft Docs](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-3.1#service-lifetimes)

Because I can't use "Microsoft.Extensions.DependencyInjection" with ASP.NET Framework, so when I use DI I choose Unity Container.

* [Welcome to Unity Container Documentation! | Unity Container](http://unitycontainer.org/index.html)

It also has "Transient", "Scoped", "Singleton".
"Transient"(every time creates new instances) and "Singleton"(creates only one instance in the application) are same as "Microsoft.Extensions.DependencyInjection".

But "Scoped" doesn't seem like "Microsoft.Extensions.DependencyInjection" one.
(creates instances per request)

Which types of lifetime should I choose to set "Scoped" of "Microsoft.Extensions.DependencyInjection"?

### Environments
* .NET Framework ver.4.8
* Unity.Container ver.5.11.8
* Unity.Mvc ver.5.11.1
* NLog.Web ver.4.9.3

## Sample projects
#### ProductsController.cs
```csharp
using System.Web.Mvc;
using NetFrameworkSample.Lifetimes;
using NetFrameworkSample.Products;
using NLog;

namespace NetFrameworkSample.Controllers
{
    public class ProductsController: Controller
    {
        private readonly Logger _logger;
        private readonly IProductsService _product;
        private readonly ISecondService _secondService;
        public ProductsController(IProductsService product,
            ISecondService secondService)
        {
            _logger = LogManager.GetCurrentClassLogger();
            _logger.Debug("ProductsController Constructor");
            _product = product;
            _secondService = secondService;
        }
        [Route("")]
        public ActionResult GetMessage()
        {
            return View("~/Views/ProductPage.cshtml");
        }
    }
}
```
#### ProductPage.cshtml
```csharp
@{
    ViewBag.Title = "ProductPage";
}
<h2>ProductPage</h2>
@Html.ActionLink("Sample", "Index", "Lifetime")
```
#### LifetimeController.cs
```csharp
using NetFrameworkSample.Products;
using NLog;
using System.Web.Mvc;

namespace NetFrameworkSample.Lifetimes
{
    public class LifetimeController : Controller
    {
        private readonly Logger _logger;
        private readonly IProductsService _product;
        private readonly ISecondService _secondService;
        public LifetimeController(IProductsService product,
            ISecondService secondService)
        {
            _logger = LogManager.GetCurrentClassLogger();
            _logger.Debug("LifetimeController Constructor");
            _product = product;
            _secondService = secondService;
        }
        [Route("Lifetime")]
        public string Index()
        {
            return View("~/Views/Lifetime/Index.cshtml");
        }
    }
}
```
#### Index.cshtml
```csharp
@{
    ViewBag.Title = "LifetimeSamplePage";
}
<h2>LifetimeSample</h2>
@Html.ActionLink("Sample", "GetMessage", "Products")
```
#### IProductsService.cs
```csharp
namespace NetFrameworkSample.Products
{
    public interface IProductsService
    { }
}
```
#### ProductsService.cs
```csharp
using NetFrameworkSample.Lifetimes;
using NLog;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace NetFrameworkSample.Products
{
    public class ProductsService: IProductsService
    {
        private readonly Logger _logger;
        private readonly IThirdService _thirdService;
        public ProductsService(IThirdService thirdService)
        {
            _logger = LogManager.GetCurrentClassLogger();
            _logger.Debug("ProductsService Constructor");
            _thirdService = thirdService;
        }
    }
}
```
#### ISecondService.cs
```csharp
namespace NetFrameworkSample.Lifetimes
{
    public interface ISecondService
    { }
}
```
#### SecondService.cs
```csharp
using NLog;

namespace NetFrameworkSample.Lifetimes
{
    public class SecondService: ISecondService
    {
        private readonly Logger _logger;
        private readonly IThirdService _thirdService;
        public SecondService(IThirdService thirdService)
        {
            _logger = LogManager.GetCurrentClassLogger();
            _logger.Debug("SecondService Constructor");
            _thirdService = thirdService;
        }
    }
}
```
#### IThirdService.cs
```csharp
namespace NetFrameworkSample.Lifetimes
{
    public interface IThirdService
    { }
}
```
#### ThirdService.cs
```csharp
using NLog;

namespace NetFrameworkSample.Lifetimes
{
    public class ThirdService: IThirdService
    {
        private readonly Logger _logger;
        public ThirdService()
        {
            _logger = LogManager.GetCurrentClassLogger();
            _logger.Debug("ThirdService Constructor");
        }
    }
}
```
#### UnityMvcActivator.cs
```csharp
using System.Linq;
using System.Web.Mvc;
using Unity.AspNet.Mvc;

[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(NetFrameworkSample.UnityMvcActivator), nameof(NetFrameworkSample.UnityMvcActivator.Start))]
[assembly: WebActivatorEx.ApplicationShutdownMethod(typeof(NetFrameworkSample.UnityMvcActivator), nameof(NetFrameworkSample.UnityMvcActivator.Shutdown))]

namespace NetFrameworkSample
{
    public static class UnityMvcActivator
    {
        public static void Start() 
        {
            FilterProviders.Providers.Remove(FilterProviders.Providers.OfType<FilterAttributeFilterProvider>().First());
            FilterProviders.Providers.Add(new UnityFilterAttributeFilterProvider(UnityConfig.Container));
            DependencyResolver.SetResolver(new UnityDependencyResolver(UnityConfig.Container));
        }
        public static void Shutdown()
        {
            UnityConfig.Container.Dispose();
        }
    }
}
```
## Transient, Scoped, Singleton
I try changing lifetime and accessing "ProductsController" and "LifetimeController".
After that, I check logs to know when and how many times are instances created.

### Transient
#### UnityConfig.cs
```csharp
using System;
using Unity;
using NetFrameworkSample.Products;
using NetFrameworkSample.Lifetimes;

namespace NetFrameworkSample
{
    public static class UnityConfig
    {
        private static Lazy<IUnityContainer> container =
          new Lazy<IUnityContainer>(() =>
          {
              var container = new UnityContainer();
              RegisterTypes(container);
              container.RegisterType<IProductsService, ProductsService>(TypeLifetime.Transient);
              container.RegisterType<ISecondService, SecondService>(TypeLifetime.Transient);
              container.RegisterType<IThirdService, ThirdService>(TypeLifetime.Transient);
              return container;
          });
        public static IUnityContainer Container => container.Value;
        public static void RegisterTypes(IUnityContainer container)
        { }
    }
}
```
#### Result
```
--- Transient ---
--- Access "ProductsController" ---
2020-10-18 19:00:57.2576||DEBUG|NetFrameworkSample.Lifetimes.ThirdService|ThirdService Constructor |url: http://localhost/|action: 
2020-10-18 19:00:57.3281||DEBUG|NetFrameworkSample.Products.ProductsService|ProductsService Constructor |url: http://localhost/|action: 
2020-10-18 19:00:57.3281||DEBUG|NetFrameworkSample.Lifetimes.ThirdService|ThirdService Constructor |url: http://localhost/|action: 
2020-10-18 19:00:57.3281||DEBUG|NetFrameworkSample.Lifetimes.SecondService|SecondService Constructor |url: http://localhost/|action: 
2020-10-18 19:00:57.3281||DEBUG|NetFrameworkSample.Controllers.ProductsController|ProductsController Constructor |url: http://localhost/|action: 

--- Access "LifetimeController" ---
2020-10-18 19:03:57.6918||DEBUG|NetFrameworkSample.Lifetimes.ThirdService|ThirdService Constructor |url: http://localhost/Lifetime|action: 
2020-10-18 19:03:57.6918||DEBUG|NetFrameworkSample.Products.ProductsService|ProductsService Constructor |url: http://localhost/Lifetime|action: 
2020-10-18 19:03:57.6918||DEBUG|NetFrameworkSample.Lifetimes.ThirdService|ThirdService Constructor |url: http://localhost/Lifetime|action: 
2020-10-18 19:03:57.6918||DEBUG|NetFrameworkSample.Lifetimes.SecondService|SecondService Constructor |url: http://localhost/Lifetime|action: 
2020-10-18 19:03:57.6918||DEBUG|NetFrameworkSample.Lifetimes.LifetimeController|LifetimeController Constructor |url: http://localhost/Lifetime|action: 
```

All instances were created each time.

### Singleton
#### UnityConfig.cs
```csharp
using System;
using Unity;
using NetFrameworkSample.Products;
using NetFrameworkSample.Lifetimes;

namespace NetFrameworkSample
{
    public static class UnityConfig
    {
        private static Lazy<IUnityContainer> container =
          new Lazy<IUnityContainer>(() =>
          {
              var container = new UnityContainer();
              RegisterTypes(container);
              container.RegisterType<IProductsService, ProductsService>(TypeLifetime.Singleton);
              container.RegisterType<ISecondService, SecondService>(TypeLifetime.Singleton);
              container.RegisterType<IThirdService, ThirdService>(TypeLifetime.Singleton);
              return container;
          });
        public static IUnityContainer Container => container.Value;
        public static void RegisterTypes(IUnityContainer container)
        { }
    }
}
```
#### Result
```
--- Singleton ---
--- Access "ProductsController" ---
2020-10-18 18:58:16.1776||DEBUG|NetFrameworkSample.Lifetimes.ThirdService|ThirdService Constructor |url: http://localhost/|action: 
2020-10-18 18:58:16.2536||DEBUG|NetFrameworkSample.Products.ProductsService|ProductsService Constructor |url: http://localhost/|action: 
2020-10-18 18:58:16.2536||DEBUG|NetFrameworkSample.Lifetimes.SecondService|SecondService Constructor |url: http://localhost/|action: 
2020-10-18 18:58:16.2536||DEBUG|NetFrameworkSample.Controllers.ProductsController|ProductsController Constructor |url: http://localhost/|action: 

--- Access "LifetimeController" ---
2020-10-18 18:59:39.8770||DEBUG|NetFrameworkSample.Lifetimes.LifetimeController|LifetimeController Constructor |url: http://localhost/Lifetime|action: 
```

Exclude controller classes, all instances are created only one time.

### Scoped
#### UnityConfig.cs
```csharp
using System;
using Unity;
using NetFrameworkSample.Products;
using NetFrameworkSample.Lifetimes;

namespace NetFrameworkSample
{
    public static class UnityConfig
    {
        private static Lazy<IUnityContainer> container =
          new Lazy<IUnityContainer>(() =>
          {
              var container = new UnityContainer();
              RegisterTypes(container);
              container.RegisterType<IProductsService, ProductsService>(TypeLifetime.Scoped);
              container.RegisterType<ISecondService, SecondService>(TypeLifetime.Scoped);
              container.RegisterType<IThirdService, ThirdService>(TypeLifetime.Scoped);
              return container;
          });
        public static IUnityContainer Container => container.Value;
        public static void RegisterTypes(IUnityContainer container)
        { }
    }
}
```
#### Result
```
--- Scoped ---
--- Access "ProductsController" ---
2020-10-18 19:05:05.4487||DEBUG|NetFrameworkSample.Lifetimes.ThirdService|ThirdService Constructor |url: http://localhost/|action: 
2020-10-18 19:05:05.5336||DEBUG|NetFrameworkSample.Products.ProductsService|ProductsService Constructor |url: http://localhost/|action: 
2020-10-18 19:05:05.5336||DEBUG|NetFrameworkSample.Lifetimes.SecondService|SecondService Constructor |url: http://localhost/|action: 
2020-10-18 19:05:05.5336||DEBUG|NetFrameworkSample.Controllers.ProductsController|ProductsController Constructor |url: http://localhost/|action: 

--- Access "LifetimeController" ---
2020-10-18 19:05:28.1375||DEBUG|NetFrameworkSample.Lifetimes.LifetimeController|LifetimeController Constructor |url: http://localhost/Lifetime|action: 
```

According to the results, the lifetime of "Scoped" is same as "Singleton".

### What is "Scoped"?
According to the documents, when the lifetime is set as "Scoped", "Unity returns a unique value for each scope".

* [Class TypeLifetime | Unity Container](http://unitycontainer.org/api/Unity.TypeLifetime.html)

Now, I want to know, what is the scope?

According to the "Remarks", "this lifetime creates local singleton for each level of the hierarchy".
And by default, the application has only one container.

So in this sample, "Scoped" lifetime is as same as "Singleton".

## How to create instance per request?
I also tried "ContainerControlled", "External", "Hierarchical", "PerContainer", "PerContainerTransient", "PerResolve", and "PerThread".
According to the result, I think I shall choose "PerResolve" to create instance per request.

#### UnityConfig.cs
```csharp
using System;
using Unity;
using NetFrameworkSample.Products;
using NetFrameworkSample.Lifetimes;

namespace NetFrameworkSample
{
    public static class UnityConfig
    {
        private static Lazy<IUnityContainer> container =
          new Lazy<IUnityContainer>(() =>
          {
              var container = new UnityContainer();
              RegisterTypes(container);
              container.RegisterType<IProductsService, ProductsService>(TypeLifetime.PerResolve);
              container.RegisterType<ISecondService, SecondService>(TypeLifetime.PerResolve);
              container.RegisterType<IThirdService, ThirdService>(TypeLifetime.PerResolve);
              return container;
          });
        public static IUnityContainer Container => container.Value;
        public static void RegisterTypes(IUnityContainer container)
        { }
    }
}
```
#### Result
```
--- PerResolve ---
--- Access "ProductsController" ---
2020-10-19 00:13:47.1347||DEBUG|NetFrameworkSample.Lifetimes.ThirdService|ThirdService Constructor |url: http://localhost/|action: 
2020-10-19 00:13:47.2177||DEBUG|NetFrameworkSample.Products.ProductsService|ProductsService Constructor |url: http://localhost/|action: 
2020-10-19 00:13:47.2177||DEBUG|NetFrameworkSample.Lifetimes.SecondService|SecondService Constructor |url: http://localhost/|action: 
2020-10-19 00:13:47.2177||DEBUG|NetFrameworkSample.Controllers.ProductsController|ProductsController Constructor |url: http://localhost/|action: 

--- Access "LifetimeController" ---
2020-10-19 00:14:09.9652||DEBUG|NetFrameworkSample.Lifetimes.ThirdService|ThirdService Constructor |url: http://localhost/Lifetime|action: 
2020-10-19 00:14:09.9672||DEBUG|NetFrameworkSample.Products.ProductsService|ProductsService Constructor |url: http://localhost/Lifetime|action: 
2020-10-19 00:14:09.9672||DEBUG|NetFrameworkSample.Lifetimes.SecondService|SecondService Constructor |url: http://localhost/Lifetime|action: 
2020-10-19 00:14:09.9672||DEBUG|NetFrameworkSample.Lifetimes.LifetimeController|LifetimeController Constructor |url: http://localhost/Lifetime|action: 
```

* [Class TypeLifetime | Unity Container](http://unitycontainer.org/api/Unity.TypeLifetime.html#Unity_TypeLifetime_PerResolve)

But I haven't understand how to use child containers.
So there may be any other way what I shall choose.
Next time, I will try.