ASP.NET Core 3 系列 - 注入多個相同的介面 (Interface)

-- Pageviews

通常在使用 ASP.NET Core 依賴注入 (Dependency Injection, DI) 都是一個介面對應一個實作類別。
若有多個類別時做相同的介面時,注入的方式就會有點變化。
本篇將介紹 ASP.NET Core 依賴注入多個相同的介面 (Interface)

前置準備

以下介面作為範例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public enum WalletType
{
Alipay,
CreditCard,
LinePay
}

public interface IWalletService
{
WalletType WalletType { get; }
void Debit(decimal amount);
}

public class AlipayService : IWalletService
{
public WalletType WalletType { get; } = WalletType.Alipay;
public void Debit(decimal amount)
{
// 從支付寶扣錢
}
}

public class CreditCardService : IWalletService
{
public WalletType WalletType { get; } = WalletType.CreditCard;
public void Debit(decimal amount)
{
// 從信用卡扣錢
}
}

public class LinePayService : IWalletService
{
public WalletType WalletType { get; } = WalletType.LinePay;
public void Debit(decimal amount)
{
// 從 Line Pay 扣錢
}
}

服務註冊

用相同的介面,註冊不同的實作類別:

1
2
3
4
5
6
7
8
9
10
11
12
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();

// 註冊 Services
services.AddSingleton<IWalletService, AlipayService>();
services.AddSingleton<IWalletService, CreditCardService>();
services.AddSingleton<IWalletService, LinePayService>();
}
}

Service Injection

在 Constructor Injection 時用 IEnumerable<T> 注入,便可取得相同介面的全部實例,再依照使用情境選擇要用的實例。範例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Mvc;

namespace MyWebsite.Controllers
{
public class ShoppingCartController : Controller
{
private readonly IEnumerable<IWalletService> _walletServices;

public ShoppingCartController(IEnumerable<IWalletService> walletServices)
{
_walletServices = walletServices;
}

public IActionResult Checkout(WalletType walletType, decimal amount)
{
var walletService = _walletServices.Single(x => x.WalletType == walletType);
walletService.Debit(amount);
return Ok();
}
}
}

示意圖如下:

ASP.NET Core 3 系列 - 注入多個相同的介面 (Interface) - 多介面注入

注意!
通常只建議 Singleton 類型的服務這樣使用,因為使用 TransientScoped 類型的服務,注入時會 new 新的實例,若沒用到的話,就變成不必要的效能耗損。

如果服務註冊用相同的介面,註冊不同的實作類別,Constructor Injection 時不是用 IEnumerable<T> 注入,就只會得到最後一個註冊的類別,如上例會得到 LinePayService 的實例。

示意圖如下:

ASP.NET Core 3 系列 - 注入多個相同的介面 (Interface) - 單一介面注入