2015-07-15 11 views
8

Der Unity-Container löst automatisch jeden Typ auf, den er selbst herausfinden kann, ohne dass eine manuelle Registrierung erforderlich ist. Das ist in gewisser Hinsicht gut, aber das Problem, das ich habe, ist, dass es eine TransientLifetimeManager für diese Art von Auflösung verwendet, während ich fast immer eine ContainerControlledLifetimeManager will. Ich kann meine Typen natürlich immer noch manuell als Singletons registrieren, aber wenn ich es vergesse, anstatt eine unbehandelte Ausnahme beim Start zu bekommen, wird die App erfolgreich gestartet und alles scheint zu funktionieren. Aber es wird irgendwann Fehler geben, möglicherweise sehr subtil, schwer zu diagnostizieren, aufgrund der Tatsache, dass es mehrere Instanzen eines Typs gibt, der ein Singleton sein soll.Unity: Ändern Sie den Standardlebensdauer-Manager für implizite Registrierungen und/oder deaktivieren Sie sie.

Also meine Frage ist: Gibt es eine Möglichkeit, entweder einen anderen Standard Lifetime Manager oder deaktivieren Sie die Standard-Auto-Auflösung Verhalten vollständig und beschränken Sie den Container auf Typen, die ich registrieren (direkt oder nach meinen eigenen Konventionen)?

+0

Mögliche Duplikat von http://StackOverflow.com/Questions/29828410/default-the-Lifetimemanager-to-the-Singleton-Manager-ContainerControlledLifetim – gastonmancini

+0

Great; das scheint mir eine Möglichkeit zu geben, den Standard 'LifetimeManager' einzustellen. Ich würde immer noch gerne wissen, ob es eine Möglichkeit gibt, die automatische/implizite Registrierung zu deaktivieren. – dlf

Antwort

5

Gibt es eine Weise, die ich entweder eine andere Standard Lebensdauer Manager

Ja, können Sie einen Container-Erweiterung verwenden, die eine andere Lebensdauer Manager angeben verwenden. Ein Beispiel finden Sie unter Request for configurable default lifetimemanager.

oder das Standard-Auto-Auflösung Verhalten vollständig deaktivieren und begrenzen die Container-Typen I registriere ich

Ja, eine Container-Erweiterung dies auch tun können.

Zuerst während der expliziten Registrierung den BuildKey der Registrierung aufzeichnen. Überprüfen Sie dann vor dem Erstellen des Objekts, ob der BuildKey explizit registriert wurde.

public class RegistrationTrackingExtension : UnityContainerExtension 
{ 
    private ConcurrentDictionary<NamedTypeBuildKey, bool> registrations = 
     new ConcurrentDictionary<NamedTypeBuildKey, bool>(); 

    protected override void Initialize() 
    { 
     base.Context.Registering += Context_Registering; 
     base.Context.Strategies.Add(
      new ValidateRegistrationStrategy(this.registrations), UnityBuildStage.PreCreation); 
    } 

    private void Context_Registering(object sender, RegisterEventArgs e) 
    { 
     var buildKey = new NamedTypeBuildKey(e.TypeTo, e.Name); 
     this.registrations.AddOrUpdate(buildKey, true, (key, oldValue) => true); 
    } 

    public class ValidateRegistrationStrategy : BuilderStrategy 
    { 
     private ConcurrentDictionary<NamedTypeBuildKey, bool> registrations; 

     public ValidateRegistrationStrategy(ConcurrentDictionary<NamedTypeBuildKey, bool> registrations) 
     { 
      this.registrations = registrations; 
     } 

     public override void PreBuildUp(IBuilderContext context) 
     { 
      if (!this.registrations.ContainsKey(context.BuildKey)) 
      { 
       Exception e = new Exception("Type was not explicitly registered in the container."); 
       throw new ResolutionFailedException(context.BuildKey.Type, context.BuildKey.Name, e, context); 
      } 
     } 
    } 
} 

Dann fügen Sie die Erweiterung hinzu, registrieren Sie einige Klassen und beheben Sie. Wenn die Klasse nicht explizit registriert wurde, wird eine Ausnahme ausgelöst.

IUnityContainer container = new UnityContainer(); 
// Add container extension 
container.AddNewExtension<RegistrationTrackingExtension>(); 

// Register types 
container.RegisterType<MyClass>(); 
container.RegisterType<IMyClass, MyClass>(); 
container.RegisterType<IMyClass, MyClass>("A"); 

// These succeed because they were explicitly registered 
container.Resolve<IMyClass>(); 
container.Resolve<IMyClass>("A"); 
container.Resolve<MyClass>(); 

// MyClass2 was not registered so this will throw an exception 
container.Resolve<MyClass2>(); 
+1

Wunderbar; Beide Lösungen funktionieren perfekt. Und 'RegistrationTrackingExtension' hat bereits einige Fehler in der Anwendung entdeckt! – dlf

1

Ich versuchte die DefaultLifetimeManagerExtension, aber irgendwie hat es nicht funktioniert. (Vielleicht hat sich die Einheit geändert?). Wenn Sie keine Erweiterung verwenden möchten, können Sie auch die Funktion RegsiterByConvention verwenden. Dadurch werden alle Klassen mit dem „DisposingTransientLifetimeManager“, die ich wählte man als Standard zu verwenden, registrieren

container.RegisterTypes(AllClasses.FromLoadedAssemblies(), WithMappings.None, WithName.Default, x => new DisposingTransientLifetimeManager()); 

. Beachten Sie, dass Sie dies zu Beginn Ihrer Registrierung tun sollten, da alle Anmeldungen frühere Anmeldungen desselben Typs und Namens überschreiben.