public void InstancePerTenant_RootAndPerTenantDependencies()
        {
            var strategy = new StubTenantIdentificationStrategy()
            {
                TenantId = "tenant1"
            };
            var builder = new ContainerBuilder();
            builder.RegisterType<StubDependency3Impl>().As<IStubDependency3>().InstancePerTenant();
            var mtc = new MultitenantContainer(strategy, builder.Build());
            mtc.ConfigureTenant("tenant1", b => b.RegisterType<StubDependency1Impl1>().As<IStubDependency1>().InstancePerTenant());
            mtc.ConfigureTenant("tenant2", b => b.RegisterType<StubDependency1Impl1>().As<IStubDependency1>().InstancePerTenant());

            // Two resolutions for a single tenant
            var dep1 = mtc.Resolve<IStubDependency3>();
            var dep2 = mtc.Resolve<IStubDependency3>();

            // One resolution for a different tenant
            strategy.TenantId = "tenant2";
            var dep3 = mtc.Resolve<IStubDependency3>();

            Assert.AreSame(dep1, dep2, "The two dependencies resolved for the first tenant should be the same.");
            Assert.AreNotSame(dep1, dep3, "The dependencies resolved across tenants should not be the same.");
            Assert.AreSame(dep1.Dependency, dep2.Dependency, "The two sub-dependencies resolved for the first tenant should be the same.");
            Assert.AreNotSame(dep1.Dependency, dep3.Dependency, "The sub-dependencies resolved across tenants should not be the same.");
        }
Example #2
0
        /// <summary>
        /// Configures the multitenant dependency container.
        /// </summary>
        private static IContainer ConfigureDependencies()
        {
            // Register default dependencies in the application container.
            var builder = new ContainerBuilder();
            builder.RegisterType<Consumer>().As<IDependencyConsumer>().InstancePerDependency();
            builder.RegisterType<BaseDependency>().As<IDependency>().SingleInstance();
            var appContainer = builder.Build();

            // Create the multitenant container.
            var mtc = new MultitenantContainer(_tenantIdentifier, appContainer);

            // Configure overrides for tenant 1. Tenant 1 registers their dependencies
            // as instance-per-dependency.
            mtc.ConfigureTenant('1', b => b.RegisterType<Tenant1Dependency>().As<IDependency>().InstancePerDependency());

            // Configure overrides for tenant 2. Tenant 2 registers their dependencies
            // as singletons.
            mtc.ConfigureTenant('2', b => b.RegisterType<Tenant2Dependency>().As<IDependency>().SingleInstance());

            // Configure overrides for the default tenant. That means the default
            // tenant will have some different dependencies than other unconfigured
            // tenants.
            mtc.ConfigureTenant(null, b => b.RegisterType<DefaultTenantDependency>().As<IDependency>().SingleInstance());

            return mtc;
        }
 public void BeginLifetimeScope_ChildScopeCanBeConfigured()
 {
     var strategy = new StubTenantIdentificationStrategy()
     {
         TenantId = "tenant1"
     };
     var mtc = new MultitenantContainer(strategy, new ContainerBuilder().Build());
     mtc.ConfigureTenant("tenant1", b => b.RegisterType<StubDependency1Impl1>().As<IStubDependency1>());
     using (var nestedScope = mtc.BeginLifetimeScope(b => b.RegisterType<StubDependency1Impl2>().As<IStubDependency1>()))
     {
         var nestedDependency = nestedScope.Resolve<IStubDependency1>();
         Assert.IsInstanceOf<StubDependency1Impl2>(nestedDependency, "The child scope was not properly configured.");
     }
 }
 public void BeginLifetimeScope_CreatesLifetimeScopeForCurrentTenant()
 {
     var strategy = new StubTenantIdentificationStrategy()
     {
         TenantId = "tenant1"
     };
     var mtc = new MultitenantContainer(strategy, new ContainerBuilder().Build());
     mtc.ConfigureTenant("tenant1", b => b.RegisterType<StubDependency1Impl2>().As<IStubDependency1>().InstancePerLifetimeScope());
     var tenantScope = mtc.GetCurrentTenantScope();
     var tenantDependency = tenantScope.Resolve<IStubDependency1>();
     using (var nestedScope = mtc.BeginLifetimeScope())
     {
         var nestedDependency = nestedScope.Resolve<IStubDependency1>();
         Assert.AreNotSame(tenantDependency, nestedDependency, "The dependency should be registered, but the scope should resolve a new instance.");
     }
 }
Example #5
0
        /// <summary>
        /// Handles the global application startup event.
        /// </summary>
        protected void Application_Start()
        {
            // Create the tenant ID strategy. Required for multitenant integration.
            var tenantIdStrategy = new RequestParameterTenantIdentificationStrategy("tenant");

            // Register application-level dependencies and controllers. Note that
            // we are manually registering controllers rather than all at the same
            // time because some of the controllers in this sample application
            // are for specific tenants.
            var builder = new ContainerBuilder();
            builder.RegisterType<HomeController>();
            builder.RegisterType<BaseDependency>().As<IDependency>();

            // Adding the tenant ID strategy into the container so controllers
            // can display output about the current tenant.
            builder.RegisterInstance(tenantIdStrategy).As<ITenantIdentificationStrategy>();

            // The service client is not different per tenant because
            // the service itself is multitenant - one client for all
            // the tenants and the service implementation switches.
            builder.Register(c => new ChannelFactory<IMultitenantService>(new BasicHttpBinding(), new EndpointAddress("http://localhost:63578/MultitenantService.svc"))).SingleInstance();
            builder.Register(c => new ChannelFactory<IMetadataConsumer>(new WSHttpBinding(), new EndpointAddress("http://localhost:63578/MetadataConsumer.svc"))).SingleInstance();

            // Register an endpoint behavior on the client channel factory that
            // will propagate the tenant ID across the wire in a message header.
            // On the service side, you'll need to read the header from incoming
            // message headers to reconstitute the incoming tenant ID.
            builder.Register(c =>
            {
                var factory = c.Resolve<ChannelFactory<IMultitenantService>>();
                factory.Opening += (sender, args) => factory.Endpoint.Behaviors.Add(new TenantPropagationBehavior<string>(tenantIdStrategy));
                return factory.CreateChannel();
            }).InstancePerRequest();
            builder.Register(c =>
            {
                var factory = c.Resolve<ChannelFactory<IMetadataConsumer>>();
                factory.Opening += (sender, args) => factory.Endpoint.Behaviors.Add(new TenantPropagationBehavior<string>(tenantIdStrategy));
                return factory.CreateChannel();
            }).InstancePerRequest();

            // Create the multitenant container based on the application
            // defaults - here's where the multitenant bits truly come into play.
            var mtc = new MultitenantContainer(tenantIdStrategy, builder.Build());

            // Notice we configure tenant IDs as strings below because the tenant
            // identification strategy retrieves string values from the request
            // context. To use strongly-typed tenant IDs, create a custom tenant
            // identification strategy that returns the appropriate type.

            // Configure overrides for tenant 1 - dependencies, controllers, etc.
            mtc.ConfigureTenant("1",
                b =>
                {
                    b.RegisterType<Tenant1Dependency>().As<IDependency>().InstancePerDependency();
                    b.RegisterType<Tenant1Controller>().As<HomeController>();
                });

            // Configure overrides for tenant 2 - dependencies, controllers, etc.
            mtc.ConfigureTenant("2",
                b =>
                {
                    b.RegisterType<Tenant2Dependency>().As<IDependency>().SingleInstance();
                    b.RegisterType<Tenant2Controller>().As<HomeController>();
                });

            // Configure overrides for the default tenant. That means the default
            // tenant will have some different dependencies than other unconfigured
            // tenants.
            mtc.ConfigureTenant(null, b => b.RegisterType<DefaultTenantDependency>().As<IDependency>().SingleInstance());

            // Create the dependency resolver using the
            // multitenant container instead of the application container.
            DependencyResolver.SetResolver(new AutofacDependencyResolver(mtc));

            // Perform the standard MVC setup requirements.
            AreaRegistration.RegisterAllAreas();
            RegisterRoutes(RouteTable.Routes);
        }
 public void ConfigureTenant_DoesNotAllowMultipleSubsequentRegistrationsForDefaultTenant()
 {
     var builder = new ContainerBuilder();
     builder.RegisterType<StubDependency1Impl1>().As<IStubDependency1>();
     var strategy = new StubTenantIdentificationStrategy()
     {
         TenantId = "tenant1"
     };
     var mtc = new MultitenantContainer(strategy, builder.Build());
     mtc.ConfigureTenant(null, b => b.RegisterType<StubDependency1Impl2>().As<IStubDependency1>());
     Assert.Throws<InvalidOperationException>(() => mtc.ConfigureTenant(null, b => b.RegisterType<StubDependency2Impl2>().As<IStubDependency2>()));
 }
        public void Resolve_TenantLevelSingleton()
        {
            var builder = new ContainerBuilder();
            builder.RegisterType<StubDependency1Impl1>().As<IStubDependency1>().SingleInstance();

            var strategy = new StubTenantIdentificationStrategy()
            {
                TenantId = "tenant1"
            };
            var mtc = new MultitenantContainer(strategy, builder.Build());
            mtc.ConfigureTenant("tenant1", b => b.RegisterType<StubDependency1Impl2>().As<IStubDependency1>().SingleInstance());
            mtc.ConfigureTenant("tenant2", b => b.RegisterType<StubDependency1Impl2>().As<IStubDependency1>().SingleInstance());

            // Get the application-level dependency
            var appLevel = mtc.ApplicationContainer.Resolve<IStubDependency1>();

            // Two resolutions for a single tenant
            var dep1 = mtc.Resolve<IStubDependency1>();
            var dep2 = mtc.Resolve<IStubDependency1>();

            // One resolution for a different tenant
            strategy.TenantId = "tenant2";
            var dep3 = mtc.Resolve<IStubDependency1>();

            Assert.IsInstanceOf<StubDependency1Impl2>(dep1, "Tenant 1's dependency should be the override value.");
            Assert.IsInstanceOf<StubDependency1Impl2>(dep3, "Tenant 2's dependency should be the override value.");
            Assert.IsInstanceOf<StubDependency1Impl1>(appLevel, "The application's dependency should be the base value.");
            Assert.AreSame(dep1, dep2, "The two dependencies resolved for the first tenant should be the same.");
            Assert.AreNotSame(dep1, dep3, "The dependencies resolved across tenants should not be the same.");
            Assert.AreNotSame(dep1, appLevel, "The dependencies resolved at the tenant level should not be the same as the ones at the application level.");
        }
        public void Resolve_ResolvesTenantSpecificRegistrations()
        {
            var builder = new ContainerBuilder();
            builder.RegisterType<StubDependency1Impl1>().As<IStubDependency1>();
            var strategy = new StubTenantIdentificationStrategy()
            {
                TenantId = "tenant1"
            };
            var mtc = new MultitenantContainer(strategy, builder.Build());
            mtc.ConfigureTenant("tenant1", b => b.RegisterType<StubDependency1Impl2>().As<IStubDependency1>());

            Assert.IsInstanceOf<StubDependency1Impl2>(mtc.Resolve<IStubDependency1>(), "The wrong dependency type was resolved for the contextual tenant.");
        }
 public void GetTenantScope_SubsequentRetrievalsGetTheSameLifetimeScope()
 {
     var strategy = new StubTenantIdentificationStrategy()
     {
         TenantId = "tenant1"
     };
     var mtc = new MultitenantContainer(strategy, new ContainerBuilder().Build());
     mtc.ConfigureTenant("tenant1", b => b.RegisterType<StubDependency1Impl2>().As<IStubDependency1>());
     var scope1 = mtc.GetTenantScope("tenant1");
     var scope2 = mtc.GetTenantScope("tenant1");
     Assert.AreSame(scope1, scope2, "The tenant scope should not change across subsequent retrievals.");
 }
 public void GetTenantScope_GetsTenantScopeForConfiguredTenant()
 {
     var strategy = new StubTenantIdentificationStrategy()
     {
         TenantId = "tenant1"
     };
     var mtc = new MultitenantContainer(strategy, new ContainerBuilder().Build());
     mtc.ConfigureTenant("tenant1", b => b.RegisterType<StubDependency1Impl2>().As<IStubDependency1>());
     var scope = mtc.GetTenantScope("tenant1");
     Assert.IsNotNull(scope, "The tenant scope retrieved not be null.");
     Assert.AreNotSame(mtc.ApplicationContainer, scope, "The tenant scope should be a real scope, not just the application container.");
 }
        public void Dispose_DisposesTenantLifetimeScopes()
        {
            var appDependency = new StubDisposableDependency();
            var tenantDependency = new StubDisposableDependency();
            var builder = new ContainerBuilder();
            builder.RegisterInstance(appDependency).OwnedByLifetimeScope();
            var strategy = new StubTenantIdentificationStrategy()
            {
                TenantId = "tenant1"
            };
            var mtc = new MultitenantContainer(strategy, builder.Build());
            mtc.ConfigureTenant("tenant1", b => b.RegisterInstance(tenantDependency).OwnedByLifetimeScope());

            // Resolve the tenant dependency so it's added to the list of things to dispose.
            // If you don't do this, it won't be queued for disposal and the test fails.
            mtc.Resolve<StubDisposableDependency>();

            mtc.Dispose();
            Assert.IsTrue(appDependency.IsDisposed, "The application scope didn't run Dispose.");
            Assert.IsTrue(tenantDependency.IsDisposed, "The tenant scope didn't run Dispose.");
        }
 public void ConfigureTenant_RequiresConfiguration()
 {
     var builder = new ContainerBuilder();
     var strategy = new StubTenantIdentificationStrategy()
     {
         TenantId = "tenant1"
     };
     var mtc = new MultitenantContainer(strategy, builder.Build());
     Assert.Throws<ArgumentNullException>(() => mtc.ConfigureTenant("tenant1", null));
 }
        /// <summary>
        /// Handles the global application startup event.
        /// </summary>
        protected void Application_Start(object sender, EventArgs e)
        {
            // Create the tenant ID strategy. Required for multitenant integration.
            var tenantIdStrategy = new OperationContextTenantIdentificationStrategy();

            // Register application-level dependencies and service implementations.
            // Note that we are registering the services as the interface type
            // because the .svc files refer to the interfaces. We could potentially
            // use named service types as well.
            var builder = new ContainerBuilder();
            builder.RegisterType<BaseImplementation>().As<IMultitenantService>();
            builder.RegisterType<BaseImplementation>().As<IMetadataConsumer>();
            builder.RegisterType<BaseDependency>().As<IDependency>();

            // Adding the tenant ID strategy into the container so services
            // can return output about the current tenant.
            builder.RegisterInstance(tenantIdStrategy).As<ITenantIdentificationStrategy>();

            // Create the multitenant container based on the application
            // defaults - here's where the multitenant bits truly come into play.
            var mtc = new MultitenantContainer(tenantIdStrategy, builder.Build());

            // Notice we configure tenant IDs as strings below because the tenant
            // identification strategy retrieves string values from the message
            // headers.

            // Configure overrides for tenant 1 - dependencies, service implementations, etc.
            mtc.ConfigureTenant("1",
                b =>
                {
                    b.RegisterType<Tenant1Dependency>().As<IDependency>().InstancePerDependency();
                    b.RegisterType<Tenant1Implementation>().As<IMultitenantService>();
                    b.RegisterType<Tenant1Implementation>().As<IMetadataConsumer>();
                });

            // Configure overrides for tenant 2 - dependencies, service implementations, etc.
            mtc.ConfigureTenant("2",
                b =>
                {
                    b.RegisterType<Tenant2Dependency>().As<IDependency>().SingleInstance();
                    b.RegisterType<Tenant2Implementation>().As<IMultitenantService>();
                    b.RegisterType<Tenant2Implementation>().As<IMetadataConsumer>();
                });

            // Configure overrides for the default tenant. That means the default
            // tenant will have some different dependencies than other unconfigured
            // tenants.
            mtc.ConfigureTenant(null, b => b.RegisterType<DefaultTenantDependency>().As<IDependency>().SingleInstance());

            // Multitenant service hosting requires use of a different service implementation
            // data provider that will allow you to define a metadata buddy class that isn't
            // tenant-specific.
            AutofacHostFactory.ServiceImplementationDataProvider = new MultitenantServiceImplementationDataProvider();

            // Add a behavior to service hosts that get created so incoming messages
            // get inspected and the tenant ID can be parsed from message headers.
            // For multitenancy to work, you need to know for which tenant a
            // given request is being made. In this case, the incoming message headers
            // expect to see a string for the tenant ID; if your tenant ID coming
            // from clients is different, change that here.
            AutofacHostFactory.HostConfigurationAction =
                host =>
                    host.Opening += (s, args) =>
                        host.Description.Behaviors.Add(new TenantPropagationBehavior<string>(tenantIdStrategy));

            // Finally, set the host factory application container on the multitenant
            // WCF host to a multitenant container. This is similar to standard
            // Autofac WCF integration.
            AutofacHostFactory.Container = mtc;

            // Note that the .svc file for your service needs to use the
            // Autofac.Extras.Multitenant.Wcf.AutofacServiceHostFactory or
            // Autofac.Extras.Multitenant.Wcf.AutofacWebServiceHostFactory rather
            // than the standard Autofac host factories.
        }
Example #14
0
        private IDependencyResolver RegisterBuilderAutofacMultitenant(HttpConfiguration httpConfiguration)
        {
            // From http://docs.autofac.org/en/latest/advanced/multitenant.html#what-is-multitenancy

            var builder = new ContainerBuilder();
            var assembly = Assembly.GetExecutingAssembly();

            builder.RegisterModule(new SharedLibModule());
            //builder.RegisterType<HelloManager>().As<IHelloManager>().InstancePerRequest();

            // TODO: Make configurable
            builder.RegisterType<RequestParameterStrategy>().As<ITenantIdentificationStrategy>();

            // Standard API registration
            builder.RegisterWebApiFilterProvider(httpConfiguration);
            builder.RegisterApiControllers(assembly);

            var container = builder.Build();

            //if (container.IsRegistered<ITenantIdentificationStrategy>())

            var tenantStrategy = container.Resolve<ITenantIdentificationStrategy>();

            var mtc = new MultitenantContainer(tenantStrategy, container);

            //mtc.ConfigureTenant("A",
            //    b => b.RegisterType<HellloManagerA>().As<IHelloManager>()
            //        .InstancePerDependency());

            // Read assembly custom attribute
            var groupedAssemblies = LoadAssemblies().Select(ass => new
            {
                Assembly = ass,
                TenantAttribute = ass.GetCustomAttribute<TenantAttributeAttribute>()
            })
            .Where(o => o.TenantAttribute != null)
            .GroupBy(o => o.TenantAttribute.TenantId, o => o.Assembly);

            foreach (var group in groupedAssemblies)
            {
                // TODO: Log tenant being loaded at info level to give a way to debug issue.
                var grp = group;
                mtc.ConfigureTenant(grp.Key, cb =>
                {
                    cb.RegisterAssemblyModules(grp.ToArray());
                });
            }

            return new AutofacWebApiDependencyResolver(mtc);
        }
        private void AddTenant(MultitenantContainer mtc, string tenantId)
        {
            mtc.ConfigureTenant(tenantId,
                b =>
                {
                    var options = this.GetMyOptions(tenantId);

                    b.Register(c => new TestDbContext(options.ConnectionString))
                        .As<TestDbContext>()
                        .InstancePerDependency();

                    b.ConfigureOptions(options);
                });
        }