System.AggregateException:扩展我自己的 EF Core DbContext 类时"Some services are not able to be constructed"



我有一个解决方案,它包含(除其他外)一个Blazor服务器端项目、三个最小的API项目、一个MAUI项目(使用最小的API)、一个Models项目(包含解决方案的模型)和一个数据访问项目。最后一个项目包含我的AppDbContext类…

public class AppDbContext : IdentityDbContext<User> {
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) {}
// DbSets go here...
}

在Blazor和minimal API项目中作为服务注册。例如,在Blazor项目中,Program.cs包含以下内容…

builder.Services.AddDbContext<AppDbContext>(options => {
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection"));
options.EnableSensitiveDataLogging();
options.EnableDetailedErrors();
}, ServiceLifetime.Transient);
builder.Services.AddDbContextFactory<AppDbContext>(lifetime: ServiceLifetime.Scoped);

请注意,我正在从普通注入(使用具有[Inject]属性的属性)切换到使用工厂注入的过程中,这就是为什么我有上面的最后一行。这样我就可以把我的代码转换成位,而它仍然可以工作。

一切正常

我现在需要在每次数据库更新时做一些额外的日志记录。我在AppDbContext中添加了以下内容…

public new Task<int> SaveChangesAsync(string userId = "", CancellationToken cancellationToken = default) {
// Do logging with userId
return await base.SaveChangesAsync(cancellationToken);
}

在三个最小的API项目中传递用户ID不是问题,因为我使用JWT,并且可以轻松地从令牌获取ID,并将其传递给SaveChangesAsync(或匿名API端点的"")。

然而,要在Blazor项目中获得登录用户的Id,我似乎需要使用AuthenticationStateProvider。我认为将以下类添加到Blazor项目中会起作用…

public class BlazorAppDbContext : AppDbContext {
private readonly AuthenticationStateProvider? _authenticationStateProvider;
public BlazorAppDbContext(DbContextOptions<AppDbContext> options, AuthenticationStateProvider? authenticationStateProvider) : base(options) =>
_authenticationStateProvider = authenticationStateProvider;
public new Task<int> SaveChangesAsync(CancellationToken cancellationToken = default) {
// Use the AuthenticationStateProvider to get the user Id and log as before
return await base.SaveChangesAsync(cancellationToken);
}
}

我修改了Program.cs中的代码,使用BlazorAppDbContext而不是AppDbContext,并试图运行,但当它击中WebApplication app = builder.Build();时得到以下异常…

系统。AggregateException: '一些服务不能被构造

(验证服务描述符时出错)ServiceType: MyProject.Admin.Helpers. blazorappdbcontext Lifetime: Transient ImplementationType: MyProject.Admin.Helpers。无法解析类型'Microsoft.EntityFrameworkCore.DbContextOptions ' 1的服务。

(在验证服务描述符时出错)服务类型:Microsoft.AspNetCore.Identity.ISecurityStampValidator生存期:Scoped实现类型:Microsoft.AspNetCore.Identity.SecurityStampValidator1[MyProject.Models.User]': Unable to resolve service for type 'Microsoft.EntityFrameworkCore.DbContextOptions1[myproject . dataccess . dataccess . net]。

验证服务描述符时出错服务类型:Microsoft.AspNetCore.Identity.ITwoFactorSecurityStampValidator生存期:Scoped实现类型:Microsoft.AspNetCore.Identity.TwoFactorSecurityStampValidator1[MyProject.Models.User]': Unable to resolve service for type 'Microsoft.EntityFrameworkCore.DbContextOptions1

之后是一大堆几乎相同的异常,但针对解决方案中的其他类型。

我做了很多搜索,但所有的这种例外的答案似乎是基于人们没有正确注册服务。考虑到这与AppDbContext工作得很好,我用BlazorAppDbContext(扩展AppDbContext)替换了Program.cs中的所有实例,我真的不确定我做错了什么。

在这个答案之后,我尝试添加以下行…

builder.Services.AddHttpContextAccessor();

…但这无济于事。我并不感到惊讶,因为我已经在项目中的几个地方使用了IHttpContextAccessor,所以如果DI容器无法解决这个问题,我早就发现了。

我试着改变构造函数如下…

public BlazorAppDbContext(DbContextOptions<BlazorAppDbContext> options, AuthenticationStateProvider? authenticationStateProvider) : base(options) =>
_authenticationStateProvider = authenticationStateProvider;

…但这会导致编译错误,因为baseDbContextOptions<AppDbContext>,而不是DbContextOptions<BlazorAppDbContext>

有人能帮忙吗?

您可以在注册BlazorAppDbContext时使用工厂方法手动构建这些选项:

builder.Services.AddTransient<BlazorAppDbContext>(sp =>
{
DbContextOptionsBuilder<AppDbContext> optionsBuilder = new();
optionsBuilder.UseSqlServer(
builder.Configuration.GetConnectionString("DefaultConnection"));
optionsBuilder.EnableSensitiveDataLogging();
optionsBuilder.EnableDetailedErrors();
return new BlazorAppDbContext(
optionsBuilder.Options,
sp.GetService<AuthenticationStateProvider>());
});

在使用:

builder.Services.AddDbContext<MyContextType>(options => ...);

则得到的DbContextOptions将是:

DbContextOptions<MyContextType>

换句话说,您不能使用AddDbContext来提供带有类型参数的DbContextOptions,而不是用于AddDbContext方法的类型参数。

这就是为什么你要用AddTransient和工厂方法代替AddDbContext,如果你想满足构造函数:

public BlazorAppDbContext(DbContextOptions<AppDbContext> options);

相关内容

  • 没有找到相关文章

最新更新