Autofac。为每个租户注册HttpContext.Session

时间:2014-09-25 18:34:40

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

我正在开发一个多租户应用程序。目前我想要实现的是获得每个租户唯一的HttpContext实例

  1. 每个租户都有自己的数据库。
  2. 所有租户共享相同的功能(没有任何租户X特定控制器)
  3. 有一个用于查询所有租户的主数据库(因此,在访问租户的设置(例如:connectionString)之前,必须至少有一个命中主数据库)。
  4. 租户是从 RequestContext RouteData.Values["tenant"]
  5. 中识别出来的

    以下是一些简化代码,因此请不要关注架构:

    路线网址模式: {tenant}/{controller}/{action}/{id}

    的Global.asax.cs:

        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
    
            var builder = new ContainerBuilder();
            builder.RegisterControllers(Assembly.GetExecutingAssembly());
    
            // Delegates for BuildSessionFactory and GetSession are declared under Application_Start()
            // Registers SessionFactory to be Singletone per Tenant
            builder.Register(BuildSessionFactory).As<ISessionFactory>().InstancePerTenant();
            builder.Register(GetSession).As<ISession>().InstancePerRequest();
            // This is the module responsible for mapping HttpContextBase to HttpContextWrapper and other mvc specific abastractions
            builder.RegisterModule(new AutofacWebTypesModule());
    
            var container = builder.Build();
            // Build multitenant container
            var mtc = new MultitenantContainer(new RouteDataTenantIdentificationStrategy("tenant"), container);
    
            DependencyResolver.SetResolver(new AutofacDependencyResolver(mtc));
        }
    
        private ISessionFactory BuildSessionFactory(IComponentContext context)
        {
            return new NHibernateConfiguration().BuildConfiguration().BuildSessionFactory();
        }
    
        private ISession GetSession(IComponentContext context)
        {
            return context.Resolve<ISessionFactory>().OpenSession();
        }
    

    HomeController 示例:

    public class HomeController : Controller
    {
        private readonly ISession _session;
        private readonly HttpContextBase _context;
    
        public HomeController(ISession session, HttpContextBase context)
        {
            _session = session;
            _context = context;
        }
    
        public ActionResult Index()
        {
            // Setting up HttpContext.Session["testSessionKey"] only for tenant1
            if (_context.Request.RequestContext.RouteData.Values["tenant"] as string == "tenant1")
            {
                _context.Session.Add("testSessionKey","Some value specific to tenant1 only");
            }
            using (var transaction = _session.BeginTransaction(IsolationLevel.ReadCommitted))
            {
                var tenants = _session.Query<Tenant>().ToList();
                transaction.Commit();
                return View(tenants);
            }
        }
    }
    

    工作流程:

    备注上面的代码忽略了租户的真实存在。它只是根据RouteDataTenantIdentificationStrategy("tenant")类定义来满足依赖关系(通过RouteData识别没有例外)。

    • 现在,当我访问网址时:/tenant1/Home/Index已添加HttpContext.Session['testSessionKey']
    • 当我尝试访问/otherTenant/Home/Index之类的内容时HttpContext.Session['testSessionKey']仍在那里。

    问题1:

    如何使用 Autofac 的依赖注入实现每个租户的唯一HttpContext?

    问题2:

    如何获得比HttpContext更多的东西?让我们说一个包含租户的HttpContext

    的WorkContext

    如果有什么不清楚,请询问,我会提供必要的说明。谢谢!

1 个答案:

答案 0 :(得分:2)

如果将上下文值的自定义推送到HttpContextBase的注册,则可以执行此操作。而不是使用AutofacWebTypesModule,请使用您自己的注册:

builder.Register(c =>
{
  var httpContext = new HttpContextWrapper(HttpContext.Current);
  var strategy = c.Resolve<ITenantIdentificationStrategy>();
  // Update the context here
  return httpContext;
}).As<HttpContextBase>()
.InstancePerRequest();

这意味着您还应该在容器中注册您的租户ID策略,但这很容易。

(很抱歉这个简短的片段;我正在手机上旅行。)