[PT-BR] Detectando se a aplicação está rodando para criar migrations
Desafios com Dependências "Scoped" no DbContext
No Entity Framework Core, o DbContext
é frequentemente usado para interagir com o banco de dados. No entanto, em cenários complexos como aplicações multi-tenant, você pode precisar injetar serviços "scoped", algo como um TenantProvider
, no seu DbContext
. Isso pode criar desafios ao gerar migrações, pois a aplicação pode não conseguir resolver essas dependências durante o processo de migração. No entanto, existe uma solução para esse problema
Veja a seguinte classe como exemplo:
public class TenantProvider : ITenantProvider {
public TenantProvider(IHttpContextAccessor httpContextAccessor) {...}
}
...
public class ApplicationDbContext : DbContext
{
private readonly ITenantProvider _tenantProvider;
// Constructor for runtime
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options, ITenantProvider tenantProvider)
: base(options)
{
_tenantProvider = tenantProvider;
}
}
Solução
Uma coisa que você pode fazer é adicionar mais um construtor, onde você adiciona manualmente as dependências, assim:
public TenantProvider(Tenant tenant)
{
Tenant = tenant;
}
Depois, use o seguinte código para detectar se está sendo executado através do EF, ou seja, não haverá solicitação para capturar dados no HttpContext.
var isMigration = Assembly.GetEntryAssembly()?.FullName?.StartsWith("ef") ?? false;
Concluindo, lidar com dependências "scoped" no seu DbContext, especialmente em cenários complexos como aplicações multi-tenant, pode ser desafiador ao criar migrações. Adicionando um construtor adicional para injetar manualmente as dependências e detectando se a aplicação está sendo executada através do EF Core, você pode gerenciar essas dependências de forma eficaz. Essa abordagem permite que você alterne de dependências "scoped" para singletons conforme necessário, garantindo a criação suave de migrações. Alternativamente, usar o DesignTimeDbContextFactory é outra solução viável, embora mais complexa.
Exemplo completo de código
Aqui está o exemplo completo de código:
var isMigration = Assembly.GetEntryAssembly()?.FullName?.StartsWith("ef") ?? false;
if (isMigration)
{
services.AddSingleton<ITenantProvider>(_ => new TenantProvider(tenantLocal));
}
else
{
services.AddScoped<ITenantProvider, TenantProvider>();
}