Giter Club home page Giter Club logo

autofac.multitenant's Introduction

Autofac character Autofac logo

Autofac is an IoC container for Microsoft .NET. It manages the dependencies between classes so that applications stay easy to change as they grow in size and complexity. This is achieved by treating regular .NET classes as components.

Build status codecov NuGet

Autofac on Stack Overflow Join the chat at https://gitter.im/autofac/autofac

Get Packages

You can get Autofac by grabbing the latest NuGet package. There are several application integration and extended functionality packages to choose from. If you're feeling adventurous, continuous integration builds are on MyGet.

Release notes are available on GitHub.

Get Help

Need help with Autofac? We have a documentation site as well as API documentation. We're ready to answer your questions on Stack Overflow or check out the discussion forum.

Get Started

Our Getting Started tutorial walks you through integrating Autofac with a simple application and gives you some starting points for learning more.

Super-duper quick start:

Register components with a ContainerBuilder and then build the component container.

var builder = new ContainerBuilder();

builder.Register(c => new TaskController(c.Resolve<ITaskRepository>()));
builder.RegisterType<TaskController>();
builder.RegisterInstance(new TaskController());
builder.RegisterAssemblyTypes(controllerAssembly);

var container = builder.Build();

Resolve services from a lifetime scope - either the container or a nested scope:

var taskController = container.Resolve<TaskController>();

There is a growing number of application integration libraries that make using Autofac with your application a snap. Support for several popular frameworks is also available through the "Extras" packages.

Intrigued? Check out our Getting Started walkthrough!

Project

Autofac is licensed under the MIT license, so you can comfortably use it in commercial applications (we still love contributions though).

File issues in the repo with the associated feature/code.

Sponsors

Autofac is supported by AWS. Thanks for your contribution!

Contributing / Pull Requests

Refer to the Contributor Guide for setting up and building Autofac source.

You can also open this repository right now in VS Code.

autofac.multitenant's People

Contributors

alexmg avatar alistairjevans avatar alsami avatar drusellers avatar gtrubach avatar marcrocny avatar me-viper avatar norekz avatar shiftkey avatar tillig avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

autofac.multitenant's Issues

Invalid interaction between DisposeAsync and Dispose in MultitenantContainer

  • Assembly version information for all project dependencies (packages.config, project.json)
    Current develop branch, commit ed664b9

  • The stack trace and message of any exception(s) encountered.

System.ObjectDisposedException : Cannot access a disposed object.
   at System.Threading.ReaderWriterLockSlim.TryEnterWriteLockCore(TimeoutTracker timeout)
   at System.Threading.ReaderWriterLockSlim.EnterWriteLock()
   at Autofac.Multitenant.MultitenantContainer.Dispose(Boolean disposing)
   at Autofac.Util.Disposable.DisposeAsync(Boolean disposing)
   at Autofac.Multitenant.MultitenantContainer.<>n__0(Boolean disposing)
   at Autofac.Multitenant.MultitenantContainer.DisposeAsync(Boolean disposing) 
  • If possible, a reproduction of the issue (ideally in a unit test form).
        [Fact]
        public async Task DisposeTest()
        {
            var strategy = new StubTenantIdentificationStrategy()
            {
                TenantId = "tenant1",
            };
            var mtc = new MultitenantContainer(strategy, new ContainerBuilder().Build());
            mtc.ConfigureTenant("tenant1", b => b.RegisterType<StubDependency1Impl1>().As<IStubDependency1>());

            await mtc.DisposeAsync();
        }

MultitenantContainer.AsyncDispose implementation does await base.DisposeAsync(disposing); call at the end. Disposable.DisposeAsync calls virtual Dispose() which causes call into MultitenantContainer.Dispose(). At the end code tries to access _readWriteLock that have been disposed already.

vNext

The MultiTenant nuget package is not working with vNext projects due to issues with using HashTables, HttpContext and the ServiceProvider from the Autofac Dependency Injection package.

I was able to get it to work by changing a few things.

  1. Convert to vnext project.
  2. Add the Microsoft.AspNet.Http and Microsoft.AspNet.Http.Abstrations dependencies
  3. Modify RequestParameterTenantIdentificationStrategy to use IHttpContextAccessor for non .NET45 targeted projects.
  4. Changed MultitenantContainer to use ConcurrentDictionary<object, object> instead of HashTable

I then had to build my own service provider, copied from Autofac.Framework.DependencyInjection. The reason I needed to do that is the need to create the new provider with the multi tenant context.

In startup.cs, I was now able to do this and it worked correctly:

        var identificationStrategy = new MultiTenantIdentificationStrategy();
        var containerBuilder = new ContainerBuilder();
        containerBuilder.Populate(services);
        containerBuilder.RegisterType<TestClassDefault>().As<ITestClass>().InstancePerLifetimeScope(); //set a default

        var container = containerBuilder.Build();
        var multiTenantContainer = new Autofac.Extras.Multitenant.MultitenantContainer(identificationStrategy, container);

        //setup tenants
        multiTenantContainer.ConfigureTenant("1",
            builder =>
            {
                builder.RegisterType<TestClass1>().As<ITestClass>().InstancePerLifetimeScope();
            });

        multiTenantContainer.ConfigureTenant("2",
            builder =>
            {
                builder.RegisterType<TestClass2>().As<ITestClass>().InstancePerLifetimeScope();
            });

        //update types
        containerBuilder = new ContainerBuilder();
        containerBuilder.RegisterType<AutoServiceProvider>().As<IServiceProvider>().SingleInstance(); //set the service provider to the correct service provider
        containerBuilder.RegisterInstance(multiTenantContainer).As<IComponentContext>().SingleInstance(); //set the component context to the multitenant container
        containerBuilder.Update(multiTenantContainer); //update the container with the new types

        return multiTenantContainer.Resolve<IServiceProvider>();

I have code done, I could do a pull request for it.

Add virtual keyword to MultitenantContainer.ConfigureTenant

Problem Statement

I am covering the project with unit tests. I have problems in covering of code that uses MultitenantContainer.ConfigureTenant(object tenantId, Action<ContainerBuilder> configuration).

I want to use Setup and Verify features in order to test how my code is dealing with possible exceptions.

Desired Solution

public void ConfigureTenant(object tenantId, Action<ContainerBuilder> configuration)
should become
public virtual void ConfigureTenant(object tenantId, Action<ContainerBuilder> configuration)

Alternatives You've Considered

Or add some support of such behavior to Automock

Reconfiguration of tenants in MultitenantContainer

Hi!

I have one question about reconfiguration tenants in MultitenantContainer, Now we cannot do it and I see the following lines in source code:

// The check and [potential] scope creation are locked here to
// ensure atomicity. We don't want to check and then have another
// thread create the lifetime scope behind our backs.
if (this._tenantLifetimeScopes.ContainsKey(tenantId))
{
    throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, Properties.Resources.MultitenantContainer_TenantAlreadyConfigured, tenantId));
}

But I think it will be great if we will can create new lifetime scope for tenant with new configuration. And does GC dispose lifetime scope when we will begin new scope for tenant?

So maybe we can do something following:

  1. Allow to create new lifetime scope for configured tenants with new configuration?

  2. Remove previous lifetime scope for reconfigured tenant?

There was small discussion here.

Autofac Multitenancy does not add tenant configuration when using new JSON config

The Multitenant module does not apply the configuration to the builder anymore.

If you have a the (nonmultitenant) core container build up and apply the configuration
to the new MultitentantContainer the new container should add its additional configuration to the already build configuration (e.g. add new additonal T specific for customer, when resolving IEnumerable)

(this is the multitenant part of my bootstrapping)

// Create the Container for IoC
this.container = builder.Build();

// Todo: Use same principle as used for tenants also for different application types/profiles
ITenantIdentificationStrategy tenantIdentificationStrategy;

// check if whe should go single- or multitenancy
if (this.container.TryResolve(out tenantIdentificationStrategy))
{
    var multitenantContainer =
        new MultitenantContainer(
            tenantIdentificationStrategy,
            this.container);

    var tenantsConfigdirectory = new DirectoryInfo(configDirectory.FullName + Path.DirectorySeparatorChar + this.configForTenants);

    RegisterMultitenantModules(multitenantContainer, tenantsConfigdirectory)
        .OnSuccess(() =>
                {
                    Log.Info(
                        logm => logm("Using multi-tenant container."));
                    // use multitenant container
                    this.container = multitenantContainer;
                });
}
else
{
    Log.Info(logm => logm("Using single-tenant container."));
}

The registration of Multitenant parts is fairly simple:

foreach (var tenant in directory.GetDirectories())
{
    try
    {
        multitenantContainer.ConfigureTenant(
            tenant.Name,
            builder =>
            {
                var tenantDirectory = new DirectoryInfo(directory.FullName + Path.DirectorySeparatorChar + tenant);

                var config = new ConfigurationBuilder();

                try
                {
                    foreach (var file in tenantDirectory.GetFiles("*.json"))
                    {
                        config.AddJsonFile(file.FullName);
                    }

                    foreach (var file in tenantDirectory.GetFiles("*.xml"))
                    {
                        config.AddXmlFile(file.FullName);
                    }
                }
                catch (DirectoryNotFoundException exception)
                {
                    Log.Warn(logm => logm("Directory for tenant '{0}' not found.", tenant), exception);
                }

                // Register this module for json/xml configuration as last module to allow (emergency) overrides.
                builder.RegisterModule(new ConfigurationModule(config.Build()));
            });

        return Result.Ok();
    }
    catch (ConfigurationErrorsException exception)
    {
        const string Message = "Configuration errors during trying to read the tenant configuration for {0}.";

        Log.Error(logm => logm(Message, tenant), exception);

        return Result.Fail(string.Format(Message, tenant));
    }
}

The debugger steps through the process and all seems to be working (reading tenant config etc.) but the new config is not applied.

InstancePerTenant dependency and tenants reconfiguration

Hello,

This is not an issue but a question. We have a really cool feature such as tenant reconfiguration. But I ran into a problem when using InstancePerTenant dependency with it.

The problem is the following: while tenants dictionary is reconfigured there is a resolve operation in another thread. And when something inner in Autofac receive a lifetime scope than this scope can be disposed in ReconfigureTenant method (since reconfiguration is occured) in another thread. And then DependencyResolutionException occured because scope is disposed but it tries to add disposable InstancePerTenant dependency to stack of disposables.

And my question is: how can I stay safe in this situation. Thanks for any advise.

Allow tenant dependencies to be explicitly resolved

From @Togusa09 on July 22, 2015 6:24

It is not possible to resolve objects for a specific tenant from an injected scope. I believe this would normally be possible when you have access to the MultitenantContainer, but not when you're in MVC and reliant on things being injected to controllers.

public ViewResult HomeController(ITenantContext context)
{
    using(var scope = context.GetTenantScope(1))
    {
        var service = scope.Resolve<IService>();
     }
}

Copied from original issue: autofac/Autofac#662

Getting all registered tenants Ids and clearing registrations

Now we have a feature for reconfiguring tenants. It's a really cool feature!

But for full tenants control I suggest to add two methods:

  1. Getting all configured tenant Ids. This will help with not storing Ids in application memory, because we already have it in Multitenant dictionary.
  2. Clearing all registrations. We can now remove them one-by-one. But in some cases it's necessary to remove all.

What do you think about it?

Use Slim reader/writer locks over tenant-scope Dictionary?

Asking before starting a PR, because I know there has been some debate about thread-safety/ in the past: would it be possible/recommended to use ReaderWriterLockSlim for synchronizing access to _tenantLifetimeScopes, the underlying tenant dictionary?

ITenantIdentificationStrategy.TryIdentifyTenant nullable annotation incomplete

Describe the Bug

Nullable annotation on ITenantIdentificationStrategy.TryIdentifyTenant is incorrect. It is missing an attribute [NotNullWhen(true)] to follow common try-get-* patterns seen commonly in .NET.

Steps to Reproduce

public void DoSomething(ITenantIdentificationStrategy strategy)
{
    if (strategy.TryIdentifyTenant(out var id))
    {
        Foo(id);
    }
}
public void Foo(object input) { }

Expected Behavior

No compiler warning.

Actual Behavior

CS8604: Possible null reference argument for parameter 'input'

Additional Info

https://github.com/dotnet/csharplang/blob/main/meetings/2019/LDM-2019-05-15.md#conditional-postconditions

Mscorelib offers some guidelines intended to be specific to that library but that turn out to be in general good to follow: The api guidelines for that repo say https://github.com/dotnet/runtime/blob/e12e2fa6cbdd1f4b0c8ad1b1e2d960a480c21703/docs/coding-guidelines/api-guidelines/nullability.md?plain=1#L88 and from this the following bullet seems to apply:

  • DO annotate non-generic out reference type arguments on Try methods as being nullable and with [NotNullWhen(true)] (e.g. TryCreate([NotNullWhen(true)] out Semaphore? semaphore)). For non-generic arguments, the argument should be nullable because a failed call will generally store null into the argument, and it should be [NotNullWhen(true)] because a successful call will store non-null.

Error after upgrade Autofac to v8.0.0

Describe the Bug

When I upgraded Autofac to v8.0.0 and Autofac.Extensions.DependencyInjection to v9.0.0 I started to get an exception 'Autofac.Multitenant.MultitenantContainer' from assembly 'Autofac.Multitenant, Version=7.0.1.0, Culture=neutral, PublicKeyToken=17863af14b0044da' does not have an implementation.'.

Steps to Reproduce

Upgrade Autofac to v8.0.0 and Autofac.Extensions.DependencyInjection to v9.0.0 in project that use Autofac.Multitenant v7.0.1.0and run the app.

Expected Behavior

Application works without the error.

Dependency Versions

Autofac to v8.0.0 and Autofac.Extensions.DependencyInjection to v9.0.0

Integration not compatible with Autofac 5.0 Release Candidate

The Autofac.Multitenant integration has build errors when built against the latest Autofac Release candidate in MyGet, specifically, the MultitenantContainer does not implement the updated ResolveRequest method.

No NuSpec to update here, but we'll need to update the reference in the csproj file once Autofac 5 goes out.

Set the active tenant on a resolved child scope?

Is there a way to set the active tenant on a child scope? I assumed it would have a global affect but it does not after the child scope (ILifetimeScope) has been resolved.

Dependencies

<package id="Autofac" version="4.9.2" targetFramework="net471" />
<package id="Autofac.Multitenant" version="4.2.0" targetFramework="net471" />

Reproduction

Reproduction written using a .net framework console application and the above listed dependencies.

using Autofac;
using Autofac.Multitenant;

namespace ConsoleAutoFacTenants
{
    class Program
    {
        static void Main(string[] args)
        {
            var builder = new ContainerBuilder();
            builder.RegisterType<GeneralReader>().As<IReader>().InstancePerDependency();
            var appContainer = builder.Build();

            var tenantIdentifier = new AutomationTenantStrategy();
            var mtc = new MultitenantContainer(tenantIdentifier, appContainer);

            mtc.ConfigureTenant("1", b => b.RegisterType<SpecificReader>().As<IReader>().InstancePerDependency());

            // expected
            var reader1 = mtc.Resolve<IReader>();
            System.Diagnostics.Debug.Assert(reader1.Name == "General");

            // unexpected result in debug.assert, assumed that reader2 would resolve type SpecificReader
            var childScoped = mtc.Resolve<ILifetimeScope>();
            tenantIdentifier.TenantId = "1";
            var reader2 = childScoped.Resolve<IReader>();
            System.Diagnostics.Debug.Assert(reader2.Name == "Specific");
        }
    }
    internal sealed class AutomationTenantStrategy : ITenantIdentificationStrategy
    {
        public object TenantId { get; set; }
        public bool TryIdentifyTenant(out object tenantId)
        {
            var activeTenant = this.TenantId;
            if (TenantId == null)
            {
                tenantId = null;
                return false;
            }
            tenantId = activeTenant;
            return true;
        }
    }
    public interface IReader
    {
        string Name { get; }
    }
    public sealed class GeneralReader : IReader
    {
        public string Name => "General";
    }
    public sealed class SpecificReader : IReader
    {
        public string Name => "Specific";
    }
}

Upgrade to VS 2017

Tried this myself in preparation for other updates, but having a bear of a time (for some reason introduces weird issues with FxCop and StyleCop) and I know I'm missing something in the build scripting.

Autofac 7.0 breaks multitenant support

After upgrade Autofac to v7.0.0 in project that uses Autofac.Multitenant v6.0.0 errors occur

System.TypeLoadException : Method 'BeginLoadContextLifetimeScope' in type 'Autofac.Multitenant.MultitenantContainer' from assembly 'Autofac.Multitenant, Version=6.0.0.0, Culture=neutral, PublicKeyToken=17863af14b0044da' does not have an implementation.

It looks Autofac.Multitenant 7.0.0 supporting Autofac 7.0.0 needs to be released.

Upgrade Autofac Multitenant with Asp.Net Core 2.2 to Asp.Net 5

I have an Asp.Net Core 2.2 application that is currently using following dependencies:
Autofac: Autofac.AspNetCore.Multitenant version 1.1.0
Autofac.AspNetCore.Extensions version :1.0.2
I want to upgrade the application from from Asp.Net Core 2.2 to Asp.Net 5. Because of the new Generic IHostBuilder and using AutofacServiceProviderFactory, I am kind of lost as to how to go about building tenants in program.cs and add/remove at runtime.
in .Net Core 2.2 I am doing it as follows:

#Program.cs
 var webHost = CreateTenantWebHostBuilder(args)
                   .UseAutofacMultiTenant()
                   .UseStartup<Startup>()
                    .Build();
                    using (var scope = webHost.Services.CreateScope())
                    {
                        try
                        {
                            var applicationLifetime = scope.ServiceProvider
                                                           .GetRequiredService<IApplicationLifetime>();
                            var tenantStore = scope.ServiceProvider
                                                   .GetRequiredService<ICustomTenantsStore>();
                            await tenantStore.InitializeTenantsAsync(applicationLifetime
                                .ApplicationStopping);
                        }
                        catch (Exception ex)
                        {
                           
                        }
                    }
await webHost.RunAsync(cancelTokenSource.Token);

How can go about initialisation with new .UseServiceProviderFactory(new AutofacServiceProviderFactory())?
Thanks

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.