Farklı domainler için multi tenant middleware kullanımı

Tenant, saas veya store mantığı ile çalışan bir web uygulamamız var diyelim ve yazılan bütün metotlar için appId yi sorgunun sonuna eklemek gerekiyor.Ama biz bu işlemi otomatik hale getireceğiz.
Url bizim appId’mizi verecektir.
Amacımız :
kod temizliği, güvenlik ve esneklik katacaktır uygulamamıza.

Url’den Gelen Tenant ‘ı cache alıyoruz.

protected override Task<TenantContext<AppTenant>> ResolveAsync(HttpContext context)
        {
            TenantContext<AppTenant> tenantContext = null;
            var hostName = context.Request.Host.Value.ToLower();

            var tenant = _tenantService.GetTenantResultByHostName(hostName);

            var appTenant = new AppTenant()
            {
                Id = tenant.tenant.tenantId,
                Host = tenant.tenant.host,
                Name = tenant.tenant.name,
                RequireSSL = tenant.tenant.RequireSSL,
                LanguageId = tenant.tenant.LanguageId
            };

            if (tenant != null)
            {
                tenantContext = new TenantContext<AppTenant>(appTenant);
            }
            return Task.FromResult(tenantContext);
        }


Örneklerle biraz daha açalım konuyu.

1. adımda appId’yi manuel olarak yazacağım ve bir Get işlemi deneyeceğim.

var userList= _userRepository.Table.where(x=>x.AppId == _appId);

2. adımda ise appId’yi middleware de otomatik eklemiş örneği görelim.

var userList= _userRepository.Table;

Aradaki fark şahane dimi.

Bu senaryoda de her tenant’ın kendi domaini var. Proje ayağa kalkerken ayarlar bir defa yüklenecek.
Önce context classımıı açıp içerisine asembly’den faydalanarak bütün veri tabanı entity classlarına appId ekleyip oluşturduğumuz expression’ı HasQueryFilter ile gönderiyoruz.

 private void AddAllConfigurations(ModelBuilder modelBuilder)
{
	foreach (var entityType in modelBuilder.Model.GetEntityTypes())
	{
		ConfigureGlobalFiltersMethodInfo
			.MakeGenericMethod(entityType.ClrType)
			.Invoke(this, new object[] { modelBuilder });
	}
}


private void ConfigureTenantQueryFilter<TEntity>
                       (ModelBuilder modelBuilder) where TEntity : class
        {
            Expression<Func<TEntity, bool>> expression = null;

            if (typeof(IHaveTenant).IsAssignableFrom(typeof(TEntity)))
            {
                expression = e => ((IHaveTenant)e).TenantId == GetTenantId() 
                  || ((IHaveTenant)e).TenantId == null 
                  || ((IHaveTenant)e).TenantId == 0;
            }

            if (expression != null)
            {
                modelBuilder.Entity<TEntity>().HasQueryFilter(expression);
            }
        }

private static readonly MethodInfo ConfigureGlobalFiltersMethodInfo =
            typeof(EfDbContext).GetMethod(nameof(ConfigureTenantQueryFilter),
                BindingFlags.Instance | BindingFlags.NonPublic);

Artık tenant ayarları tamam. Sorgular sadece bulunduğu domain üzerindeki kaynaklara eişecektir.
Daha detaylı bir tenant makalesi ile görüşmek üzere

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir