I have a base library which includes some basic entities (logs, settings, ...) in a DbContext class. In my specific project I am inheriting the Context from this class and do the project specific stuff.
Base Context
public class BaseContext : DbContext {
public BaseContext(DbContextOptions<BaseContext> options)
: base(options)
{
}
}
Project Specific Context
public class ProjectContext: BaseContext {
public ProjectContext(DbContextOptions<BaseContext> options)
: base(options)
{
}
public ProjectContext(DbContextOptions options)
: base(options)
{
}
}
Context will be added in Startup:
services.AddDbContext<Context>(options =>
{
if (Helpers.IsDevelopment())
{
options.EnableSensitiveDataLogging();
options.EnableDetailedErrors();
}
options.UseNpgsql(Configuration.GetConnectionString("Context"), b =>
{
b.MigrationsAssembly("App.Project.Specific");
b.UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery);
b.EnableRetryOnFailure(5);
});
}
);
So some services and controlers implemented in the base library work with BaseContext, which is a child of Context.
public AssetsService(BaseContext db,...
So this results in the following error message:
Unable to resolve service for type 'App.Shared.DataModel.BaseContext' while attempting to activate 'App.Shared.Services.AssetsService
So how to inject the contexts correctly to get access from both ways?
CodePudding user response:
A DbContext is a multi-entity Repository and Unit-of-Work. It makes little sense to have a "base" repository and no sense to register the base instead of concrete repositories.
Furthermore, the DI container can't guess by itself which concrete service to create when only a base class is registered. .NET can't guess which specific Repository classes like AssetsService
or CustomersService
want. If both SalesContext
and MarketingContext
inherit from some base Context
class, why not send MarketingContext
to CustomersService
and SalesContext
to WarehouseService
?
DI registration
For starters, all the DbContext types that are going to be used need to be registered. If a service expects a BaseContext, then BaseContext should be registered. Same with ProjectContext
, TimeSheetContext
, CustomerContext
etc. Registering a base class doesn't register its derived classes.
Common registration and configuration
It seems that the real question is how to register multiple DbContexts using the same code. This can be done with an extension method that accepts a DbContext
type parameter and calls AddDbContext
:
public static IServiceCollection AddMyContext<T>(
this IServiceCollection services,
IConfiguration configuration) where T:DbContext
{
services.AddDbContext<T>(options =>
{
if (Helpers.IsDevelopment())
{
options.EnableSensitiveDataLogging();
options.EnableDetailedErrors();
}
options.UseNpgsql(configuration.GetConnectionString("Context"), b =>
{
b.MigrationsAssembly("App.Project.Specific");
b.UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery);
b.EnableRetryOnFailure(5);
});
}
);
return services;
}
In the application's startup, call AddMyContext
instead of AddDbContext
.