Mar*_*tin 3 asp.net-mvc dependency-injection entity-framework-core asp.net-core-mvc asp.net-core
我正在使用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>();
}
}
Run Code Online (Sandbox Code Playgroud)
在用户通过身份验证后,是否可以初始化我的存储库一次?我如何通过构造函数传递TenantId?
Ste*_*ven 10
您的租户和用户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();
}
Run Code Online (Sandbox Code Playgroud)
这样可以优雅地解决问题,因为现在您可以定义一个ITenantContext知道如何为当前请求检索正确的租户ID的实现.例如:
public sealed class AspNetSessionTenantContext : ITenantContext {
public int CurrentTenantId {
get { return (int)HttpContext.Current.Session["tenantId"]; }
}
}
Run Code Online (Sandbox Code Playgroud)
这甚至允许您将所有组件注册为单例,这可以提高性能,并减少常见DI陷阱的更改,例如强制依赖性.
| 归档时间: |
|
| 查看次数: |
1435 次 |
| 最近记录: |