All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
v5.14.1 - 2024-04-08
- #163: Last-write win problem when hash collision happens.
v5.14.0 - 2023-12-15
WithRequiredMemberInjection()
registration and container configuration option to control the auto injection ofrequired
members.
v5.13.0 - 2023-11-18
- .NET 8.0 target.
- #134 Concept of Auto lifetime:
- It aligns to the lifetime of the resolved service's dependencies. When the underlying service has a dependency with a higher lifespan, this lifetime will inherit that lifespan up to a given boundary.
- Auto injection of
required
members. - MS.DI compatibility features for supporting keyed services:
DependencyName
attribute. When a parameter is marked with this attribute, the container will pass the given dependency's name to it.WithUniversalName()
container configuration method. It sets the universal name which is a special name that allows named resolution work for any given name.WithAdditionalDependencyNameAttribute()
container configuration method. It adds an attribute type that is considered a dependency name indicator just like theDependencyName
attribute.WithAdditionalDependencyAttribute()
container configuration method. It adds an attribute type that is considered a dependency indicator just like theDependency
attribute.
v5.12.2 - 2023-09-05
- There was an issue where using decorators with instance registrations resulted in resolution failure.
v5.12.1 - 2023-09-05
- #144: There was a case where closed generic decorators were not taken into account during service resolution.
- #143: Child scopes attached to their parents were not removed from disposal tracking when they were disposed individually.
- #141: There was a case where wrong decorators were selected during an
IEnumerable<T>
resolution call.
v5.11.1 - 2023-08-16
- #142: Upon disposing child containers, their parents still held a strong reference to them.
v5.11.0 - 2023-06-21
- Moved several functions of
IDependencyResolver
to extension methods.
v5.10.2 - 2023-06-13
- Access to the actual
TypeInformation
as a factory delegate input parameter. TheTypeInformation
holds every reflected context information about the currently resolving type. This can be useful when the resolution is, e.g., in an open generic context, and we want to know which closed generic variant is requested.container.Register(typeof(IService<>), options => options.WithFactory<TypeInformation>(typeInfo => /* typeInfo.Type holds the currently resolving closed generic type */));
v5.10.1 - 2023-06-09
ParentDependency
flag forResolutionBehavior
. It indicates that parent containers (including indirect all ancestors) can only provide dependencies for services that are already selected for resolution.
- During factory resolution, the type map check failed for registrations like:
.Register<IService>(c => c.WithFactory(/* ... */).AsServiceAlso<IAnother>())
. Now, the container gets the implementation type from the generic context where it's possible.
v5.10.0 - 2023-06-04
- Each
Resolve()
method now accepts aResolutionBehavior
flag parameter. It determines which level of the container hierarchy can take part in the service resolution. Possible values:Parent
: Indicates that parent containers (including indirect all ancestors) can participate in the resolution request's service selection.Current
: Indicates that the current container (which initiated the resolution request) can participate in the service selection.Default
: The default behavior, it's used when the parameter is not specified. Its value isParent | Current
, so the parents and the current (which initiated the resolution request) container can participate in the resolution request's service selection.
CreateChildContainer()
now accepts anattachToParent
boolean parameter, which indicates whether the parent container's disposal should also dispose the child. It defaults totrue
.ITenantDistributor
andTenantDistributor
types became obsolete. Their functionality is available onIStashboxContainer
.ITenantDistributor.ConfigureTenant()
->IStashboxContainer.CreateChildContainer()
ITenantDistributor.GetTenant()
->IStashboxContainer.GetChildContainer()
- Calling
Validate()
on a container will execute validation on each of its child container if it has any.
IEnumerable<T>
andResolveAll()
requests were not taking services in parent containers into account. Now, it respects the givenResolutionBehavior
and as its default value isParent | Current
,IEnumerable<T>
requests will return services from parent containers by default.- Decorator selection during a resolution request was not take parent containers into consideration. It now respects the given
ResolutionBehavior
parameter.
v5.9.1 - 2023-06-01
- The per-request expression cache stored the underlying expressions with type conversion to the requested service type. This caused type mismatch exceptions when a service was registered to multiple base types. Now, the cache stores the raw instantiation expression and the conversion happens one layer above when needed.
v5.9.0 - 2023-05-31
- Resolving
IServiceProvider
always returned the actual resolution scope, which prevented the usage of custom registered implementations. Now, the container returns the actual resolution scope only when no otherIServiceProvider
implementation is registered.
v5.8.2 - 2023-03-29
- #133: In some cases, open generic constraint validation rejected resolution requests for generic arguments with
struct
constraint.
v5.8.1 - 2023-03-29
- #132: Open generic constraint validation rejected resolution requests for interface type generic arguments with
class
constraint.
v5.8.0 - 2023-02-28
-
Batch registration (like
.RegisterAssembly()
and.RegisterTypes()
) produced individual registrations for each interface/base type and implementation type pairs.For an example class like
class Sample : ISample1, ISample2 { }
the registration mapping looked like this:ISample1 => NewRegistrationOf(Sample) ISample2 => NewRegistrationOf(Sample)
Now each interface/base type is mapped to the same registration:
registration = NewRegistrationOf(Sample) ISample1 => registration ISample2 => registration
-
There are cases where the above fix for batch registration indirectly breaks the following service type filter format:
container.RegisterAssemblyContaining<ISample>(configurator: options => { if (options.ServiceType == typeof(IService)) context.WithScopedLifetime(); });
This worked before (and still works if the related service implements only a single type) because for each implemented type there was an individual registration configuration object passed to the
configurator
delegate.Now it will not work properly if the bound type implements more than one type, as only one object containing each implemented type is passed to the delegate.
Therefore, to still support this case, a new service type checker method was introduced:
container.RegisterAssemblyContaining<ISample>(configurator: options => { if (options.HasServiceType<IService>()) // or .HasServiceType(typeof(IService)) context.WithScopedLifetime(); });
v5.7.1 - 2023-01-20
net7.0
target framework.
- Replaced many
typeof()
calls with static type cache.
v5.7.0 - 2022-12-19
ITenantDistributor
now extendsIStashboxContainer
for easier integration.
v5.6.0 - 2022-12-06
WhenResolutionPathHas()
&WhenInResolutionPathOf()
registration options for handling more conditional resolution cases. They extend the original parent type and attribute conditions with inheritance.
- Name comparison during named scope resolution.
v5.5.3 - 2022-11-29
IsRegistered()
produced falsy results on requests with dynamically constructed string service names.
v5.5.2 - 2022-10-14
v5.5.1 - 2022-10-13
- During the resolution of an open generic service, the actual closed generic registration didn't inherit the registration options from the open generic registration.
v5.5.0 - 2022-10-12
- Minor registration improvements.
v5.4.3 - 2022-09-09
- Named resolution using ResolveAll returns all named and unnamed instances disregarding the WithNamedDependencyResolutionForUnNamedRequests flag. #118
v5.4.2 - 2022-06-02
- Name conflict on the service resolution delegates.
- Make the
name
parameter of theResolve()
functions nullable.
v5.4.1 - 2022-05-16
- Type load exception when the library was trimmed.
v5.4.0 - 2022-05-03
Resolve<IEnumerable<>>(name)
now returns each service that has the same name.
ResolveAll(name)
that returns each service that has the same name.
- Obsolete
Resolve()
method with thenullResultAllowed
parameter, it was replaced byResolveOrDefault()
. - Each obsolete
ResolveFactory<>()
method as their functionality is equivalent toResolve<Func<>>()
. - Obsolete
.WithRuntimeCircularDependencyTracking()
container configuration option in favor of parameterized factory delegates.
v5.3.0 - 2022-04-10
WithDynamicResolution()
registration option to indicate that the service's resolution should be handled by a dynamicResolve()
call on the currentIDependencyResolver
instead of a pre-built instantiation expression.- Support for resolving custom Delegate types alongside
Func<>
.
v5.2.1 - 2022-03-12
- Consolidate
Resolve()
API, using method overloads instead of optional parameters.
v5.2.0 - 2022-03-07
- Unable to resolve IHubContext. #114
- Null-safety by enabling null-state analysis.
- Option to exclude a factory's result from dispose tracking, even if it would be tracked by default. This gives the ability to decide within the factory delegate that the result should be tracked or not.
.Register<Service>(options => options .WithFactory<IRequestContext>(requestContext => requestContext.ExcludeFromTracking(/* get an existing or instantiate a new service */) ) );
- A new
ResolveFactoryOrDefault()
method that allowsnull
results. - A new
ResolveOrDefault()
method that allowsnull
results. ValueTuple<,>
metadata support.
Resolve()
with thenullResultAllowed
parameter became obsolete, it was replaced byResolveOrDefault()
.- Each
ResolveFactory<>()
method became obsolete as their functionality is equivalent toResolve<Func<>>()
.
nullResultAllowed
parameter ofResolveFactory()
.
v5.1.0 - 2022-02-27
- Marked the
.WithRuntimeCircularDependencyTracking()
container configuration option as Obsolete in favor of parameterized factory delegates.
v5.0.1 - 2022-02-10
- Converted the
ServiceContext
to a read-only struct. - Made the
.AsServiceContext()
extension method ofExpression
public.
v5.0.0 - 2022-02-09
- Additional metadata registration option.
- Support for requesting a service along with its identifier.
- Support for per-request lifetime.
- New, clearer API for wrapper extensions.
- There was a bug in the expression compiler that resulted in wrong IL generation in case of value types inside
IEnumerable<>
.
-
Tuple<>
requests are not resolved with services in all its items anymore. It's became part of the newly introduced resolution with metadata feature. -
The
IResolver
interface became the base for the newly introducedIServiceWrapper
andIServiceResolver
interfaces. These became the main entrypoints for container extensions. -
To make the dependency overrides available in factories the
IResolutionContext
was bound to the generated expression tree and the compiled delegate. (#105) This temporary solution could lead issues as the resolution context is static between the compiled delegates, however the dependency overrides are not.To resolve this, a new
IRequestContext
parameter is introduced for each compiled factory delegate that can be used to access overrides. (The same context object is used to produce and track per-request services)container.Register<Service>(options => options. WithFactory<IRequestContext>(requestContext => { // access the overrides through: requestContext.GetOverrides() // or: requestContext.GetDependencyOverrideOrDefault<OverrideType>() }))
- Support of circular dependencies with
Lazy<>
along with the.WithCircularDependencyWithLazy()
container configuration option.
v4.1.0 - 2021-11-21
IsRegistered()
returnstrue
only when the container has a registration with the given type (and name).CanResolve()
returnstrue
only when at least one of the following is true:- The given type is registered in the current or one of the parent containers.
- The given type is a closed generic type and its open generic definition is registered.
- The given type is a wrapper (
IEnumerable<>
,Lazy<>
,Func<>
, orTuple<>
) and the underlying type is registered. - The given type is not registered but it's resolvable and the unknown type resolution is enabled.
v4.0.0 - 2021-11-18
- .NET 4.0 support.
v3.6.4 - 2021-08-31
Skip()
method forUnknownRegistrationConfigurator
used to prevent specific types from auto injection. #105- Parameterized
WithFactory()
option for runtime type based registrations and decorators. #105
v3.6.3 - 2021-05-26
v3.6.2 - 2021-04-23
- Rare NullReferenceException on Resolve. #101
- Decorators having
IEnumerable<TDecoratee>
dependency were not handled correctly.
v3.6.1 - 2021-03-16
- Lifetime validation for scoped services requested from root scope. The validation was executed only at the expression tree building phase, so an already built scoped factory invoked on the root scope was able to bypass the lifetime validation and store the instance as a singleton. Now the validation runs at every request.
v3.6.0 - 2021-02-25
- Parameterized factory delegates. Read more. Also, here is the list of the new factory configuration methods.
- Multiple conditions from the same type are now combined with OR logical operator. Read more.
- Named version of the
.WhenDecoratedServiceIs()
decorator condition. Read more.
.InjectMember()
registration configuration option..WithDependencyBindig()
should be used instead. Read more.
- The
GetRegistrationOrDefault(type, resolutionContext, name)
method of theIRegistrationRepository
interface. - Some properties of the
RegistrationContext
class were moved to internal visibility.
v3.5.1 - 2021-02-19
- When a singleton registration was replaced with
.ReplaceExisting()
, the container still used the old instance. #98
v3.5.0 - 2021-01-31
- Assembly scanning:
- Added option to filter service types and disable self-registration.
- Recognize generic definitions.
- Support to covariant/contravariant generic type resolution.
- Services with named scope lifetime were not chosen right from the registration repo.
v3.4.0 - 2020-11-15
- The core components of multitenant functionality.
- Throw
ObjectDisposedException
when the container or scope is used after their disposal.
v3.3.0 - 2020-11-05
- Option to rebuild singletons in child container with dependencies overridden in it.
- Singleton instances were built when the Validate() was called, now just the expression is generated for them.
v3.2.9 - 2020-11-02
- Option to replace a registration only if an existing one is registered with the same type or name.
v3.2.8 - 2020-10-17
- Switch to license expression in nuget package. #95
v3.2.7 - 2020-10-16
- Minor bugfixes.
v3.2.6 - 2020-10-16
- The Validate() method now throws an AggregateException containing all the underlying exceptions.
- Minor bugfixes.
v3.2.5 - 2020-10-12
- Minor bugfixes.
v3.2.4 - 2020-07-22
- The
.WhenDecoratedServiceHas()
and.WhenDecoratedServiceIs()
decorator configuration options.
v3.2.2 - 2020-07-21
- Support of conditional and lifetime managed decorators #93
v3.2.1 - 2020-07-09
- Factory resolution didn't use the built-in expression compiler.
v3.2.0 - 2020-06-29
- IAsyncDisposable support #90
- It works on >=net461, >=netstandard2.0 frameworks.
- On net461 and netstandard2.0 the usage of IAsyncDisposable interface requires the Microsoft.Bcl.AsyncInterfaces package, on netstandard2.1 it's part of the framework.
- Resolution with custom parameter values #91
v3.1.2 - 2020-06-22
v3.1.1 - 2020-06-11
- String constant is not handled well by the built-in compiler #86
- Registration behaviour doesn't respect replacing #87
v3.1.0 - 2020-06-08
- Nested named resolution could cause stack overflow #74
- Improve support for Assemblies loaded into Collectible AssemblyLoadContexts #73
- Unknown type resolution does not work recursively #77
- Exception when building expressions #76
- Bad performance #79
- Expected override behaviour not working with scopes #80
WithUniqueRegistrationIdentifiers()
option has been removed,WithRegistrationBehavior()
has been added instead.- Circular dependency tracking is enabled now by default, for runtime tracking the renamed
WithRuntimeCircularDependencyTracking()
option can be used. WithMemberInjectionWithoutAnnotation()
container configuration option has been renamed toWithAutoMemberInjection()
.SetImplementationType()
option has been added to the registration configuration used when unknown type detected.- Removed the
GetScopedInstace()
method from theIResolutionScope
, they are treated as expression overrides now and consumed automatically by the container. - Lifetimes became stateless and their API has been changed, read this for more info.
- Lifetime validation has been added:
- Tracking dependencies that has shorter life-span than their direct or indirect parent's.
- Tracking scoped services resolved from root.
- The container throws a LifetimeValidationFailedException when the validation fails.
PerRequestLifetime
has been renamed toPerScopedRequestLifetime
.RegisterInstanceAs()
has been removed, every functionality is available on theRegisterInstance()
methods.- Service/Implementation type map validation has been added to the non-generic registration methods.
InjectionParameter
has been replaced withKeyValuePair<string, object>
.IserviceRegistration
interface has been removed, only its implementation remained.- Removed the legacy container extension functionality.
- Removed the support of PCL v259.