如何在运行时更新 Autofac 容器中的注册实例

How to update registered instances in Autofac container in runtime

我想在运行时用 ASP.NET MVC 应用程序中的新实例替换 Autofac 中现有的已注册实例。当我处理不同子类型的实例集合时,注册是关键的,尽管它似乎与我的问题无关。

应用程序启动时的初始注册

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

此外,在控制器方法中,我执行以下操作:处理旧实例、获取新实例、创建新构建器、重新注册现有组件并注册新实例,然后更新 Autofac 的 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);

下次我进入控制器方法时,在控制器构造函数中,旧实例被解析为 IIndex<InstanceType, IInstance[]>,而不是新实例。我究竟做错了什么?

您的代码不起作用,因为 componentContext 是当前范围的上下文,而不是全局范围。您可以查看此 .NetFiddle 以显示一些说明问题的代码:https://dotnetfiddle.net/GNvOL4

如果您真的想替换实例,使用提供程序会更简单:

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
    }
}