同一個介面多個實作的註冊

Register Multiple Implementations Of The Same Interface

今天的重點是在於當我使用了同一個 Interface 的時候,要如何註冊並且分別取得多種實作的部分,因此不會著墨在 Interface 的原理和 DI 的介紹。

.NET 和 Web API

假設今天有兩種傳送訊息的方式,一種是透過 slack,一種是透過 gmail,在同一個想要同時使用兩種發送方式的話,就會需要使用到 同一個介面註冊多個實作 的方法。

首先建立兩個 Service,一個是 slack 一個是 gmail,並抽出 interface:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
public interface IMessageService
{
    void Send();
}

public class SlackService : IMessageService
{
    public void Send()
    {
        Console.WriteLine("Send By Slack");
    }
}

public class GmailService : IMessageService
{
    public void Send()
    {
        Console.WriteLine("Send By Gmail");
    }
}

接著我們在 Program.cs 使用 delegate 註冊 Interface,並且告知對應的 key 輸入的時候要回傳哪一個 Service:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();
builder.Services.AddSingleton<GmailService>();
builder.Services.AddSingleton<SlackService>();
builder.Services.AddSingleton<MessageServiceResolver>(serviceProvider => key =>
{
    return key switch
    {
        "gmail" => serviceProvider.GetService<GmailService>(),
        "slack" => serviceProvider.GetService<SlackService>(),
    };
});

var app = builder.Build();
app.MapControllers();
app.Run();

public delegate IMessageService MessageServiceResolver(string key);

最後,我們建立一個 Controller,在 Controller 裡使用的時候分辨註冊 Interface,並調用 MessageServiceResolver 來分別取得實作:

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

namespace WebApplication1.Controllers;

[ApiController, Route("api/[controller]")]
public class TestController : ControllerBase
{
    private readonly IMessageService _gmail;
    private readonly IMessageService _slack;

    public TestController(MessageServiceResolver _service)
    {
        _slack = _service("slack");
        _gmail = _service("gmail");
    }
    
    public void Test()
    {
        _slack.Send();
        _gmail.Send();
    }
}

參考資料

Built with Hugo
Theme Stack designed by Jimmy