ASP.NET Core Dependency Injection With Factory Pattern


  1. 說明

筆記如何結合 Factory Pattern 搭配 Dependency Injection,讓服務的注入使用更富有選擇彈性。

logo

說明

ASP.NET Core 原生的 DI Container 使用一段時間後逐漸習慣註冊服務,接著再到實際頁面注入使用的開發方式。

但一個困惑也隨之而起,例如 HttpClient 在註冊的時候加入 Base Uri Address,但實際再注入的時候如果要動態的選擇 Base Uri Address 該如何進行?

一的處理方式是透過 HttpRequestMessage,但後續的嘗試發現透過 Factory Pattern 可以有更好的使用方式。

IPersistence.cs

public interface IPersistence
{
    void Save(object data);
    object Load();
}

DatabaseStorage.cs

public class DatabaseStorage : IPersistence
{
    public void Save(object data)
    {
        // Implement detailed
    }

    public object Load()
    {
        return new object();
    }
}

public class FileStorage : IPersistence
{
    // ...
}

public class CloudStorage : IPersistence
{
    // ...
}

PersistenceFactory.cs

public class PersistenceFactory
{
    public IPersistence CreatePersistence(string type)
    {
        switch (type.ToLower())
        {
            case "database":
                return new DatabaseStorage();
            case "file":
                return new FileStorage();
            case "cloud":
                return new CloudStorage();
            default:
                throw new ArgumentException("Unsupported persistence type");
        }
    }
}

DataService.cs

public class DataService
{
    private IPersistence _persistence;

    public DataService(PersistenceFactory factory, string type)
    {
        _persistence = factory.CreatePersistence(type);
    }

    public void SaveData(object data)
    {
        _persistence.Save(data);
    }

    public object LoadData()
    {
        return _persistence.Load();
    }
}

Program.cs

var builder = WebApplication.CreateBuilder(args);

// 註冊 Persistence Factory 為單例
builder.Services.AddSingleton<PersistenceFactory>();

// 註冊 DataService,並使用 Factory
builder.Services.AddScoped<DataService>(serviceProvider =>
{
    var factory = serviceProvider.GetRequiredService<PersistenceFactory>();
    string persistenceType = builder.Configuration.GetValue<string>("PersistenceType") ?? "file";
    return new DataService(factory, persistenceType);
});

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

可以透過在 appsettings.json 設定 PersistenceType 決定預設使用的注入類型。

{
    "PersistenceType": "cloud"
}

Controller.cs

public class MyController : Controller
{
    private readonly DataService _dataService;

    public MyController(DataService dataService)
    {
        _dataService = dataService;
    }

    public IActionResult SaveData(object data)
    {
        _dataService.SaveData(data);
        return Ok("Data saved successfully.");
    }

    public IActionResult LoadData()
    {
        var data = _dataService.LoadData();
        return Ok(data);
    }
}