2

我想在運行時用ASP.NET MVC應用程序中的新實例替換Autofac中的現有註冊實例。在我處理不同子類型實例的集合時,註冊是關鍵的,儘管它似乎與我的問題無關。如何在運行時更新Autofac容器中的註冊實例

在應用程序啓動的初始登記

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

此外上,在一個控制器的方法i執行以下操作:處理舊的情況下,獲得新的,創建一個新的助洗劑,重新註冊的現有組件,並且還註冊新的情況下,然後更新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[]>,而不是新的。我究竟做錯了什麼?

+4

這感覺就像是一個壞主意,我。爲什麼不註冊一個可以容納和更改引用的對象?如果您在您的[組合根目錄](http://stackoverflow.com/questions/6277771/what-is-a-composition-root-in-the-context-of-dependency-injection)之外使用您的容器應用程序,那麼這是一種代碼味道。 –

+2

我完全同意@SamHolder:這樣做是一種可怕的做法。這是複雜的,容易出錯的,性能沉重,以及維護的噩夢。如果你解釋你試圖完成的是什麼(你爲什麼要替換註冊),我們可能會給出一些反饋意見並展示更好的方法。 – Steven

+0

@SamHolder和Steven:是的,我知道代碼味道很糟糕,儘管我很好奇爲什麼組件上下文更新不起作用。 實例是MassTransit服務總線,我需要保持對象引用能夠正確關閉它們並按需獲取診斷數據。在刷新行動後,巴士的配置可能會改變,因此我必須關閉舊巴士並開始新巴士。無論如何,最好的方法似乎是使用一種對象提供者來保持對可用服務總線的引用。 – jjjjj

回答

-1

您的代碼不起作用,因爲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 
    } 
} 
+0

我不敢在容器本身註冊一個容器的實例(否則我怎麼才能得到它的mvc控制器構造函數注入?),那太邪惡了。我認爲這個想法是使用ComponentContext對象作爲使用ReisterInstance()註冊的實例的默認生命週期範圍是Singleton。 對象提供者確實有道理,毫無疑問,我將重寫我的代碼以避免應用程序啓動後與容器相關的任何操作。 – jjjjj

+0

@jjjjj我很高興一些容器濫用,如果超出限制:) –

+0

@SamHolder沒有容器受到傷害,至少在現場環境:) – jjjjj