iT邦幫忙

2021 iThome 鐵人賽

DAY 11
1
自我挑戰組

.NET Core MVC網頁應用開發系列 第 12

.NET Core第12天_服務依賴注入_IoC容器生命週期_ConfigureServices

我們前面有示範幾種
服務注入
比方
注入MVC服務
services.AddMvc();

注入EF資料庫服務
services.AddDbContext(options =>options.UseSqlServer(Configuration.GetConnectionString("DbConnectonString")));

注入驗證服務
services.AddAuthentication();

全寫在Startup.cs的
public void ConfigureServices(IServiceCollection services)方法當中

關於依賴注入部分可以參考之前篇章
Dependency Injection原理與實踐(一)

何謂IoC Container
Inversion of Control 控制反轉
把對於某個物件的控制權移轉給第三方容器,藉此原本兩物件互相依賴變更為
兩物件都依賴於第三方物件(俗稱容器)
https://ithelp.ithome.com.tw/upload/images/20210914/20107452ah6qRQkqmi.png

在.net core內建的Container Service就是IServiceCollection這個型別
用於註冊服務到.net core容器中,預設支援constructor injection。

那事實上還有其餘很多方法
https://ithelp.ithome.com.tw/upload/images/20210914/20107452JrjwP7gJdE.png

生命週期:
Transient:每次被請求都會創建新的實體
Transient objects are always different; a new instance is provided to every controller and every service.

Scoped:每次Web請求會創建一個新實體,直到web請求結束就銷毀。
Scoped objects are the same within a request, but different across different requests.

Singleton:一旦被創建實體就會持續一直用,直到應用停止才銷毀。
Singleton objects are the same for every object and every request.

https://ithelp.ithome.com.tw/upload/images/20210914/20107452HmfXS4wMKU.png

新增一個.net core Model-View-Controller專案
並添加一個新的控制器取名為ProductController
https://ithelp.ithome.com.tw/upload/images/20210914/20107452kZkkuaMroX.png

add new folder 命名為Database
並新增interface命名為 IProductService,定義要實作的兩個method 規格
分別是getInstanceId()跟getProductName()。
另外新增額外實作該介面的具體Class ProductService
https://ithelp.ithome.com.tw/upload/images/20210914/20107452jcMBvwg135.png

IProductService.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace ContainerServiceMethods.Database
{
    public interface IProductService
    {
        string getInstanceId();
        string getProductName(int id);
    }
}

ProductService.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace ContainerServiceMethods.Database
{
    public class ProductService : IProductService
    {
        string InstanceId { get; set; }
        public ProductService()
        {
            InstanceId = Guid.NewGuid().ToString();
        }
        public string getInstanceId()
        {
            return InstanceId;
        }
        public string getProductName(int id)
        {
            return "愛之味-牛奶花生";
        }
    }
}

在這我們為了驗證物件是否為舊的還是新創建出來的因此透過
於建構子設定唯一的Guid來識別。

在ProductService中調整action method跟相應建構子傳入部分

using ContainerServiceMethods.Database;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace ContainerServiceMethods.Controllers
{
    public class ProductController : Controller
    {
        IProductService _p1;
        IProductService _p2;

        public ProductController(IProductService p1, IProductService p2)
        {
            _p1 = p1;
            _p2 = p2;
        }

        public string[] GetInstances()
        {
            string[] data = new string[2];
            data[0] = _p1.getInstanceId();
            data[1] = _p2.getInstanceId();
            return data;
        }
    }
}

於Startup.cs
public void ConfigureServices(IServiceCollection services)方法

我們去注入剛創建好的自訂的服務
使用services.AddSingleton<IProductService, ProductService>();
第一個參數傳入interface第二個則是實作該interface的class
https://ithelp.ithome.com.tw/upload/images/20210914/20107452dOElRewwWV.png

這裡可以看到使用Singleton效果物件ID都一樣
5071849d-8884-4ffb-94af-fd095a93985c

https://ithelp.ithome.com.tw/upload/images/20210914/20107452nKH3SZlly3.png

而且不管在重整呼叫同一個action method路由,物件id都不會變。

回到Startup.cs修改成
使用services.AddScoped<IProductService, ProductService>();
Scoped是每次Web請求會創建一個新實體,直到web請求結束就銷毀。

所以我們要模擬再次跳轉到這一個網址路由
我們可以到Views/Shared/_Layout.cshtml中調整多擴充一個訪問按鈕
來方便我們直接訪問就不用透過輸入網址方式

https://ithelp.ithome.com.tw/upload/images/20210914/20107452P0KwdPiAcO.png

那就能發現當重整或是重呼叫一次同樣的url時候會有不同的object id

https://ithelp.ithome.com.tw/upload/images/20210914/20107452EcFjf6SVtK.png

回到Startup.cs修改成
改使用 services.AddTransient<IProductService, ProductService>();

可以從第一次呼叫就發現回傳回來的兩個object id都不同
第二次也都是跟第一次完全不同的id
https://ithelp.ithome.com.tw/upload/images/20210914/20107452Jhx3L1EFol.png

原因在於Transient
每次要求元件時就建立一個新的,永不共用。

本篇同步發表至個人部落格
https://coolmandiary.blogspot.com/2021/07/net-core12iocconfigureservices.html

Ref:
What is the AddSingleton vs AddScoped vs Add Transient C# Asp.net Core?
https://www.tutorialspoint.com/what-is-the-addsingleton-vs-addscoped-vs-add-transient-chash-asp-net-core

Understanding AddTransient Vs AddScoped Vs AddSingleton In ASP.NET Core
https://www.c-sharpcorner.com/article/understanding-addtransient-vs-addscoped-vs-addsingleton-in-asp-net-core/

AddTransient, AddScoped and AddSingleton Services Differences
https://stackoverflow.com/questions/38138100/addtransient-addscoped-and-addsingleton-services-differences

IOC(控制反轉) , DI(依賴注入) 深入淺出~~
https://dotblogs.com.tw/daniel/2018/01/17/140435

筆記 - 不可不知的 ASP.NET Core 依賴注入
https://blog.darkthread.net/blog/aspnet-core-di-notes/


上一篇
.NET Core第11天_Controller定義_附加屬性_資料接收方式_返回View方式
下一篇
.NET Core第13天_View常見操作_Layout佈局頁_PartialView部分檢視_強類型視圖(大量資料或物件的傳遞)
系列文
.NET Core MVC網頁應用開發30

尚未有邦友留言

立即登入留言