0

形勢ASP.NET MVC多租戶使用Autofac和Owin

分離式數據庫,我們必須與SQL Server一起運行一個ASP.NET MVC應用5。我們有一個主數據庫,其中包含一個表Tenants,我們所有的租戶都使用連接字符串屬性註冊到他們自己的個人數據庫。

對於認證,我們使用Microsoft Owin庫。

Autofac

我們已經建立autofac這樣的:

var builder = new ContainerBuilder(); 

// Register the controllers 
builder.RegisterControllers(typeof(Project.Web.ProjectApplication).Assembly); 

// ### Register all persistence objects 

// Project main database registration (Peta Poco instance using connectionstring as parameter) 
builder.RegisterType<ProjectDatabase>() 
    .As<ProjectDatabase>() 
    .WithParameter(new NamedParameter("connectionString", GlobalSettings.ProjectTenantConnectionString)) 
    .InstancePerLifetimeScope(); 

// Project tenant specific database registration 
// ... 

// Unit of work 
builder.RegisterType<PetaPocoUnitOfWork>() 
    .As<IDatabaseUnitOfWork>() 
    .InstancePerRequest(); 

// ### Register all services 
builder.RegisterAssemblyTypes(Assembly.Load("Project.Core")) 
    .Where(t => t.Name.EndsWith("Service")) 
    .AsImplementedInterfaces() 
    .InstancePerLifetimeScope(); 

// ### Register all repositories 
builder.RegisterType<RepositoryFactory>() 
    .As<IRepositoryFactory>() 
    .InstancePerLifetimeScope(); 

builder.RegisterAssemblyTypes(Assembly.Load("Project.Core")) 
    .Where(t => t.Name.EndsWith("Repository")) 
    .AsImplementedInterfaces() 
    .InstancePerLifetimeScope(); 

// Register Logging 
builder.RegisterType<Logger>().As<ILogger>().InstancePerLifetimeScope(); 

// Register Automapper 
builder.RegisterAssemblyTypes(Assembly.Load("Project.Core")).As<Profile>(); 
builder.RegisterAssemblyTypes(Assembly.Load("Project.Web")).As<Profile>(); 
builder.Register(context => new MapperConfiguration(cfg => 
{ 
    foreach (var profile in context.Resolve<IEnumerable<Profile>>()) 
    { 
     cfg.AddProfile(profile); 
    } 
})).AsSelf().SingleInstance(); 
builder.Register(c => c.Resolve<MapperConfiguration>().CreateMapper(c.Resolve)) 
    .As<AutoMapper.IMapper>() 
    .InstancePerLifetimeScope(); 

// Register Owin 
builder.Register(ctx => HttpContext.Current.GetOwinContext()).As<IOwinContext>(); 
builder.Register(
    c => new IdentityUserStore(c.Resolve<IUserService>())) 
.AsImplementedInterfaces().InstancePerRequest(); 
builder.Register(
    ctx => ctx.Resolve<IOwinContext>().Authentication) 
.As<IAuthenticationManager>().InstancePerRequest(); 
builder.RegisterType<IdentityUserManager>().AsSelf().Inst‌​ancePerRequest(); 

// Build container 
var container = builder.Build(); 

// Tenant container 
var tenantIdentifier = new RequestSubdomainStrategy(); 
var mtc = new MultitenantContainer(tenantIdentifier, container); 

// Set autofac as dependency resolver 
DependencyResolver.SetResolver(new AutofacDependencyResolver(mtc)); 

更多細節

使用這個設置中,我們有Autofac一個實例安裝到我們的主Tenant數據庫。 然後將其注入我們的PetaPocoUnitOfWork以進行交易。

這有效,我可以得到租戶信息。

但是現在我們需要以下工作,我們不知道從哪裏開始。

  1. 我們如何設置autofac註冊租戶地圖POCO數據庫實例注入PetaPocoUnitOfWork,以及如何將應用程序現在該怎麼解決這個問題?因爲我們需要訪問2個數據庫(主數據庫和個人租戶數據庫),首先需要獲取租戶連接字符串,然後再對租戶數據庫執行crud操作。
  2. 我們的PetaPocoUnitOfWork包含數據庫的工作方式,我們是否應該爲每個租戶註冊,並使用autofac的解析方法傳遞數據庫,並在每個請求的實例上設置它?
+0

很高興地看到,已經3 SO用戶要關閉這個問題...如果它能夠廣泛我應該將它們放置在分離式問題,並在一起或鏈接...? – Mivaweb

回答

0

實際上,您可以擁有一個使用連接字符串名稱和租戶上下文的分區管理器[更類似於Microsoft Azure分區管理器]。從這些信息中,它可以解析連接,然後將其傳遞給上下文。

這將在每個租戶的基礎上加以解決,然後應用程序使用基於租戶連接,即這是在每一項服務的注入,使建立[登錄用戶的身份]身份可以用來設置EF/Data層中的正確連接對象。這樣,它便於鬆耦合設計,也便於測試和模型。

你可以找到示例代碼和這樣的實現會是什麼樣子的小文件從我github repository

恕我直言,這種做法背後的理由,我認爲將是每個租戶分區將被存儲在事實一個數據庫[通常是您的主數據庫],即使您能夠通過Autofac注入這些數據庫,也需要獲取和使用這些數據庫。我沒有在這裏重現代碼,因爲它需要一些長的解釋來獲取代碼和解釋,這在github中已經得到了關注。

HTH