@@ -22,15 +22,42 @@ public static class SimpleInjectorAddOptionsAspNetCoreExtensions
2222 /// additional integration options to be applied. These basic integrations includes wrapping each web
2323 /// request in an <see cref="AsyncScopedLifestyle"/> scope and making the nessesary changes that make
2424 /// it possible for enabling the injection of framework components in Simple Injector-constructed
25- /// components when
25+ /// components when
2626 /// <see cref="SimpleInjectorServiceCollectionExtensions.UseSimpleInjector(IServiceProvider, Container)"/>
27- /// is called.
27+ /// is called. This method uses the default <see cref="ServiceScopeReuseBehavior"/>, which is
28+ /// <see cref="ServiceScopeReuseBehavior.OnePerRequest"/>. This means that within a single web request, the same
29+ /// <see cref="IServiceScope"/> instance will be used, irregardless of the number of Simple Injector
30+ /// <see cref="Scope"/> instances you create. Outside the context of a web request, the ASP.NET Core
31+ /// integration falls back to the default behavior specified by the
32+ /// <see cref="SimpleInjectorAddOptions.ServiceProviderAccessor"/>. By default, a new
33+ /// <see cref="IServiceScope"/> instance will be created per Simple Injector <see cref="Scope"/>.
2834 /// </summary>
2935 /// <param name="options">The options to which the integration should be applied.</param>
3036 /// <returns>A new <see cref="SimpleInjectorAspNetCoreBuilder"/> instance that allows additional
3137 /// configurations to be made.</returns>
3238 /// <exception cref="ArgumentNullException">Thrown when <paramref name="options"/> is null.</exception>
3339 public static SimpleInjectorAspNetCoreBuilder AddAspNetCore ( this SimpleInjectorAddOptions options )
40+ {
41+ return AddAspNetCore ( options , ServiceScopeReuseBehavior . OnePerRequest ) ;
42+ }
43+
44+ /// <summary>
45+ /// Adds basic Simple Injector integration for ASP.NET Core and returns a builder object that allow
46+ /// additional integration options to be applied. These basic integrations includes wrapping each web
47+ /// request in an <see cref="AsyncScopedLifestyle"/> scope and making the nessesary changes that make
48+ /// it possible for enabling the injection of framework components in Simple Injector-constructed
49+ /// components when
50+ /// <see cref="SimpleInjectorServiceCollectionExtensions.UseSimpleInjector(IServiceProvider, Container)"/>
51+ /// is called.
52+ /// </summary>
53+ /// <param name="options">The options to which the integration should be applied.</param>
54+ /// <param name="serviceScopeBehavior">Defines in which way Simple Injector should use and reuse the ASP.NET
55+ /// Core <see cref="IServiceScope"/>, which is used to resolve cross-wired dependencies from.</param>
56+ /// <returns>A new <see cref="SimpleInjectorAspNetCoreBuilder"/> instance that allows additional
57+ /// configurations to be made.</returns>
58+ /// <exception cref="ArgumentNullException">Thrown when <paramref name="options"/> is null.</exception>
59+ public static SimpleInjectorAspNetCoreBuilder AddAspNetCore (
60+ this SimpleInjectorAddOptions options , ServiceScopeReuseBehavior serviceScopeBehavior )
3461 {
3562 if ( options is null )
3663 {
@@ -44,15 +71,41 @@ public static SimpleInjectorAspNetCoreBuilder AddAspNetCore(this SimpleInjectorA
4471 // Add the IHttpContextAccessor to allow Simple Injector cross wiring to work in ASP.NET Core.
4572 services . TryAddSingleton < IHttpContextAccessor , HttpContextAccessor > ( ) ;
4673
47- // Replace the default IServiceProviderAccessor with on that can use IHttpContextAccessor to
48- // resolve instances that are scoped inside the current request.
49- options . ServiceProviderAccessor = new AspNetCoreServiceProviderAccessor (
50- new HttpContextAccessor ( ) ,
51- options . ServiceProviderAccessor ) ;
74+ options . ServiceProviderAccessor = CreateServiceProviderAccessor ( options , serviceScopeBehavior ) ;
5275
5376 services . UseSimpleInjectorAspNetRequestScoping ( container ) ;
5477
5578 return new SimpleInjectorAspNetCoreBuilder ( options ) ;
5679 }
80+
81+ private static IServiceProviderAccessor CreateServiceProviderAccessor (
82+ SimpleInjectorAddOptions options , ServiceScopeReuseBehavior serviceScopeBehavior )
83+ {
84+ if ( serviceScopeBehavior < ServiceScopeReuseBehavior . OnePerRequest
85+ || serviceScopeBehavior > ServiceScopeReuseBehavior . Unchanged )
86+ {
87+ throw new ArgumentOutOfRangeException ( nameof ( serviceScopeBehavior ) ) ;
88+ }
89+
90+ if ( serviceScopeBehavior == ServiceScopeReuseBehavior . OnePerRequest )
91+ {
92+ // This IServiceProviderAccessor uses IHttpContextAccessor to resolve instances that are scoped inside
93+ // the current request.
94+ return new OnePerRequestServiceProviderAccessor (
95+ new HttpContextAccessor ( ) ,
96+ options . ServiceProviderAccessor ) ;
97+ }
98+ else if ( serviceScopeBehavior == ServiceScopeReuseBehavior . OnePerNestedScope )
99+ {
100+ // This IServiceProviderAccessor resolves cross-wired services from the request's IServiceScope, but
101+ // uses a new IServiceScope within a nested scope.
102+ return new OnePerNestedScopeServiceProviderAccessor ( options . Container , options . ServiceProviderAccessor ) ;
103+ }
104+ else
105+ {
106+ // This uses the default behavior.
107+ return options . ServiceProviderAccessor ;
108+ }
109+ }
57110 }
58111}
0 commit comments