Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Birçok iş kolu uygulaması birden çok müşteriyle çalışacak şekilde tasarlanmıştır. Müşteri verilerinin "sızdırılması" veya diğer müşteriler ve olası rakipler tarafından görülmemesi için verilerin güvenliğini sağlamak önemlidir. Her müşteri kendi veri kümesine sahip bir uygulama kiracısı olarak kabul edildiğinden, bu uygulamalar "çok kiracılı" olarak sınıflandırılır.
Uyarı
Bu makalede, kullanıcının kimliğinin doğrulanması gerekmeyen bir yerel veritabanı kullanılır. Üretim uygulamaları kullanılabilir en güvenli kimlik doğrulama akışını kullanmalıdır. Dağıtılan test ve üretim uygulamaları için kimlik doğrulaması hakkında daha fazla bilgi için bkz . Güvenli kimlik doğrulama akışları.
Önemli
Bu belgede "olduğu gibi" örnekler ve çözümler sağlanır. Bunlar "en iyi uygulamalar" değil, sizin dikkate alınması gereken "çalışma uygulamaları" olarak tasarlanmıştır.
Çoklu kiracıyı destekleme
Uygulamalarda çok kiracılılık uygulamaya yönelik birçok yaklaşım vardır. Yaygın yaklaşımlardan biri (bazen bir gereksinimdir), her müşteri için verileri ayrı bir veritabanında tutmaktır. Şema aynıdır ancak veriler müşteriye özgüdür. Bir diğer yaklaşım da mevcut veritabanındaki verileri müşteriye göre bölümlendirmektir. Bu, bir tablodaki bir sütun kullanılarak veya her kiracı için şema içeren birden çok şemada bir tablo bulunarak yapılabilir.
Yaklaşım | Kiracı için sütun mu? | Kiracı başına şema mı? | Birden çok Veritabanı mı? | EF Core Desteği |
---|---|---|---|---|
Ayırt Edici (sütun) | Evet | Hayır | Hayır | Genel sorgu filtresi |
Kiracı başına veritabanı | Hayır | Hayır | Evet | Yapılandırma |
Kiracı başına şema | Hayır | Evet | Hayır | Desteklenmez |
Kiracı başına veritabanı yaklaşımı için doğru veritabanına geçiş yapmak, doğru bağlantı dizesi sağlamak kadar basittir. Veriler tek bir veritabanında depolandığında, genel sorgu filtresi , kiracı kimliği sütununa göre satırları otomatik olarak filtrelemek için kullanılabilir ve geliştiricilerin diğer müşterilerin verilerine erişebilecek kodu yanlışlıkla yazmamasını sağlar.
Bu örnekler konsol, WPF, WinForms ve ASP.NET Core uygulamaları dahil olmak üzere çoğu uygulama modelinde sorunsuz çalışmalıdır. Blazor Server uygulamaları özel bir değerlendirme gerektirir.
Blazor Server uygulamaları ve fabrikanın ömrü
Blazor uygulamalarında Entity Framework Core'u kullanmak için Varsayılan olarak, fabrika bir tekil nesne olduğundan, uygulamanın tüm kullanıcıları için yalnızca bir tane mevcuttur. Genellikle sorun olmaz çünkü fabrika paylaşılsa da, tek tek DbContext
örnekler paylaşılmamaktadır.
Çok kiracılı kullanımda, bağlantı dizesi kullanıcıya göre değişebilir. Fabrika yapılandırmayı aynı yaşam süresiyle önbelleğe alır, bu da tüm kullanıcıların aynı yapılandırmayı paylaşması gerektiği anlamına gelir. Bu nedenle, yaşam süresi olarak Scoped
değiştirilmelidir.
Bu sorun Blazor WebAssembly uygulamalarında meydana gelmez çünkü singleton kullanıcıya özgü şekilde sınırlıdır. Öte yandan Blazor Server uygulamaları benzersiz bir zorluk sunar. Uygulama bir web uygulaması olsa da SignalR kullanılarak gerçek zamanlı iletişim tarafından "canlı tutulur". Kullanıcı başına bir oturum oluşturulur ve ilk isteğin ötesinde sürer. Yeni ayarlara izin vermek için kullanıcı başına yeni bir fabrika sağlanmalıdır. Bu özel fabrikanın kullanım ömrü sınırlıdır ve her kullanıcı oturumu için yeni bir örnek oluşturulur.
Örnek bir çözüm (tek veritabanı)
Kullanıcının geçerli kiracısını ayarlayan basit bir ITenantService
hizmeti oluşturmak olası bir çözümdür. Kiracı değiştiğinde kodun bildirilmesi için geri çağırmalar sağlar. Uygulama (netlik için geri çağırmalar atlanmış olarak) şöyle görünebilir:
namespace Common
{
public interface ITenantService
{
string Tenant { get; }
void SetTenant(string tenant);
string[] GetTenants();
event TenantChangedEventHandler OnTenantChanged;
}
}
DbContext
daha sonra çoklu kiracılığı yönetebilir. Yaklaşım, veritabanı stratejinize bağlıdır. Tüm kiracıları tek bir veritabanında depoluyorsanız, büyük olasılıkla bir sorgu filtresi kullanacaksınız.
ITenantService
, bağımlılık ekleme yoluyla oluşturucuya geçirilir ve kiracı tanımlayıcısını çözümlemek ve depolamak için kullanılır.
public ContactContext(
DbContextOptions<ContactContext> opts,
ITenantService service)
: base(opts) => _tenant = service.Tenant;
OnModelCreating
yöntemi, sorgu filtresini belirtmek için geçersiz kılınmıştır.
protected override void OnModelCreating(ModelBuilder modelBuilder)
=> modelBuilder.Entity<MultitenantContact>()
.HasQueryFilter(mt => mt.Tenant == _tenant);
Bu, her sorgunun her istekte kiracıya filtrelendiğinden emin olmasını sağlar. Genel filtre otomatik olarak uygulanacağından uygulama kodunda filtreleme yapmanız gerekmez.
Kiracı sağlayıcısı ve DbContextFactory
örnek olarak Sqlite kullanılarak uygulama başlangıcında aşağıdaki gibi yapılandırılır:
builder.Services.AddDbContextFactory<ContactContext>(
opt => opt.UseSqlite("Data Source=singledb.sqlite"), ServiceLifetime.Scoped);
Hizmet ömrünün ile ServiceLifetime.Scoped
yapılandırıldığına dikkat edin. Bu, kiracı sağlayıcıya bağımlı olmasını sağlar.
Not
Bağımlılıklar her zaman singleton nesneye doğru akmalıdır. Bu, hizmetin başka bir Scoped
Scoped
hizmete veya Singleton
hizmete bağımlı olabileceği, ancak Singleton
hizmetin yalnızca diğer Singleton
hizmetlere bağlı olabileceği anlamına gelir: Transient => Scoped => Singleton
.
Birden çok şema
Uyarı
Bu senaryo EF Core tarafından doğrudan desteklenmez ve önerilen bir çözüm değildir.
Farklı bir yaklaşımda, aynı veritabanı tenant1
ve tenant2
öğelerini tablo şemalarını kullanarak işleyebilir.
-
Kiracı1 -
tenant1.CustomerData
-
Kiracı2 -
tenant2.CustomerData
Geçişlerle veritabanı güncelleştirmelerini işlemek için EF Core kullanmıyorsanız ve zaten çok şemalı tablolarınız varsa, içindeki şemayı DbContext
OnModelCreating
şöyle geçersiz kılabilirsiniz (tablo CustomerData
şeması kiracıya ayarlanır):
protected override void OnModelCreating(ModelBuilder modelBuilder) =>
modelBuilder.Entity<CustomerData>().ToTable(nameof(CustomerData), tenant);
Birden çok veritabanı ve bağlantı dizesi
Birden çok veritabanı sürümü, her kiracı için farklı bir bağlantı dizesi kullanılarak uygulanır. Uygulama başlangıcında, hizmet sağlayıcısı çözümlenerek ve bu hizmet sağlayıcısı kullanılarak bağlantı dizesi oluşturulabilir. Yapılandırma dosyasına kiracıya göre bağlantı dizesi bölümü eklenirappsettings.json
.
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"ConnectionStrings": {
"TenantA": "Data Source=tenantacontacts.sqlite",
"TenantB": "Data Source=tenantbcontacts.sqlite"
},
"AllowedHosts": "*"
}
Hizmet ve yapılandırma her ikisi de DbContext
içerisine enjekte edilir.
public ContactContext(
DbContextOptions<ContactContext> opts,
IConfiguration config,
ITenantService service)
: base(opts)
{
_tenantService = service;
_configuration = config;
}
Kiracı, ardından OnConfiguring
içindeki bağlantı dizesini aramak için kullanılır.
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
var tenant = _tenantService.Tenant;
var connectionStr = _configuration.GetConnectionString(tenant);
optionsBuilder.UseSqlite(connectionStr);
}
Bu, kullanıcı aynı oturum sırasında kiracıları değiştiremiyorsa çoğu senaryoda düzgün çalışır.
Kiracılar arasında geçiş yapma
Birden çok veritabanı için önceki yapılandırmada, seçenekler Scoped
düzeyinde önbelleğe alınır. Bu, kullanıcı kiracıyı değiştirirse seçeneklerin yeniden değerlendirilmediği ve dolayısıyla kiracı değişikliğinin sorgulara yansıtılmadığı anlamına gelir.
Kiracının değişebileceği durumlarda bunun kolay çözümü, yaşam süresini Transient.
Bu olarak ayarlamaktır. Bu, kiracının her istendiğinde DbContext
bağlantı dizesi ile birlikte yeniden değerlendirilmesini sağlar. Kullanıcı kiracıları istedikleri sıklıkta değiştirebilir. Aşağıdaki tablo, fabrikanız için en anlamlı ömrü seçmenize yardımcı olur.
Senaryo | Tek veritabanı | Birden çok veritabanı |
---|---|---|
Kullanıcı tek bir kiracıda kalır | Scoped |
Scoped |
Kullanıcı kiracıları değiştirebilir | Scoped |
Transient |
Veritabanınız kullanıcıya özgü bağımlılıkları kabul etmiyorsa, yine de Singleton
varsayılan değer anlamlıdır.
Performans notları
EF Core, DbContext
örneklerinin mümkün olduğunca az ek yükle ve hızlı bir şekilde oluşturulabilmesi için tasarlanmıştır. Bu nedenle, işlem başına yeni bir DbContext
oluşturmak genellikle iyi olacaktır. Bu yaklaşım uygulamanızın performansını etkiliyorsa DbContext havuzu kullanmayı göz önünde bulundurun.
Sonuç
Bu, EF Core uygulamalarında çok kiracılılık uygulamaya yönelik çalışma kılavuzudur. Başka örnekleriniz veya senaryolarınız varsa veya geri bildirim sağlamak istiyorsanız lütfen bir sorun açın ve bu belgeye başvurun.