无法从单例中使用作用域服务 applicationdbcontext。

huangapple go评论77阅读模式
英文:

Cannot consume scoped service applicationdbcontext from singleton

问题

我正在构建一个ASP.NET Core 6.0 Web应用程序,我创建了一个使用Microsoft Identity的站点,它创建了ApplicationDbContext.cs文件:

public class ApplicationDbContext : IdentityDbContext
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
        : base(options)
    {
    }

    public DbSet<Settingw> Settings { get; set; }
}

接下来,我创建了一个Settings仓储和仓储接口。运行了一切,测试了一切,一切都正常工作。

现在我正在尝试从该仓储内部调用dbcontext,但是我遇到了一个错误:

无法从单例中使用作用域服务applicationdbcontext

我被卡住了,不确定我做错了什么。

这是我的program.cs

var builder = WebApplication.CreateBuilder(args);

// 将服务添加到容器中。
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();

builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
    .AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddRazorPages();

builder.Services.AddSingleton<ISettingsRepository, SettingsRepository>(); // 这里出错了

var app = builder.Build();

SettingsRepository.cs

public class SettingsRepository : ISettingsRepository
{
    private readonly ApplicationDbContext _dbContext;

    public SettingsRepository(ApplicationDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    public Settings Settings()
    {
        return _dbContext.Settings.AsNoTracking().First();
    }
}
英文:

I am building an ASP.NET Core 6.0 web app, I created a site that uses Microsoft Identity which created the ApplicationDbContext.cs file:

public class ApplicationDbContext : IdentityDbContext
{
    public ApplicationDbContext(DbContextOptions&lt;ApplicationDbContext&gt; options)
        : base(options)
    {
    }

    public DbSet&lt;Settingw&gt; Settings { get; set; }
}

Next I created a Settings repository and repository interface. Ran everything, tested and everything is working fine.

Now I'm trying to call the dbcontext from inside that repository and I'm getting an error

> Cannot consume scoped service applicationdbcontext from singleton

I'm stuck, not sure what I am doing wrong.

Here's my program.cs:

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
var connectionString = builder.Configuration.GetConnectionString(&quot;DefaultConnection&quot;);
builder.Services.AddDbContext&lt;ApplicationDbContext&gt;(options =&gt;
    options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();

builder.Services.AddDefaultIdentity&lt;IdentityUser&gt;(options =&gt; options.SignIn.RequireConfirmedAccount = true)
    .AddEntityFrameworkStores&lt;ApplicationDbContext&gt;();
builder.Services.AddRazorPages();

builder.Services.AddSingleton&lt;ISettingsRepository, SettingsRepository&gt;(); //errors here

var app = builder.Build();

SettingsRepository.cs:

public class SettingsRepository : ISettingsRepository
{
    private readonly ApplicationDbContext _dbContext;

    public SettingsRepository(ApplicationDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    public Settings Settings()
    {
        return _dbContext.Settings.AsNoTracking().First();
    }
}

答案1

得分: 2

如Steve Py在评论中提到的那样,你需要像这样更改设置存储库服务的生命周期:

builder.Services.AddScoped<ISettingsRepository, SettingsRepository>();

EF上下文默认为Scoped生命周期。

  • Singleton:服务只创建一次,并且相同的实例也会在下一次请求中返回
  • Scoped:每个“作用域”创建一次,由于ASP.NET Core为每个请求创建一个作用域,这基本上意味着在典型情况下,服务每个请求只创建一次
  • Transient:每次需要服务时都会创建

你不应该依赖于生命周期较短的服务。
在这种情况下,你的存储库(Singleton)依赖于上下文(Scoped)。
问题在于你的存储库只会创建一次,但它所依赖的上下文是一个每个作用域的服务,并且在请求完成时会被销毁。
在这种情况下,降低存储库的生命周期是正确的选择。

英文:

Like Steve Py mentioned in the comment, you need to change the lifetime of your settings repository service like this:

builder.Services.AddScoped&lt;ISettingsRepository, SettingsRepository&gt;();

EF contexts are Scoped lifetime by default.

  • Singleton: service is created once and the same instance is returned for the next requests as well
  • Scoped: created once per "scope", and since ASP.NET Core creates a scope for a request, this essentially means the service is created once per request in typical scenarios
  • Transient: created every time the service is needed

You should not depend on services with a smaller lifetime.
In this case your repository (Singleton) is depending on the context (Scoped).
The issue would be that your repository is only created once but the context it depends on is a per-scope service and would be disposed when the request is done.
In this case lowering the lifetime of the repository is the correct choice.

huangapple
  • 本文由 发表于 2023年8月9日 06:06:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/76863469.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定