ASP.NET MVC Multi Tenant,使用Autofac和Owin分离数据库

时间:2017-07-16 17:09:03

标签: asp.net asp.net-mvc dependency-injection autofac multi-tenant

场合

我们有一个与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来注册租户peta poco数据库实例以注入PetaPocoUnitOfWork以及应用程序现在如何解决此问题?因为我们需要访问2个数据库(主数据库和个人租户数据库),首先是获取租户连接字符串,然后是对租户数据库进行crud操作。
  2. 我们的PetaPocoUnitOfWork包含要使用的数据库怎么样?我们是否应该按租户注册这个数据并使用autofac的解析方法传递数据库并根据请求在实例上设置它?

1 个答案:

答案 0 :(得分:0)

您实际上可以使用连接字符串名称和租户上下文的分片管理器[更类似于Microsoft Azure Shard Manager的分片管理器]。根据这些信息,它可以解析连接,然后将其传递给Context。

这将在每个租户的基础上解决,然后应用程序与基于租户的连接一起工作,即在每个服务中注入,以便建立[登录用户身份]的身份可以用于设置EF / Data Tier中的右连接对象。这样,它便于松散耦合设计,并且易于测试和模型化。

您可以在github repository

中找到示例代码和很少的文档说明 恕我直言,我建议采用这种方法背后的理由是,每个租户的分区将存储在数据库[通常是您的主数据库]中,即使您能够使用某些数据库也需要获取和使用 - 通过Autofac注入这些。我没有在这里重现代码,因为这里需要一些长的解释来获取代码和解释,这在github中得到了解决。

HTH