三種服務的生命週期:Singleton、Scoped 和 Transient
Singleton
- Singleton(單例):這種服務只會被建立一次,並且在整個應用程式中重複使用。
- 這意味著所有使用這種服務的類都會得到同一個服務例項。這種服務適合用於建立成本高昂或需要全域性共享的服務,
- 例如資料庫連線或配置資訊。您可以使用 AddSingleton 方法註冊 Singleton 服務,例如:
services.AddSingleton<IProductService, ProductService>();
這行程式碼告訴容器,當有類需要 IProductService 時,就提供一個 ProductService 的例項,並且只建立一次,一直保持在記憶體中。¹
Scoped
- Scoped(範圍內):這種服務每次請求(Request)都會被建立一次,並且在同一個請求中重複使用。這意味著在處理一個請求時,所有使用這種服務的類都會得到同一個服務例項,
- 但是不同的請求會得到不同的服務例項。這種服務適合用於建立和請求相關的服務,
- 例如 Entity Framework 的上下文(Context),它可以跟蹤和儲存請求的資料變化。您可以使用 AddScoped 方法註冊 Scoped 服務,例如:
services.AddScoped<IProductService, ProductService>();
這行程式碼告訴容器,當有類需要 IProductService 時,就提供一個 ProductService 的例項,並且每個請求都建立一個新的例項,請求結束後銷燬。¹
Transient
- Transient(臨時):這種服務每次請求(Request)都會被建立,但是不會在請求中重複使用。
- 這意味著每次使用這種服務的類都會得到一個新的服務例項,即使是在同一個請求中。
- 這種服務適合用於建立輕量級、無狀態的服務,例如日誌記錄或驗證的服務。
您可以使用 AddTransient 方法註冊 Transient 服務,例如:
services.AddTransient<IProductService, ProductService>();
這行程式碼告訴容器,當有類需要 IProductService 時,就提供一個 ProductService 的例項,並且每次都建立一個新的例項,使用完後銷燬。¹
比喻
為了幫助您更好地理解這三種服務的生命週期,我可以用一個比喻來說明。假設您去一家餐廳吃飯,餐廳的服務就相當於 ASP.NET Core 的服務,而您的訂單就相當於一個請求。那麼:
-
Singleton 服務就像是餐廳的老闆,他只有一個,而且在餐廳開業期間一直在場。無論您點什麼菜,他都會親自為您服務,並且記住您的喜好。他對所有的客人都是如此,所以他很忙,也很累,但是他很有經驗,也很負責。
-
Scoped 服務就像是餐廳的服務員,他們每個人都負責一桌客人。當您進入餐廳時,會有一個服務員為您服務,他會為您點菜、上菜、結賬,直到您離開餐廳。如果您再次來到餐廳,可能會遇到同一個服務員,也可能會遇到不同的服務員,但是他們都會為您提供專業的服務。他們對每桌客人都是如此,所以他們也很忙,但是他們很專注,也很友好。
-
Transient 服務就像是餐廳的廚師,他們每次都會為您做新鮮的菜。當您點了一個菜時,會有一個廚師為您做這個菜,並且只做這個菜,做完後就不再管您了。如果您再次點了同一個菜,可能會有同一個廚師為您做,也可能會有不同的廚師為您做,但是他們都會為您做出美味的菜。他們對每個菜都是如此,所以他們很快,也很靈活,但是他們不太關心您的其他需求。
實際例子
Singleton服務 -- 配置資訊(Configuration)
- Singleton 服務:一個常見的使用 Singleton 服務的場景是配置資訊(Configuration)。配置資訊通常是在應用程式啟動時從檔案或資料庫中讀取的,它們在整個應用程式中是不變的,所以沒有必要每次都重新讀取。您可以使用 AddSingleton 方法將 IConfiguration 介面註冊為 Singleton 服務,然後在任何需要配置資訊的地方注入它,例如:
services.AddSingleton<IConfiguration>(Configuration);
這樣,您就可以在控制器或其他服務中使用 IConfiguration 的例項來訪問配置資訊,例如:
public class HomeController : Controller
{
private readonly IConfiguration _configuration;
public HomeController(IConfiguration configuration)
{
_configuration = configuration;
}
public IActionResult Index()
{
var title = _configuration["AppSettings:Title"];
ViewBag.Title = title;
return View();
}
}
Scoped 服務 -- Entity Framework Core 的上下文(DbContext)
- Scoped 服務:一個常見的使用 Scoped 服務的場景是 Entity Framework Core 的上下文(DbContext)。DbContext 是用於運算元據庫的類,它可以跟蹤和儲存每個請求的資料變化。您可以使用 AddDbContext 方法將 DbContext 註冊為 Scoped 服務,然後在需要運算元據庫的地方注入它,例如:
services.AddDbContext<AppDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
這樣,您就可以在控制器或其他服務中使用 AppDbContext 的例項來運算元據庫,例如:
public class ProductController : Controller
{
private readonly AppDbContext _context;
public ProductController(AppDbContext context)
{
_context = context;
}
public IActionResult Index()
{
var products = _context.Products.ToList();
return View(products);
}
}
- Transient 服務 -- 日誌記錄(Logging)
- Transient 服務:一個常見的使用 Transient 服務的場景是日誌記錄(Logging)。日誌記錄是用於記錄應用程式的執行情況的服務,它通常是輕量級的,不需要保持狀態。您可以使用 AddLogging 方法將 ILoggerFactory 介面註冊為 Transient 服務,然後在需要記錄日誌的地方注入它,例如:
services.AddLogging();
這樣,您就可以在控制器或其他服務中使用 ILoggerFactory 的例項來建立日誌記錄器,例如:
public class HomeController : Controller
{
private readonly ILogger _logger;
public HomeController(ILoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger<HomeController>();
}
public IActionResult Index()
{
_logger.LogInformation("Index action executed");
return View();
}
}