LightInject v6.0.0 Release Notes
Release Date: 2019-08-28 // over 4 years ago-
๐ Change Log
๐ v6.0.0 (8/28/2019)
๐ Full Changelog
๐ Merged Pull Requests
โก๏ธ Updated an xmldoc typo (7/12/2019) #491 (Hammerstad)
โก๏ธ Updated a typo in the xmldoc for ContainerOptions.LogFactory
โก๏ธ Update version (8/2/2019) #493 (danielmarbach)๐ Given https://github.com/seesharper/LightInject/blob/master/src/LightInject/LightInject.csproj#L5 should the version also be reflected in the source file?
โ Added Scope Performance tests (8/11/2019) #498 (seesharper)๐ Flow the scope when possible (8/28/2019) #500 (seesharper)
๐ This PR adds support for "flowing" the scope whenever possible.
This means that we pass the scope that requested a service throughout the object graph.
Example
container.RegisterScoped\<IFoo\>(factory =\> new Foo());
The
factory
passed into the factory delegate is anIServiceFactory
and this used to always be theServiceContainer
implementing theIServiceFactory
interface. What is changed is that we now pass in theScope
which also implementsIServiceFactory
.When LightInject was born, there was always this notion of a current scope. An ambient context that can be used to access the current scope.
๐ It supports scenarios likeusing (container.BeginScope()) { var foo = container.GetInstance\<IFoo\>(); }
The way this works is that when
IFoo
is requested we ask for the current scope and use that scope for resolving the instance.๐ Then we introduced support for getting a service directly from a scope.
using (var outerScope = container.BeginScope()) { using(var innerScope = container.BeginScope()) { var outerFoo = outerScope.GetInstance\<IFoo\>(); var innerFoo = innerScope.GetInstance\<IFoo\>(); } }
โช The way that this used to work was that we swapped the current scope with the scope from which the service was requested. After we resolved the service we restored the current scope to the previous current scope.
This was problematic in a number of ways.
- Swapping the current scope performs really bad as most of the time the current scope is backed by an
AsyncLocal<T>
. - Deferred resolution such as
Func<T>
andLazy<T>
that always relied on the current scope could end up using the "wrong" scope if someone or something started a new scope usingcontainer.BeginScope
which in turn sets the current scope to new newly created scope. - Multiple parallel scopes was almost impossible to get right because of the assumption that we always have the correct current scope.
Instead of always relying on the current scope, we pass the scope throughout the code that is generated to resolve an instance. One important aspect of this is that we do this with as little breakage as possible. That means that of the service is directly requested from the scope, we pass that scope without messing with the current scope. If we request a service from the container, the current scope will be used as before.
๐ It should be noted that requesting service directly from the scope is the preferred way with regards to performance and correctness. We will not remove support for the ambient scope, but we might emit a warning log message in the future.
Closed Issues
- ๐ Decorator patter with a lifetime that doesn't match the default (5/23/2019) #478 (bounav)
- ASP.NET Core SetCompatibilityVersion(CompatibilityVersion.Version_2_2) Breaks LightInject (5/23/2019) #482 (nystrup)
- ๐ AspNetCore 2.2 AspNetCoreHostingModel InProcess not working (5/22/2019) #488 (valeriob)
- ๐ Issue w/ Lazy<> and Scoped unit tests. (8/9/2019) #497 (danyhoron)
- Swapping the current scope performs really bad as most of the time the current scope is backed by an