DI & IoC - 使用Unity.MVC讓ASP.NET Framework4.8實現DI注入

使用Unity.MVC讓ASP.NET Framework4.8 MVC實現DI注入

在.Net(Core)的DI注入功能是內建的,我們在Program.cs裡面就可以直接設定介面跟要對應的實作類別。但在.Net Framework4.8 MVC還沒有內建DI容器這種東西,所以必須要另外安裝DI套件,才能實現依賴注入(DI)


安裝套件Unity & Unity.Mvc5

可以透過NuGet來安裝


建立設定檔UnityConfig.cs

在App_Start資料夾底下,新增UnityConfig.cs,預設內容如下。

using Unity;

using Unity.Mvc5;

    public static class UnityConfig
    {
        public static void RegisterComponents()
        {
			var container = new UnityContainer();
			
            // register all your components with the container here
            // it is NOT necessary to register your controllers

            // e.g. container.RegisterType<ITestService, TestService>();

            DependencyResolver.SetResolver(new UnityDependencyResolver(container));
        }
    }

建立對應
using Unity;
using Unity.Injection; //新增namespace
using Unity.Mvc5;
    
    public static class UnityConfig
    {
        public static void RegisterComponents()
        {
			var container = new UnityContainer();
			var rootPath = HttpRuntime.AppDomainAppPath;
            string txtFilePath = System.IO.Path.Combine(rootPath, "Areas", "Viewer", "Content", "test_log.txt");
			
            // register all your components with the container here
            // it is NOT necessary to register your controllers

            // e.g. container.RegisterType<ITestService, TestService>();
            container.RegisterType<ILogService, TxtLogService>(new InjectionConstructor(txtFilePath)); //建立介面(ILogService)跟低階類別(TxtLogService)的對應

            DependencyResolver.SetResolver(new UnityDependencyResolver(container));
        }
    }
    public interface ILogService
    {
        void LogClear();
        void Log(string content);
    }
    public class TxtLogService: ILogService
    {
        private readonly string _filePath;

        public TxtLogService(string filePath)
        {
            _filePath = filePath;
        }

        public void LogClear()
        {
            // 使用StreamWriter清空文件内容
            using (StreamWriter writer = new StreamWriter(_filePath, false))
            {
                writer.Write(string.Empty);
            }
        }

        public void Log(string content)
        {
            using (StreamWriter writer = new StreamWriter(_filePath, true))
            {
                writer.WriteLine($"{content}\r\n");
            }
        }
    }

建構子注入 & 應用
    public class TestController : BaseController
    {
    	private readonly ILogService _logService;
    	
    	public TestController(
    		ILogService logService
    	)
    	{
    		_logService = logService
    	}
    	
    	public async Task<ActionResult> Index()
    	{
			_logService.LogClear();
            _logService.Log($"point-start. => {DateTime.Now}");
    	}
    }

底層類別替換
//UnityConfig.cs
container.RegisterType<ILogService, MailLogService>(); //低階類別TxtLogService替換成MailLogService
    public class MailLogService: ILogService
    {
        public void LogClear()
        {
            實作內容省略
...
        }

        public void Log(string content)
        {
            實作內容省略
...        
        }
    }

生命週期設定

在.Net(Core)的DI裡,注入的服務會有生命週期(請參考:.Net Core DI 服務生命週期)。

 .Net(Core)Unity.MVC
每次Post/Get Request在Application結束前,
都會使用相同的instance
builder.Services.AddScoped<ILogService, MailLogService>();container.RegisterType<ILogService, MailLogService>(new PerRequestLifetimeManager());
每次注入都會建立新的instancebuilder.Services.AddTransient<ILogService, MailLogService>();container.RegisterType<ILogService, MailLogService>(new TransientLifetimeManager());
應用程式從開始到結束,使用的都是同一個instancebuilder.Services.AddSingleton<ILogService, MailLogService>();container.RegisterType<ILogService, MailLogService>(new ContainerControlledLifetimeManager());