如何在运行时更新 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
}
}
我想在运行时用 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
}
}