简体   繁体   中英

How to update registered instances in Autofac container in runtime

I want to replace existing registered instances in Autofac with new ones in ASP.NET MVC application in runtime. Registrations are keyed as I work with collections of instances of different subtype, though it seems to be irrelevant to my issue.

Initial registration on application startup

foreach (var instance in instances)
{
    builder.RegisterInstance(instance).Keyed<IInstance>(InstanceType.A); 
}
IContainer container = builder.Build();    
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

Further on, in a controller method I do the following: dispose old instances, obtain new ones, create a new builder, reregister existing components and also register new instances, then update Autofac's ComponentContext

//...dispose old instances, obtain new instances

var builder = new ContainerBuilder();
foreach (var c in _componentContext.ComponentRegistry.Registrations)
{
    builder.RegisterComponent(c);
}
foreach (var instance in newInstances)
{
    builder.RegisterInstance(instance).Keyed<IInstance>(InstanceType.A);
}
builder.Update(_componentContext.ComponentRegistry);

Next time I enter the controller method, in controller constructor the old instances are resolved as IIndex<InstanceType, IInstance[]> , not the new ones. What am I doing wrong?

Your code doesn't work because componentContext is the context for the current scope and not the global scope. You can look at this .NetFiddle to show some code illustrating the problem : https://dotnetfiddle.net/GNvOL4

If you really want to replace instance it will be simpler to use a provider :

class Program
{
    static void Main(string[] args)
    {
        ContainerBuilder builder = new ContainerBuilder();
        builder.RegisterInstance(new FooProvider(new Foo("a")))
               .As<FooProvider>();
        builder.Register(c => c.Resolve<FooProvider>().Value)
               .ExternallyOwned()
               .Keyed<Foo>(1);

        IContainer container = builder.Build();
        using (ILifetimeScope scope = container.BeginLifetimeScope())
        {
            Do(scope);
        }

        using (ILifetimeScope scope = container.BeginLifetimeScope())
        {
            IComponentContext context = scope.Resolve<IComponentContext>();
            container.Resolve<FooProvider>().Value = new Foo("b");
            Do(scope);
        }

        using (ILifetimeScope scope = container.BeginLifetimeScope())
        {
            Do(scope);
        }
    }

    static void Do(ILifetimeScope scope)
    {
        IIndex<Int32, Foo> index = scope.Resolve<IIndex<Int32, Foo>>();
        Foo foo = index[1];
        Console.WriteLine(foo.Value);
    }
}

public class FooProvider 
{
    public FooProvider(Foo value)
    {
        this._value = value;
    }

    private volatile Foo _value;
    public Foo Value
    {
        get
        {
            return this._value;
        }
    }

    public void ChangeValue(Foo value)
    {
        if(value == null)
        {
            throw new ArgumentNullException("value");
        }
        if(value == this._value)
        {
            return; 
        }

        Foo oldValue = this._value; 
        this._value = value;
        oldValue.Dispose();
    }

    public void Dispose() 
    {
        this._value.Dispose(); 
    }
}
public class Foo : IDisposable
{
    public Foo(String value)
    {
        this._value = value;
    }

    private readonly String _value;
    public String Value
    {
        get
        {
            return this._value;
        }
    }

    public void Dispose()
    {
        // do things
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM