Implementando uma Solução MultiTenancy com o NHibernate.

MultiTenancy, ou multitenant, é um conceito fundamental em arquiteturas de software modernas, permitindo que uma única instância de software atenda a vários clientes (tenants) de forma personalizada e segura. Implementar uma solução MultiTenancy com NHibernate pode ser desafiador. Já encontrei diversas implementações, incluindo o uso de múltiplas SessionFactories armazenadas em um ConcurrentDictionary. Essa abordagem pode ser particularmente complicada se o uso de memória for uma restrição para o seu projeto. No entanto, com a abordagem correta, é possível desenvolver uma solução robusta e escalável.

Neste artigo detalharemos as etapas e considerações para implementar MultiTenancy usando NHibernate, usando o conceito de “Base de Dados Separada” para maximizar o isolamento e a segurança dos dados.

1. O Que é MultiTenancy?

MultiTenancy refere-se a uma arquitetura de software onde uma única aplicação é utilizada por múltiplos clientes, conhecidos como tenants. Cada tenant pode ter suas próprias configurações, dados e personalizações na aplicação. Existem três principais abordagens de MultiTenancy:

  • Base de Dados Compartilhada, Esquema Compartilhado: Todos os tenants compartilham o mesmo banco de dados e o mesmo esquema, diferenciados apenas por dados de identificação.
  • Base de Dados Compartilhada, Esquema Separado: Todos os tenants compartilham o mesmo banco de dados, mas cada tenant possui seu próprio esquema.
  • Base de Dados Separada: Cada tenant possui seu próprio banco de dados independente.

2. Escolhendo a Abordagem

A escolha da abordagem depende das necessidades específicas da aplicação, como escalabilidade, manutenção, segurança e isolamento de dados. Neste artigo, focaremos na abordagem de “Base de Dados Separada”, que oferece um ótimo isolamento, pois cada tenant possui um banco de dados independente, garantindo a máxima segurança e privacidade dos dados.

3. Configurando o NHibernate para MultiTenancy

NHibernate suporta configuração específica para MultiTenancy. Durante a definição das configurações do DatabaseIntegration, você especifica o tipo de MultiTenancy (Database ou Schema) desejado e o provider que deve ser usado para realizar o MultiTenancy.

Exemplo de Configuração

Para suportar MultiTenancy usando bancos de dados separados, no NHibernate, é necessário informar uma string de conexão válida e acessível, pois o NHibernate precisa acessar o banco de dados para gerar o SessionFactory, além de configurar o Provider para MultiTenancy:

Configuration cfg = new Configuration() .DataBaseIntegration(db => { db.MultiTenancy = MultiTenancyStrategy.Database; db.MultiTenancyConnectionProvider<MultiTenancyConnectionProvider>(); db.Dialect<PostgreSQL83Dialect>(); db.ConnectionString = "User ID=postgres;Password=<password>;Host=localhost;Port=5432;Database=postgres;Pooling=true;"; db.Driver<NpgsqlDriver>(); db.LogSqlInConsole = true; });
Enter fullscreen mode
Exit fullscreen mode

Implementando o MultiTenancyConnectionProvider

O próximo passo é implementar o MultiTenancyConnectionProvider, que permitirá configurar a string de conexão específica para cada tenant.

public class MultiTenancyConnectionProvider : AbstractMultiTenancyConnectionProvider
{ public MultiTenancyConnectionProvider() { } protected override string GetTenantConnectionString(TenantConfiguration tenantConfiguration, ISessionFactoryImplementor sessionFactory) { var tenant = (AppSettingsTenantConfiguration)tenantConfiguration; return tenant.ConnectionString; }
}
Enter fullscreen mode
Exit fullscreen mode

Integração com Dependency Injection

Para facilitar a obtenção das strings de conexão a partir das configurações, você deve criar uma classe que herde de TenantConfiguration e configure a injeção de dependência para carregar as configurações do appSettings.json.

public class AppSettingsTenantConfiguration : TenantConfiguration
{ public string ConnectionString { get; } public AppSettingsTenantConfiguration(string tenantIdentifier, IConfiguration configuration) : base(tenantIdentifier) { ConnectionString = configuration.GetConnectionString(tenantIdentifier); }
}
Enter fullscreen mode
Exit fullscreen mode

Exemplo de AppSettings.json

O arquivo appSettings.json deve conter as configurações dos tenants, como no exemplo abaixo:

{ "ConnectionStrings": { "Tenant1": "Server=localhost;Database=tenant01;User Id=postgres;Password=<password>;", "Tenant2": "Server=localhost;Database=tenant02;User Id=postgres;Password=<password>;" }
}
Enter fullscreen mode
Exit fullscreen mode

Obtendo o ISession

Após configurar o NHibernate e o MultiTenancyConnectionProvider, é necessário configurar a obtenção da sessão (ISession) específica para cada tenant. Isso pode ser feito usando injeção de dependência e o IHttpContextAccessor para capturar o identificador do tenant a partir dos cabeçalhos da solicitação HTTP.

Registrando o ISession

Configurando a injeção de dependência para fornecer a sessão (ISession) correta com base no tenant atual:

builder.Services.AddScoped<ISession>(sp =>
{ var context = sp.GetRequiredService<IHttpContextAccessor>(); var tenant = context.HttpContext?.Request.Headers["x-customer"].ToString(); if (string.IsNullOrEmpty(tenant)) { throw new Exception("Tenant not specified in the request headers."); } var sessionFactory = sp.GetRequiredService<ISessionFactory>(); var tenantConfig = new AppSettingsTenantConfiguration(tenant, sp.GetRequiredService<IConfiguration>()); var session = sessionFactory.WithOptions() .Tenant(tenantConfig) .OpenSession(); return session;
});
Enter fullscreen mode
Exit fullscreen mode

No exemplo acima, o ISession é configurado dinamicamente com base no identificador do tenant fornecido no cabeçalho HTTP x-customer. O AppSettingsTenantConfiguration é utilizado para obter a string de conexão específica para o tenant, permitindo que a sessão se conecte ao banco de dados correto.

Executando

Database Tenant01

Image description

GET Tenant01

Image description

Database Tenant02

Image description

GET Tenant02

Image description

Conclusão

A implementação de MultiTenancy com NHibernate é um processo que alia simplicidade, robustez e escalabilidade. Utilizando a classe TenantConfiguration, podemos acessar/obter/montar as strings de conexão usando a Injeção de Dependência. Utilizando esse modelo de implementação e seguindo os passos e exemplos fornecidos, você usará o MultiTenancy em sua aplicação NHibernate, garantindo uma solução eficiente e adaptável para atender a diferentes necessidades de locatários.


Discover more from Coursity

Subscribe to get the latest posts sent to your email.

Leave a Comment

Your email address will not be published. Required fields are marked *

Discover more from Coursity

Subscribe now to keep reading and get access to the full archive.

Continue reading

Scroll to Top
The technical storage or access that is used exclusively for statistical purposes. Trusted restaurant review & rating.