ASP.NET MVC多租户,具有使用Autofac和Owin的独立数据库
形势 我们有一个ASP.NETMVC5应用程序与SQLServer一起运行。我们有一个主数据库,其中包含一个表ASP.NET MVC多租户,具有使用Autofac和Owin的独立数据库,asp.net,asp.net-mvc,dependency-injection,autofac,multi-tenant,Asp.net,Asp.net Mvc,Dependency Injection,Autofac,Multi Tenant,形势 我们有一个ASP.NETMVC5应用程序与SQLServer一起运行。我们有一个主数据库,其中包含一个表Tenants,其中所有租户都使用连接字符串属性注册到他们自己的个人数据库 对于身份验证,我们使用的是Microsoft Owin库 Autofac 我们已将autofac设置为: var builder = new ContainerBuilder(); // Register the controllers builder.RegisterControllers(typeof(Pr
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().InstancePerRequest();
// 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));
var builder=newcontainerbuilder();
//注册控制器
注册控制器(typeof(Project.Web.ProjectApplication.Assembly);
//####注册所有持久化对象
//项目主数据库注册(使用connectionstring作为参数的Peta Poco实例)
builder.RegisterType()
.As()
.WithParameter(新名称Parameter(“connectionString”,GlobalSettings.ProjectTenantConnectionString))
.InstancePerLifetimeScope();
//项目租户特定数据库注册
// ...
//工作单位
builder.RegisterType()
.As()
.InstancePerRequest();
//####注册所有服务
builder.RegisterAssemblyTypes(Assembly.Load(“Project.Core”))
.Where(t=>t.Name.EndsWith(“服务”))
.AsImplementedInterfaces()
.InstancePerLifetimeScope();
//####注册所有存储库
builder.RegisterType()
.As()
.InstancePerLifetimeScope();
builder.RegisterAssemblyTypes(Assembly.Load(“Project.Core”))
.Where(t=>t.Name.EndsWith(“存储库”))
.AsImplementedInterfaces()
.InstancePerLifetimeScope();
//寄存器记录
builder.RegisterType();
//寄存器自动映射器
builder.RegisterAssemblyTypes(Assembly.Load(“Project.Core”)).As();
builder.RegisterAssemblyTypes(Assembly.Load(“Project.Web”)).As();
注册(上下文=>新的MapperConfiguration(cfg=>
{
foreach(context.Resolve()中的变量配置文件)
{
cfg.AddProfile(profile);
}
})).AsSelf().SingleInstance();
builder.Register(c=>c.Resolve().CreateMapper(c.Resolve))
.As()
.InstancePerLifetimeScope();
//注册Owin
Register(ctx=>HttpContext.Current.GetOwinContext()).As();
建筑商登记(
c=>newidentityUserStore(c.Resolve())
.AsImplementedInterfaces().InstancePerRequest();
建筑商登记(
ctx=>ctx.Resolve().Authentication)
.As().InstancePerRequest();
builder.RegisterType().AsSelf().InstancePerRequest();
//构建容器
var container=builder.Build();
//租户集装箱
var tenantIdentifier=new RequestSubdomainStrategy();
var mtc=新的多租户容器(租户标识符、容器);
//将autofac设置为依赖项解析程序
SetResolver(新的AutofacDependencyResolver(mtc));
更多详细信息
使用此设置,我们在Autofac中为我们的主租户数据库设置了一个实例。
然后将其注入我们的PetaPocoUnitOfWork
以提交事务
这很有效,我可以得到租户信息
但现在,我们需要以下的工作,我们不知道从哪里开始
我们如何设置autofac来注册租户,将peta poco数据库实例注入PetaPocoUnitOfWork
,应用程序现在将如何解决这个问题?因为我们需要访问两个数据库(主数据库和个人租户数据库),首先获取租户连接字符串,然后对租户数据库执行crud操作
我们的PetaPocoUnitOfWork
,其中包含要使用的数据库,我们是否也应该为每个租户注册此项,并使用autofac的解析方法传递数据库,并为每个请求在实例上设置此项
实际上,您可以有一个碎片管理器[更类似于Microsoft Azure碎片管理器],它采用connectionstring名称和租户上下文。根据这些信息,它可以解析连接,然后将其传递给上下文
这将在每个租户的基础上解决,然后应用程序使用基于租户的连接,即,这将被注入到每个服务中,以便建立的标识[登录用户标识]可用于在EF/数据层中设置正确的连接对象。这样,它有利于松耦合设计,也易于测试和建模
您可以从我的
IMHO,我所建议的这种方法背后的基本原理是,每个租户的分区将存储在一个数据库(通常是您的主数据库)中,即使您能够通过Autofac以某种方式注入分区,也需要获取和使用该分区。我没有在这里复制代码,因为在这里获得代码和解释需要一点长的解释,这在github中得到了关注
HTH您实际上可以拥有一个碎片管理器[更类似于Microsoft Azure碎片管理器],它采用connectionstring名称和租户上下文。根据这些信息,它可以解析连接,然后将其传递给上下文
这将在每个租户的基础上解决,然后应用程序使用基于租户的连接,即,这将被注入到每个服务中,以便建立的标识[登录用户标识]可用于在EF/数据层中设置正确的连接对象。这样,它有利于松耦合设计,也易于测试和建模
您可以从我的
IMHO,我所建议的这种方法背后的基本原理是,每个租户的分区将存储在一个数据库(通常是您的主数据库)中,即使您能够通过Autofac以某种方式注入分区,也需要获取和使用该分区。我没有在这里复制代码,因为它需要花费一些时间来解释