【问题标题】:How to Dispose() after every HTTP request using Scoped Service in OnModelCreating()?如何在 OnModelCreating() 中使用 Scoped Service 在每个 HTTP 请求后进行 Dispose()?
【发布时间】:2021-05-16 20:04:34
【问题描述】:

我有一个多租户应用程序,对于每个 HTTP Request,它应该验证 Headers 的属性 AccountId

全局查询过滤器是隔离.NET Core Docs 中提到的租户的好方法,但它没有列出在每次请求后如何处理状态。

这是一个例子:

ApplicationDbContext.cs 使用FooHeaderService 注入的AccountIdAccount 实体提供全局查询过滤器

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)
}

FooHeaderServiceAccountId 获取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.csFooHeaderService注册为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 循环处理状态?

【问题讨论】:

  • 您将上下文和服务注册为范围,因此您应该为每个请求获取新实例。所以上面的一切都应该正常工作。你确定这就是你的代码的样子吗?此外,如果您需要处置服务类型,请实施 IDisposable 以便在其范围结束后处置实例

标签: c# entity-framework dependency-injection entity-framework-core


【解决方案1】:

在此处查看示例: https://github.com/dotnet/EntityFramework.Docs/blob/master/samples/core/Querying/QueryFilters/BloggingContext.cs

OnModelCreating 只运行一次,因此您无法在那里解析特定的 AccountId。而是将服务传递给您的 DbContext 构造函数,该构造函数允许您访问 AccountId。您实际上已经这样做了,只是没有在 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)
}

这样每个请求都会获得一个新的 DbContexts(因为它是作用域的),并且每个 DbContext 都有不同的 IFooHeaders 以插入到全局查询过滤器中。

【讨论】:

    【解决方案2】:

    你可以使用HttpResponse.RegisterForDisposal方法:

    HttpContext.Response.RegisterForDisposal(fooId);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-06-12
      • 1970-01-01
      • 1970-01-01
      • 2021-06-27
      • 1970-01-01
      • 2016-07-23
      • 1970-01-01
      • 2011-08-30
      相关资源
      最近更新 更多