如何使用依賴注入將UserId / TenantId傳遞給存儲庫構造函數?


我正在使用ASP.NET 5和EF7編寫多租戶Web服務。存儲庫數據特定於租戶/用戶。因為我將在所有調用中使用TenantId,所以我想用當前的TenantId初始化Repository。

public class MyRepository {
    private int tenantId;
    public MyRepository(MyDbContext context, int tenantId) { 
        this.tenantId = tenantId;
        // ...
    }

    public Task<List<Data>> GetAllAsync() {
        return this.context.Data.Where(d => d.TenantId == this.tenantId).ToListAsync();
    }
}

public class Startup {
    public void ConfigureServices(IServiceCollection services) {
        // How do I pass the TenantId to the constructor?
        services.AddScoped<MyRepository>();
    }
}

在用戶通過身份驗證後,是否可以初始化我的存儲庫一次?我如何通過構造函數傳遞TenantId?

熱門答案

您的租戶和用戶ID值都是運行時數據,您不應該將運行時數據注入系統的組件 (在這種情況下是您的存儲庫),因為這極大地使您的組合根複雜化(正如您已經體驗過的那樣)並使其幾乎不可能驗證您的對像圖。運行時數據應該流經已構建的對像圖。實現這一點基本上有兩種方法。您可以通過組件的公共API的方法調用來傳遞數據,也可以注入一個負責在請求時檢索運行時值的組件。

在您的情況下,後一種選擇是最好的。因此,我的建議是注入一個允許檢索此上下文信息的組件:

public interface ITenantContext
{
    int CurrentTenantId { get; }
}

public interface IUserContext
{
    int CurrentUserId { get; }
}

public class MyRepository {
    private readonly Func<MyDbContext> contextProvider;
    private readonly ITenantContext tentantContext;

    public MyRepository(Func<MyDbContext> contextProvider, ITenantContext tentantContext){ 
        this.contextProvider = contextProvider;
        this.tentantContex = tentantContex;
    }

    public Task<List<Data>> GetAllAsync() {
        return this.contextProvider().Data
            .Where(d => d.TenantId == this.tenantContext.CurrentTenantId)
            .ToListAsync();
}

這樣可以優雅地解決問題,因為現在您可以定義ITenantContext實現,該實現知道如何為當前請求檢索正確的租戶ID。例如:

public interface ITenantContext
{
    int CurrentTenantId { get; }
}

public interface IUserContext
{
    int CurrentUserId { get; }
}

public class MyRepository {
    private readonly Func<MyDbContext> contextProvider;
    private readonly ITenantContext tentantContext;

    public MyRepository(Func<MyDbContext> contextProvider, ITenantContext tentantContext){ 
        this.contextProvider = contextProvider;
        this.tentantContex = tentantContex;
    }

    public Task<List<Data>> GetAllAsync() {
        return this.contextProvider().Data
            .Where(d => d.TenantId == this.tenantContext.CurrentTenantId)
            .ToListAsync();
}

這甚至允許您將所有組件註冊為單例,這可以提高性能,並減少常見DI陷阱的更改,例如強制依賴性





許可下: CC-BY-SA
不隸屬於 Stack Overflow
這個KB合法嗎? 是的,了解原因