如何在 OnModelCreating() 中使用 Scoped Service 在每次 HTTP 请求后 Dispose()?
How to Dispose() after every HTTP request using Scoped Service in OnModelCreating()?
我有一个多租户应用程序,对于每个 HTTP Request
,它应该为 属性 AccountId
.
验证 Headers
全局查询过滤器是隔离.NET Core Docs中提到的租户的好方法,但它没有列出在每次请求后如何处理状态。
这是一个例子:
ApplicationDbContext.cs
使用由 FooHeaderService
注入的 AccountId
对 Account
实体有一个全局查询过滤器
private readonly IFooHeader _fooHeaders;
public ApplicationDbContext(IFooHeader fooHeaders) : base(options)
{
this._fooHeaders = fooHeaders;
}
protected override void OnModelCreating() {
FooHeaders foo = this._fooHeaders.GetFooHeaders().AccountId;
// or using Microsoft.EntityFrameworkCore.Infrastructure
FooHeaders foo = this.Database.GetService<IFooHeaders>();
Guid fooId = foo.AccountId; // MUST DISPOSE BETWEEN REQUESTS!
// Global Query Filter
modelBuilder.Entity<Account>()
.HasQueryFilter(filter => filter.AccountId = fooId)
}
FooHeaderService
为 AccountId
获取 Headers
public class FooHeaderService : IFooHeaders
{
private readonly FooHeaders _headers;
public FooHeaderService(IHttpContextAccessor contextAccessor)
{
_headers.AccountId = contextAccessor.HttpContext?.Request
.Headers["accountId"].ToString();
}
public FooHeaders GetFooHeaders() => _headers;
}
Startup.cs
将 FooHeaderService
注册为 ScopedService
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddScoped<IFooHeader, FooHeaderService>();
services.AddDbContext<ApplicationDbContext>();
}
问题
如果没有妥善处理,OnModelCreating()
中的变量 fooId = AccountId
会在 HTTP Requests
之间持续存在(非常危险的东西!)。
如何将 FooHeaderService
依赖注入 OnModelCreating()
并为每个 HTTP Request
周期处理状态?
您可以使用HttpResponse.RegisterForDisposal方法:
HttpContext.Response.RegisterForDisposal(fooId);
OnModelCreating 只运行一次,因此您不能在那里解析特定的 AccountId。而是将服务传递到允许您访问 AccountId 的 DbContext 构造函数。您实际上已经这样做了,只是没有在 OnModelCreating 中使用它。
所以这应该是
public ApplicationDbContext(IFooHeader fooHeaders) : base(options)
{
this._fooHeaders = fooHeaders;
}
protected override void OnModelCreating() {
// Global Query Filter
modelBuilder.Entity<Account>()
.HasQueryFilter(filter => filter.AccountId = this._fooHeaders.AccountId)
}
这样每个请求都会得到一个新的 DbContext(因为它是有范围的),并且每个 DbContext 都有不同的 IFooHeaders 以插入全局查询过滤器。
我有一个多租户应用程序,对于每个 HTTP Request
,它应该为 属性 AccountId
.
Headers
全局查询过滤器是隔离.NET Core Docs中提到的租户的好方法,但它没有列出在每次请求后如何处理状态。
这是一个例子:
ApplicationDbContext.cs
使用由 FooHeaderService
AccountId
对 Account
实体有一个全局查询过滤器
private readonly IFooHeader _fooHeaders;
public ApplicationDbContext(IFooHeader fooHeaders) : base(options)
{
this._fooHeaders = fooHeaders;
}
protected override void OnModelCreating() {
FooHeaders foo = this._fooHeaders.GetFooHeaders().AccountId;
// or using Microsoft.EntityFrameworkCore.Infrastructure
FooHeaders foo = this.Database.GetService<IFooHeaders>();
Guid fooId = foo.AccountId; // MUST DISPOSE BETWEEN REQUESTS!
// Global Query Filter
modelBuilder.Entity<Account>()
.HasQueryFilter(filter => filter.AccountId = fooId)
}
FooHeaderService
为 AccountId
Headers
public class FooHeaderService : IFooHeaders
{
private readonly FooHeaders _headers;
public FooHeaderService(IHttpContextAccessor contextAccessor)
{
_headers.AccountId = contextAccessor.HttpContext?.Request
.Headers["accountId"].ToString();
}
public FooHeaders GetFooHeaders() => _headers;
}
Startup.cs
将 FooHeaderService
注册为 ScopedService
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddScoped<IFooHeader, FooHeaderService>();
services.AddDbContext<ApplicationDbContext>();
}
问题
如果没有妥善处理,OnModelCreating()
中的变量 fooId = AccountId
会在 HTTP Requests
之间持续存在(非常危险的东西!)。
如何将 FooHeaderService
依赖注入 OnModelCreating()
并为每个 HTTP Request
周期处理状态?
您可以使用HttpResponse.RegisterForDisposal方法:
HttpContext.Response.RegisterForDisposal(fooId);
OnModelCreating 只运行一次,因此您不能在那里解析特定的 AccountId。而是将服务传递到允许您访问 AccountId 的 DbContext 构造函数。您实际上已经这样做了,只是没有在 OnModelCreating 中使用它。
所以这应该是
public ApplicationDbContext(IFooHeader fooHeaders) : base(options)
{
this._fooHeaders = fooHeaders;
}
protected override void OnModelCreating() {
// Global Query Filter
modelBuilder.Entity<Account>()
.HasQueryFilter(filter => filter.AccountId = this._fooHeaders.AccountId)
}
这样每个请求都会得到一个新的 DbContext(因为它是有范围的),并且每个 DbContext 都有不同的 IFooHeaders 以插入全局查询过滤器。