You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Simple Injector allows decorators to be constructed in three different ways:
A decorator can accept the decoratee as constructor argument
A decorator can accept a decoratee factory as constructor argument
A decorator can accept a scoped decoratee factory as constructor argument
Simple Injector will generate the Func<T> and Func<Scope, T> factory methods and injects them into the constructor of the decorator. A Func<Scope, T> delegate, however, can only function correctly when it is supplied with a Scope that:
The Container instance is the same instance that has created the object graph the decorator consists of
If the above conditions are not met, weird things happen:
A NullReferenceException is thrown when a container-less Scope instance is provided.
A confusing "X is registered as 'Scoped' lifestyle, but the instance is requested outside the context of an active (Scoped) scope" exception is thrown when the Scope's container is a different one.
The following tests demonstrate the problem:
publicclassScopedPluginProxy:IPlugin{publicreadonlyFunc<Scope,IPlugin>Factory;publicScopedPluginProxy(Func<Scope,IPlugin>factory)=>this.Factory =factory;}[TestMethod]publicvoidTest1(){// Arrangevarcontainer=new Container();
container.Options.DefaultScopedLifestyle = ScopedLifestyle.Flowing;
container.Register<IPlugin,PluginImpl>(Lifestyle.Scoped);
container.RegisterDecorator<IPlugin,ScopedPluginProxy>(Lifestyle.Singleton);varproxy=(ScopedPluginProxy)container.GetInstance<IPlugin>();Func<Scope,IPlugin>factory= proxy.Factory;varcontainerlessScope=new Scope();// ActActionaction=()=> factory(containerlessScope);// Assert
AssertThat.ThrowsWithExceptionMessageContains<InvalidOperationException>("For scoped decoratee factories to function, they have to be supplied with a Scope "+"instance that references the Container for which the object graph has been built. "+"But the Scope instance, provided to this Func<Scope, IPlugin> delegate does not "+"belong to any container. Please ensure the supplied Scope instance is created "+"using the constructor overload that accepts a Container instance.",
action);}[TestMethod]publicvoidTest2(){// Arrangevarcontainer=new Container();
container.Options.DefaultScopedLifestyle = ScopedLifestyle.Flowing;
container.Register<IPlugin,PluginImpl>(Lifestyle.Scoped);
container.RegisterDecorator<IPlugin,ScopedPluginProxy>(Lifestyle.Singleton);varproxy=(ScopedPluginProxy)container.GetInstance<IPlugin>();Func<Scope,IPlugin>factory= proxy.Factory;varscopeFromAnotherContainer=new Scope(new Container());// ActActionaction=()=> factory(scopeFromAnotherContainer);// Assert
AssertThat.ThrowsWithExceptionMessageContains<InvalidOperationException>("For scoped decoratee factories to function, they have to be supplied with a Scope "+"instance that references the Container for which the object graph has been built. "+"But the Scope instance, provided to this Func<Scope, IPlugin> delegate references "+"a different Container instance.",
action);}[TestMethod]publicvoidTest3(){// Arrangevarcontainer=new Container();
container.Options.DefaultScopedLifestyle = ScopedLifestyle.Flowing;
container.Register<IPlugin,PluginImpl>(Lifestyle.Scoped);
container.RegisterDecorator<IPlugin,ScopedPluginProxy>(Lifestyle.Singleton);varproxy=(ScopedPluginProxy)container.GetInstance<IPlugin>();Func<Scope,IPlugin>factory= proxy.Factory;varvalidScope=new Scope(container);// Actvarplugin1= factory(validScope);varplugin2= factory(validScope);varplugin3= factory(new Scope(container));// Assert
AssertThat.IsInstanceOfType(typeof(PluginImpl), plugin1);
Assert.AreSame(plugin1, plugin2,"Instance is not scoped but Transient.");
Assert.AreNotSame(plugin2, plugin3,"Instance is not scoped but Singleton.");}
The text was updated successfully, but these errors were encountered:
Simple Injector allows decorators to be constructed in three different ways:
Simple Injector will generate the
Func<T>
andFunc<Scope, T>
factory methods and injects them into the constructor of the decorator. AFunc<Scope, T>
delegate, however, can only function correctly when it is supplied with aScope
that:Container
instance (currently, aScope
instance can be constructed withoutContainer
, Mark Scope's default constructor obsolete #701 fixes that)Container
instance is the same instance that has created the object graph the decorator consists ofIf the above conditions are not met, weird things happen:
NullReferenceException
is thrown when a container-lessScope
instance is provided.Scope
's container is a different one.The following tests demonstrate the problem:
The text was updated successfully, but these errors were encountered: