}
[NonEvent]
- public void ScopeDisposed(ServiceProviderEngine engine, ScopeState state)
- {
- if (IsEnabled(EventLevel.Verbose, EventKeywords.All))
- {
- ScopeDisposed(engine.GetHashCode(), state.ResolvedServicesCount, state.DisposableServicesCount);
- }
- }
-
- [NonEvent]
public void ServiceResolved(Type serviceType)
{
if (IsEnabled(EventLevel.Verbose, EventKeywords.All))
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System;
-using System.Collections.Generic;
-using Microsoft.Extensions.DependencyInjection.ServiceLookup;
-
-namespace Microsoft.Extensions.DependencyInjection
-{
- internal class ScopeState
- {
- public Dictionary<ServiceCacheKey, object> ResolvedServices { get; }
- public List<object> Disposables { get; set; }
-
- public int DisposableServicesCount => Disposables?.Count ?? 0;
- public int ResolvedServicesCount => ResolvedServices.Count;
-
- public ScopeState()
- {
- ResolvedServices = new Dictionary<ServiceCacheKey, object>();
- }
-
- public void Track(ServiceProviderEngine engine)
- {
- DependencyInjectionEventSource.Log.ScopeDisposed(engine, this);
- }
- }
-}
throw new ArgumentNullException(nameof(options));
}
- IServiceProviderEngine engine;
-
-#if !NETSTANDARD2_1
- engine = new DynamicServiceProviderEngine(services);
-#else
- if (RuntimeFeature.IsDynamicCodeCompiled)
- {
- engine = new DynamicServiceProviderEngine(services);
- }
- else
- {
- // Don't try to compile Expressions/IL if they are going to get interpreted
- engine = new RuntimeServiceProviderEngine(services);
- }
-#endif
-
- return new ServiceProvider(services, engine, options);
+ return new ServiceProvider(services, options);
}
}
}
{
internal sealed class CallSiteRuntimeResolver : CallSiteVisitor<RuntimeResolverContext, object>
{
+ public static CallSiteRuntimeResolver Instance { get; } = new();
+
+ private CallSiteRuntimeResolver()
+ {
+ }
+
public object Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
{
return VisitCallSite(callSite, new RuntimeResolverContext
}
var lockType = RuntimeResolverLock.Root;
- ServiceProviderEngineScope serviceProviderEngine = context.Scope.Engine.Root;
+ ServiceProviderEngineScope serviceProviderEngine = context.Scope.RootProvider.Root;
lock (callSite)
{
{
// Check if we are in the situation where scoped service was promoted to singleton
// and we need to lock the root
- return context.Scope == context.Scope.Engine.Root ?
+ return context.Scope.IsRootScope ?
VisitRootCache(callSite, context) :
VisitCache(callSite, context, context.Scope, RuntimeResolverLock.Scope);
}
protected override object VisitServiceScopeFactory(ServiceScopeFactoryCallSite serviceScopeFactoryCallSite, RuntimeResolverContext context)
{
- return context.Scope.Engine;
+ return serviceScopeFactoryCallSite.Value;
}
protected override object VisitIEnumerable(IEnumerableCallSite enumerableCallSite, RuntimeResolverContext context)
// The .NET Foundation licenses this file to you under the MIT license.
using System;
-using System.Collections.Generic;
namespace Microsoft.Extensions.DependencyInjection.ServiceLookup
{
public ExpressionResolverBuilder ResolverBuilder { get; }
#endif
- public CompiledServiceProviderEngine(IEnumerable<ServiceDescriptor> serviceDescriptors)
- : base(serviceDescriptors)
+ public CompiledServiceProviderEngine(ServiceProvider provider)
{
-#if IL_EMIT
- ResolverBuilder = new ILEmitResolverBuilder(RuntimeResolver, this, Root);
-#else
- ResolverBuilder = new ExpressionResolverBuilder(RuntimeResolver, this, Root);
-#endif
+ ResolverBuilder = new(provider);
}
- protected override Func<ServiceProviderEngineScope, object> RealizeService(ServiceCallSite callSite)
- {
- Func<ServiceProviderEngineScope, object> realizedService = ResolverBuilder.Build(callSite);
- RealizedServices[callSite.ServiceType] = realizedService;
- return realizedService;
- }
+ public override Func<ServiceProviderEngineScope, object> RealizeService(ServiceCallSite callSite) => ResolverBuilder.Build(callSite);
}
}
// The .NET Foundation licenses this file to you under the MIT license.
using System;
-using System.Collections.Generic;
using System.Threading;
namespace Microsoft.Extensions.DependencyInjection.ServiceLookup
{
internal sealed class DynamicServiceProviderEngine : CompiledServiceProviderEngine
{
- public DynamicServiceProviderEngine(IEnumerable<ServiceDescriptor> serviceDescriptors)
- : base(serviceDescriptors)
+ private readonly ServiceProvider _serviceProvider;
+
+ public DynamicServiceProviderEngine(ServiceProvider serviceProvider): base(serviceProvider)
{
+ _serviceProvider = serviceProvider;
}
- protected override Func<ServiceProviderEngineScope, object> RealizeService(ServiceCallSite callSite)
+ public override Func<ServiceProviderEngineScope, object> RealizeService(ServiceCallSite callSite)
{
int callCount = 0;
return scope =>
// Resolve the result before we increment the call count, this ensures that singletons
// won't cause any side effects during the compilation of the resolve function.
- var result = RuntimeResolver.Resolve(callSite, scope);
+ var result = CallSiteRuntimeResolver.Instance.Resolve(callSite, scope);
if (Interlocked.Increment(ref callCount) == 2)
{
{
try
{
- base.RealizeService(callSite);
+ _serviceProvider.ReplaceServiceAccessor(callSite, base.RealizeService(callSite));
}
catch (Exception ex)
{
Expression.Call(ScopeParameter, CaptureDisposableMethodInfo, CaptureDisposableParameter),
CaptureDisposableParameter);
- private readonly CallSiteRuntimeResolver _runtimeResolver;
-
- private readonly IServiceScopeFactory _serviceScopeFactory;
-
private readonly ServiceProviderEngineScope _rootScope;
private readonly ConcurrentDictionary<ServiceCacheKey, Func<ServiceProviderEngineScope, object>> _scopeResolverCache;
private readonly Func<ServiceCacheKey, ServiceCallSite, Func<ServiceProviderEngineScope, object>> _buildTypeDelegate;
- public ExpressionResolverBuilder(CallSiteRuntimeResolver runtimeResolver, IServiceScopeFactory serviceScopeFactory, ServiceProviderEngineScope rootScope)
+ public ExpressionResolverBuilder(ServiceProvider serviceProvider)
{
- if (runtimeResolver == null)
- {
- throw new ArgumentNullException(nameof(runtimeResolver));
- }
-
+ _rootScope = serviceProvider.Root;
_scopeResolverCache = new ConcurrentDictionary<ServiceCacheKey, Func<ServiceProviderEngineScope, object>>();
- _runtimeResolver = runtimeResolver;
- _serviceScopeFactory = serviceScopeFactory;
- _rootScope = rootScope;
_buildTypeDelegate = (key, cs) => BuildNoCache(cs);
}
public Func<ServiceProviderEngineScope, object> Build(ServiceCallSite callSite)
{
- // Optimize singleton case
- if (callSite.Cache.Location == CallSiteResultCacheLocation.Root)
- {
- object value = _runtimeResolver.Resolve(callSite, _rootScope);
- return scope => value;
- }
-
// Only scope methods are cached
if (callSite.Cache.Location == CallSiteResultCacheLocation.Scope)
{
protected override Expression VisitRootCache(ServiceCallSite singletonCallSite, object context)
{
- return Expression.Constant(_runtimeResolver.Resolve(singletonCallSite, _rootScope));
+ return Expression.Constant(CallSiteRuntimeResolver.Instance.Resolve(singletonCallSite, _rootScope));
}
protected override Expression VisitConstant(ConstantCallSite constantCallSite, object context)
protected override Expression VisitServiceScopeFactory(ServiceScopeFactoryCallSite serviceScopeFactoryCallSite, object context)
{
- return Expression.Constant(_serviceScopeFactory);
+ return Expression.Constant(serviceScopeFactoryCallSite.Value);
}
protected override Expression VisitFactory(FactoryCallSite factoryCallSite, object context)
// The .NET Foundation licenses this file to you under the MIT license.
using System;
-using System.Collections.Generic;
namespace Microsoft.Extensions.DependencyInjection.ServiceLookup
{
internal sealed class ExpressionsServiceProviderEngine : ServiceProviderEngine
{
private readonly ExpressionResolverBuilder _expressionResolverBuilder;
- public ExpressionsServiceProviderEngine(IEnumerable<ServiceDescriptor> serviceDescriptors) : base(serviceDescriptors)
+
+ public ExpressionsServiceProviderEngine(ServiceProvider serviceProvider)
{
- _expressionResolverBuilder = new ExpressionResolverBuilder(RuntimeResolver, this, Root);
+ _expressionResolverBuilder = new ExpressionResolverBuilder(serviceProvider);
}
- protected override Func<ServiceProviderEngineScope, object> RealizeService(ServiceCallSite callSite)
+ public override Func<ServiceProviderEngineScope, object> RealizeService(ServiceCallSite callSite)
{
- Func<ServiceProviderEngineScope, object> realizedService = _expressionResolverBuilder.Build(callSite);
- RealizedServices[callSite.ServiceType] = realizedService;
- return realizedService;
+ return _expressionResolverBuilder.Build(callSite);
}
}
}
private sealed class ILEmitResolverBuilderRuntimeContext
{
- public IServiceScopeFactory ScopeFactory;
public object[] Constants;
public Func<IServiceProvider, object>[] Factories;
}
public DynamicMethod DynamicMethod;
}
- private readonly CallSiteRuntimeResolver _runtimeResolver;
-
- private readonly IServiceScopeFactory _serviceScopeFactory;
-
private readonly ServiceProviderEngineScope _rootScope;
private readonly ConcurrentDictionary<ServiceCacheKey, GeneratedMethod> _scopeResolverCache;
private readonly Func<ServiceCacheKey, ServiceCallSite, GeneratedMethod> _buildTypeDelegate;
- public ILEmitResolverBuilder(CallSiteRuntimeResolver runtimeResolver, IServiceScopeFactory serviceScopeFactory, ServiceProviderEngineScope rootScope) :
- base()
+ public ILEmitResolverBuilder(ServiceProvider serviceProvider)
{
- if (runtimeResolver == null)
- {
- throw new ArgumentNullException(nameof(runtimeResolver));
- }
- _runtimeResolver = runtimeResolver;
- _serviceScopeFactory = serviceScopeFactory;
- _rootScope = rootScope;
+ _rootScope = serviceProvider.Root;
_scopeResolverCache = new ConcurrentDictionary<ServiceCacheKey, GeneratedMethod>();
_buildTypeDelegate = (key, cs) => BuildTypeNoCache(cs);
}
public Func<ServiceProviderEngineScope, object> Build(ServiceCallSite callSite)
{
- // Optimize singleton case
- if (callSite.Cache.Location == CallSiteResultCacheLocation.Root)
- {
- object value = _runtimeResolver.Resolve(callSite, _rootScope);
- return scope => value;
- }
-
return BuildType(callSite).Lambda;
}
protected override object VisitRootCache(ServiceCallSite callSite, ILEmitResolverBuilderContext argument)
{
- AddConstant(argument, _runtimeResolver.Resolve(callSite, _rootScope));
+ AddConstant(argument, CallSiteRuntimeResolver.Instance.Resolve(callSite, _rootScope));
return null;
}
protected override object VisitServiceScopeFactory(ServiceScopeFactoryCallSite serviceScopeFactoryCallSite, ILEmitResolverBuilderContext argument)
{
- // this.ScopeFactory
- argument.Generator.Emit(OpCodes.Ldarg_0);
- argument.Generator.Emit(OpCodes.Ldfld, typeof(ILEmitResolverBuilderRuntimeContext).GetField(nameof(ILEmitResolverBuilderRuntimeContext.ScopeFactory)));
+ AddConstant(argument, serviceScopeFactoryCallSite.Value);
return null;
}
return new ILEmitResolverBuilderRuntimeContext
{
Constants = context.Constants?.ToArray(),
- Factories = context.Factories?.ToArray(),
- ScopeFactory = _serviceScopeFactory
+ Factories = context.Factories?.ToArray()
};
}
// The .NET Foundation licenses this file to you under the MIT license.
using System;
-using System.Collections.Generic;
namespace Microsoft.Extensions.DependencyInjection.ServiceLookup
{
internal sealed class ILEmitServiceProviderEngine : ServiceProviderEngine
{
private readonly ILEmitResolverBuilder _expressionResolverBuilder;
- public ILEmitServiceProviderEngine(IEnumerable<ServiceDescriptor> serviceDescriptors) : base(serviceDescriptors)
+ public ILEmitServiceProviderEngine(ServiceProvider serviceProvider)
{
- _expressionResolverBuilder = new ILEmitResolverBuilder(RuntimeResolver, this, Root);
+ _expressionResolverBuilder = new ILEmitResolverBuilder(serviceProvider);
}
- protected override Func<ServiceProviderEngineScope, object> RealizeService(ServiceCallSite callSite)
+ public override Func<ServiceProviderEngineScope, object> RealizeService(ServiceCallSite callSite)
{
- Func<ServiceProviderEngineScope, object> realizedService = _expressionResolverBuilder.Build(callSite);
- RealizedServices[callSite.ServiceType] = realizedService;
- return realizedService;
+ return _expressionResolverBuilder.Build(callSite);
}
}
}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System;
-
-namespace Microsoft.Extensions.DependencyInjection.ServiceLookup
-{
- internal interface IServiceProviderEngine : IServiceProvider, IDisposable, IAsyncDisposable
- {
- IServiceScope RootScope { get; }
- void InitializeCallback(IServiceProviderEngineCallback callback);
- void ValidateService(ServiceDescriptor descriptor);
- }
-}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System;
-
-namespace Microsoft.Extensions.DependencyInjection.ServiceLookup
-{
- internal interface IServiceProviderEngineCallback
- {
- void OnCreate(ServiceCallSite callSite);
- void OnResolve(Type serviceType, IServiceScope scope);
- }
-}
// The .NET Foundation licenses this file to you under the MIT license.
using System;
-using System.Collections.Generic;
namespace Microsoft.Extensions.DependencyInjection.ServiceLookup
{
internal sealed class RuntimeServiceProviderEngine : ServiceProviderEngine
{
- public RuntimeServiceProviderEngine(IEnumerable<ServiceDescriptor> serviceDescriptors) : base(serviceDescriptors)
- {
- }
+ public static RuntimeServiceProviderEngine Instance { get; } = new RuntimeServiceProviderEngine();
- protected override Func<ServiceProviderEngineScope, object> RealizeService(ServiceCallSite callSite)
+ private RuntimeServiceProviderEngine() { }
+
+ public override Func<ServiceProviderEngineScope, object> RealizeService(ServiceCallSite callSite)
{
return scope =>
{
- Func<ServiceProviderEngineScope, object> realizedService = p => RuntimeResolver.Resolve(callSite, p);
-
- RealizedServices[callSite.ServiceType] = realizedService;
- return realizedService(scope);
+ return CallSiteRuntimeResolver.Instance.Resolve(callSite, scope);
};
}
}
// The .NET Foundation licenses this file to you under the MIT license.
using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.Threading.Tasks;
namespace Microsoft.Extensions.DependencyInjection.ServiceLookup
{
- internal abstract class ServiceProviderEngine : IServiceProviderEngine, IServiceScopeFactory
+ internal abstract class ServiceProviderEngine
{
- private IServiceProviderEngineCallback _callback;
-
- private readonly Func<Type, Func<ServiceProviderEngineScope, object>> _createServiceAccessor;
-
- private bool _disposed;
-
- protected ServiceProviderEngine(IEnumerable<ServiceDescriptor> serviceDescriptors)
- {
- _createServiceAccessor = CreateServiceAccessor;
- Root = new ServiceProviderEngineScope(this);
- RuntimeResolver = new CallSiteRuntimeResolver();
- CallSiteFactory = new CallSiteFactory(serviceDescriptors);
- CallSiteFactory.Add(typeof(IServiceProvider), new ServiceProviderCallSite());
- CallSiteFactory.Add(typeof(IServiceScopeFactory), new ServiceScopeFactoryCallSite());
- RealizedServices = new ConcurrentDictionary<Type, Func<ServiceProviderEngineScope, object>>();
- }
-
- internal ConcurrentDictionary<Type, Func<ServiceProviderEngineScope, object>> RealizedServices { get; }
-
- internal CallSiteFactory CallSiteFactory { get; }
-
- protected CallSiteRuntimeResolver RuntimeResolver { get; }
-
- public ServiceProviderEngineScope Root { get; }
-
- public IServiceScope RootScope => Root;
-
- void IServiceProviderEngine.InitializeCallback(IServiceProviderEngineCallback callback)
- {
- _callback = callback;
- }
-
- public void ValidateService(ServiceDescriptor descriptor)
- {
- if (descriptor.ServiceType.IsGenericType && !descriptor.ServiceType.IsConstructedGenericType)
- {
- return;
- }
-
- try
- {
- ServiceCallSite callSite = CallSiteFactory.GetCallSite(descriptor, new CallSiteChain());
- if (callSite != null)
- {
- _callback?.OnCreate(callSite);
- }
- }
- catch (Exception e)
- {
- throw new InvalidOperationException($"Error while validating the service descriptor '{descriptor}': {e.Message}", e);
- }
- }
-
- public object GetService(Type serviceType) => GetService(serviceType, Root);
-
- protected abstract Func<ServiceProviderEngineScope, object> RealizeService(ServiceCallSite callSite);
-
- public void Dispose()
- {
- _disposed = true;
- Root.Dispose();
- }
-
- public ValueTask DisposeAsync()
- {
- _disposed = true;
- return Root.DisposeAsync();
- }
-
- internal object GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
- {
- if (_disposed)
- {
- ThrowHelper.ThrowObjectDisposedException();
- }
-
- Func<ServiceProviderEngineScope, object> realizedService = RealizedServices.GetOrAdd(serviceType, _createServiceAccessor);
- _callback?.OnResolve(serviceType, serviceProviderEngineScope);
- DependencyInjectionEventSource.Log.ServiceResolved(serviceType);
- return realizedService.Invoke(serviceProviderEngineScope);
- }
-
- public IServiceScope CreateScope()
- {
- if (_disposed)
- {
- ThrowHelper.ThrowObjectDisposedException();
- }
-
- return new ServiceProviderEngineScope(this);
- }
-
- private Func<ServiceProviderEngineScope, object> CreateServiceAccessor(Type serviceType)
- {
- ServiceCallSite callSite = CallSiteFactory.GetCallSite(serviceType, new CallSiteChain());
- if (callSite != null)
- {
- DependencyInjectionEventSource.Log.CallSiteBuilt(serviceType, callSite);
- _callback?.OnCreate(callSite);
- return RealizeService(callSite);
- }
-
- return _ => null;
- }
+ public abstract Func<ServiceProviderEngineScope, object> RealizeService(ServiceCallSite callSite);
}
}
namespace Microsoft.Extensions.DependencyInjection.ServiceLookup
{
- internal sealed class ServiceProviderEngineScope : IServiceScope, IServiceProvider, IAsyncDisposable
+ internal sealed class ServiceProviderEngineScope : IServiceScope, IServiceProvider, IAsyncDisposable, IServiceScopeFactory
{
// For testing only
internal Action<object> _captureDisposableCallback;
private bool _disposed;
- private readonly ScopeState _state;
+ private List<object> _disposables;
- public ServiceProviderEngineScope(ServiceProviderEngine engine)
+ public ServiceProviderEngineScope(ServiceProvider provider)
{
- Engine = engine;
- _state = new ScopeState();
+ ResolvedServices = new Dictionary<ServiceCacheKey, object>();
+ RootProvider = provider;
}
- internal Dictionary<ServiceCacheKey, object> ResolvedServices => _state.ResolvedServices;
+ internal Dictionary<ServiceCacheKey, object> ResolvedServices { get; }
// This lock protects state on the scope, in particular, for the root scope, it protects
- // the list of disposable entries only, since ResolvedServices is a concurrent dictionary.
+ // the list of disposable entries only, since ResolvedServices are cached on CallSites
// For other scopes, it protects ResolvedServices and the list of disposables
- internal object Sync => _state;
+ internal object Sync => ResolvedServices;
- public ServiceProviderEngine Engine { get; }
+ public bool IsRootScope => this == RootProvider.Root;
+
+ internal ServiceProvider RootProvider { get; }
public object GetService(Type serviceType)
{
ThrowHelper.ThrowObjectDisposedException();
}
- return Engine.GetService(serviceType, this);
+ return RootProvider.GetService(serviceType, this);
}
public IServiceProvider ServiceProvider => this;
- public bool IsRootScope => this == Engine.Root;
+ public IServiceScope CreateScope() => RootProvider.CreateScope();
internal object CaptureDisposable(object service)
{
return service;
}
+ bool disposed = false;
lock (Sync)
{
if (_disposed)
{
- if (service is IDisposable disposable)
- {
- disposable.Dispose();
- }
- else
- {
- // sync over async, for the rare case that an object only implements IAsyncDisposable and may end up starving the thread pool.
- Task.Run(() => ((IAsyncDisposable)service).DisposeAsync().AsTask()).GetAwaiter().GetResult();
- }
+ disposed = true;
+ }
+ else
+ {
+ _disposables ??= new List<object>();
- ThrowHelper.ThrowObjectDisposedException();
+ _disposables.Add(service);
}
+ }
- _state.Disposables ??= new List<object>();
+ // Don't run customer code under the lock
+ if (disposed)
+ {
+ if (service is IDisposable disposable)
+ {
+ disposable.Dispose();
+ }
+ else
+ {
+ // sync over async, for the rare case that an object only implements IAsyncDisposable and may end up starving the thread pool.
+ Task.Run(() => ((IAsyncDisposable)service).DisposeAsync().AsTask()).GetAwaiter().GetResult();
+ }
- _state.Disposables.Add(service);
+ ThrowHelper.ThrowObjectDisposedException();
}
return service;
}
// Track statistics about the scope (number of disposable objects and number of disposed services)
- _state.Track(Engine);
+ DependencyInjectionEventSource.Log.ScopeDisposed(RootProvider.GetHashCode(), ResolvedServices.Count, _disposables?.Count ?? 0);
// We've transitioned to the disposed state, so future calls to
// CaptureDisposable will immediately dispose the object.
// trying to get a cached singleton service. If it doesn't find it
// it will try to create a new one which will result in an ObjectDisposedException.
- return _state.Disposables;
+ return _disposables;
}
}
}
{
internal sealed class ServiceScopeFactoryCallSite : ServiceCallSite
{
- public ServiceScopeFactoryCallSite() : base(ResultCache.None)
+ public ServiceScopeFactoryCallSite(IServiceScopeFactory value) : base(ResultCache.None)
{
+ Value = value;
}
public override Type ServiceType { get; } = typeof(IServiceScopeFactory);
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-namespace Microsoft.Extensions.DependencyInjection.ServiceLookup
-{
-}
// The .NET Foundation licenses this file to you under the MIT license.
using System;
+using System.Collections.Concurrent;
using System.Collections.Generic;
+using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection.ServiceLookup;
/// <summary>
/// The default IServiceProvider.
/// </summary>
- public sealed class ServiceProvider : IServiceProvider, IDisposable, IServiceProviderEngineCallback, IAsyncDisposable
+ public sealed class ServiceProvider : IServiceProvider, IDisposable, IAsyncDisposable
{
- private readonly IServiceProviderEngine _engine;
-
private readonly CallSiteValidator _callSiteValidator;
- internal ServiceProvider(IEnumerable<ServiceDescriptor> serviceDescriptors, IServiceProviderEngine engine, ServiceProviderOptions options)
+ private readonly Func<Type, Func<ServiceProviderEngineScope, object>> _createServiceAccessor;
+
+ // Internal for testing
+ internal ServiceProviderEngine _engine;
+
+ private bool _disposed;
+
+ private ConcurrentDictionary<Type, Func<ServiceProviderEngineScope, object>> _realizedServices;
+
+ internal CallSiteFactory CallSiteFactory { get; }
+
+ internal ServiceProviderEngineScope Root { get; }
+
+ internal ServiceProvider(IEnumerable<ServiceDescriptor> serviceDescriptors, ServiceProviderOptions options)
{
- _engine = engine;
+ _engine = GetEngine();
+ _createServiceAccessor = CreateServiceAccessor;
+ _realizedServices = new ConcurrentDictionary<Type, Func<ServiceProviderEngineScope, object>>();
+
+ Root = new ServiceProviderEngineScope(this);
+ CallSiteFactory = new CallSiteFactory(serviceDescriptors);
+ CallSiteFactory.Add(typeof(IServiceProvider), new ServiceProviderCallSite());
+ CallSiteFactory.Add(typeof(IServiceScopeFactory), new ServiceScopeFactoryCallSite(Root));
if (options.ValidateScopes)
{
- _engine.InitializeCallback(this);
_callSiteValidator = new CallSiteValidator();
}
{
try
{
- _engine.ValidateService(serviceDescriptor);
+ ValidateService(serviceDescriptor);
}
catch (Exception e)
{
throw new AggregateException("Some services are not able to be constructed", exceptions.ToArray());
}
}
+
}
/// <summary>
/// </summary>
/// <param name="serviceType">The type of the service to get.</param>
/// <returns>The service that was produced.</returns>
- public object GetService(Type serviceType) => _engine.GetService(serviceType);
+ public object GetService(Type serviceType) => GetService(serviceType, Root);
/// <inheritdoc />
public void Dispose()
{
- _engine.Dispose();
+ _disposed = true;
+ Root.Dispose();
}
- void IServiceProviderEngineCallback.OnCreate(ServiceCallSite callSite)
+ /// <inheritdoc/>
+ public ValueTask DisposeAsync()
{
- _callSiteValidator.ValidateCallSite(callSite);
+ _disposed = true;
+ return Root.DisposeAsync();
}
- void IServiceProviderEngineCallback.OnResolve(Type serviceType, IServiceScope scope)
+ private void OnCreate(ServiceCallSite callSite)
{
- _callSiteValidator.ValidateResolution(serviceType, scope, _engine.RootScope);
+ _callSiteValidator?.ValidateCallSite(callSite);
}
- /// <inheritdoc/>
- public ValueTask DisposeAsync()
+ private void OnResolve(Type serviceType, IServiceScope scope)
+ {
+ _callSiteValidator?.ValidateResolution(serviceType, scope, Root);
+ }
+
+ internal object GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
+ {
+ if (_disposed)
+ {
+ ThrowHelper.ThrowObjectDisposedException();
+ }
+
+ Func<ServiceProviderEngineScope, object> realizedService = _realizedServices.GetOrAdd(serviceType, _createServiceAccessor);
+ OnResolve(serviceType, serviceProviderEngineScope);
+ DependencyInjectionEventSource.Log.ServiceResolved(serviceType);
+ return realizedService.Invoke(serviceProviderEngineScope);
+ }
+
+ private void ValidateService(ServiceDescriptor descriptor)
+ {
+ if (descriptor.ServiceType.IsGenericType && !descriptor.ServiceType.IsConstructedGenericType)
+ {
+ return;
+ }
+
+ try
+ {
+ ServiceCallSite callSite = CallSiteFactory.GetCallSite(descriptor, new CallSiteChain());
+ if (callSite != null)
+ {
+ OnCreate(callSite);
+ }
+ }
+ catch (Exception e)
+ {
+ throw new InvalidOperationException($"Error while validating the service descriptor '{descriptor}': {e.Message}", e);
+ }
+ }
+
+ private Func<ServiceProviderEngineScope, object> CreateServiceAccessor(Type serviceType)
+ {
+ ServiceCallSite callSite = CallSiteFactory.GetCallSite(serviceType, new CallSiteChain());
+ if (callSite != null)
+ {
+ DependencyInjectionEventSource.Log.CallSiteBuilt(serviceType, callSite);
+ OnCreate(callSite);
+
+ // Optimize singleton case
+ if (callSite.Cache.Location == CallSiteResultCacheLocation.Root)
+ {
+ object value = CallSiteRuntimeResolver.Instance.Resolve(callSite, Root);
+ return scope => value;
+ }
+
+ return _engine.RealizeService(callSite);
+ }
+
+ return _ => null;
+ }
+
+ internal void ReplaceServiceAccessor(ServiceCallSite callSite, Func<ServiceProviderEngineScope, object> accessor)
{
- return _engine.DisposeAsync();
+ _realizedServices[callSite.ImplementationType] = accessor;
+ }
+
+ internal IServiceScope CreateScope()
+ {
+ if (_disposed)
+ {
+ ThrowHelper.ThrowObjectDisposedException();
+ }
+
+ return new ServiceProviderEngineScope(this);
+ }
+
+ private ServiceProviderEngine GetEngine()
+ {
+ ServiceProviderEngine engine;
+
+#if !NETSTANDARD2_1
+ engine = new DynamicServiceProviderEngine(this);
+#else
+ if (RuntimeFeature.IsDynamicCodeCompiled)
+ {
+ engine = new DynamicServiceProviderEngine(this);
+ }
+ else
+ {
+ // Don't try to compile Expressions/IL if they are going to get interpreted
+ engine = RuntimeServiceProviderEngine.Instance;
+ }
+#endif
+ return engine;
}
}
}
{
public class CallSiteTests
{
- private static readonly CallSiteRuntimeResolver CallSiteRuntimeResolver = new CallSiteRuntimeResolver();
-
public static IEnumerable<object[]> TestServiceDescriptors(ServiceLifetime lifetime)
{
Func<object, object, bool> compare;
public void BuiltExpressionWillReturnResolvedServiceWhenAppropriate(
ServiceDescriptor[] descriptors, Type serviceType, Func<object, object, bool> compare)
{
- var provider = new DynamicServiceProviderEngine(descriptors);
+ var provider = new ServiceProvider(descriptors, ServiceProviderOptions.Default);
var callSite = provider.CallSiteFactory.GetCallSite(serviceType, new CallSiteChain());
var collectionCallSite = provider.CallSiteFactory.GetCallSite(typeof(IEnumerable<>).MakeGenericType(serviceType), new CallSiteChain());
descriptors.AddScoped<ServiceB>();
descriptors.AddScoped<ServiceC>();
- var provider = new DynamicServiceProviderEngine(descriptors);
+ var provider = new ServiceProvider(descriptors, ServiceProviderOptions.Default);
var callSite = provider.CallSiteFactory.GetCallSite(typeof(ServiceC), new CallSiteChain());
var compiledCallSite = CompileCallSite(callSite, provider);
descriptors.Add(ServiceDescriptor.Describe(typeof(ServiceC), typeof(DisposableServiceC), lifetime));
var disposables = new List<object>();
- var provider = new DynamicServiceProviderEngine(descriptors);
+ var provider = new ServiceProvider(descriptors, ServiceProviderOptions.Default);
provider.Root._captureDisposableCallback = obj =>
{
disposables.Add(obj);
typeof(ServiceC), p => new DisposableServiceC(p.GetService<ServiceB>()), lifetime));
var disposables = new List<object>();
- var provider = new DynamicServiceProviderEngine(descriptors);
+ var provider = new ServiceProvider(descriptors, ServiceProviderOptions.Default);
provider.Root._captureDisposableCallback = obj =>
{
disposables.Add(obj);
descriptors.AddTransient<ServiceC>();
var disposables = new List<object>();
- var provider = new DynamicServiceProviderEngine(descriptors);
+ var provider = new ServiceProvider(descriptors, ServiceProviderOptions.Default);
provider.Root._captureDisposableCallback = obj =>
{
disposables.Add(obj);
descriptors.Add(ServiceDescriptor.Describe(typeof(ServiceD), typeof(ServiceD), lifetime));
var disposables = new List<object>();
- var provider = new DynamicServiceProviderEngine(descriptors);
+ var provider = new ServiceProvider(descriptors, ServiceProviderOptions.Default);
provider.Root._captureDisposableCallback = obj =>
{
disposables.Add(obj);
descriptors.AddTransient<ClassWithThrowingCtor>();
descriptors.AddTransient<IFakeService, FakeService>();
- var provider = new DynamicServiceProviderEngine(descriptors);
+ var provider = new ServiceProvider(descriptors, ServiceProviderOptions.Default);
var callSite1 = provider.CallSiteFactory.GetCallSite(typeof(ClassWithThrowingEmptyCtor), new CallSiteChain());
var compiledCallSite1 = CompileCallSite(callSite1, provider);
descriptors.AddTransient<ServiceD>();
descriptors.AddTransient<ServiceE>();
- var provider = new DynamicServiceProviderEngine(descriptors);
+ var provider = new ServiceProvider(descriptors, ServiceProviderOptions.Default);
var callSite1 = provider.CallSiteFactory.GetCallSite(typeof(ServiceE), new CallSiteChain());
var compileCallSite = CompileCallSite(callSite1, provider);
private static object Invoke(ServiceCallSite callSite, ServiceProviderEngineScope scope)
{
- return CallSiteRuntimeResolver.Resolve(callSite, scope);
+ return CallSiteRuntimeResolver.Instance.Resolve(callSite, scope);
}
- private static Func<ServiceProviderEngineScope, object> CompileCallSite(ServiceCallSite callSite, ServiceProviderEngine engine)
+ private static Func<ServiceProviderEngineScope, object> CompileCallSite(ServiceCallSite callSite, ServiceProvider provider)
{
- return new ExpressionResolverBuilder(CallSiteRuntimeResolver, engine, engine.Root).Build(callSite);
+ return new ExpressionResolverBuilder(provider).Build(callSite);
}
}
}
return services.BuildServiceProvider(options);
}
- IServiceProviderEngine engine = mode switch
+ var provider = new ServiceProvider(services, ServiceProviderOptions.Default);
+ ServiceProviderEngine engine = mode switch
{
- ServiceProviderMode.Dynamic => new DynamicServiceProviderEngine(services),
- ServiceProviderMode.Runtime => new RuntimeServiceProviderEngine(services),
- ServiceProviderMode.Expressions => new ExpressionsServiceProviderEngine(services),
- ServiceProviderMode.ILEmit => new ILEmitServiceProviderEngine(services),
+ ServiceProviderMode.Dynamic => new DynamicServiceProviderEngine(provider),
+ ServiceProviderMode.Runtime => RuntimeServiceProviderEngine.Instance,
+ ServiceProviderMode.Expressions => new ExpressionsServiceProviderEngine(provider),
+ ServiceProviderMode.ILEmit => new ILEmitServiceProviderEngine(provider),
_ => throw new NotSupportedException()
};
-
- return new ServiceProvider(services, engine, options);
+ provider._engine = engine;
+ return provider;
}
}
}
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-using System;
using Microsoft.Extensions.DependencyInjection.Specification.Fakes;
using Xunit;
[Fact]
public void DoubleDisposeWorks()
{
- var engine = new FakeEngine();
- var serviceProviderEngineScope = new ServiceProviderEngineScope(engine);
+ var provider = new ServiceProvider(new ServiceCollection(), ServiceProviderOptions.Default);
+ var serviceProviderEngineScope = new ServiceProviderEngineScope(provider);
serviceProviderEngineScope.ResolvedServices.Add(new ServiceCacheKey(typeof(IFakeService), 0), null);
serviceProviderEngineScope.Dispose();
serviceProviderEngineScope.Dispose();
}
-
- private class FakeEngine : ServiceProviderEngine
- {
- public FakeEngine() :
- base(Array.Empty<ServiceDescriptor>())
- {
- }
-
- protected override Func<ServiceProviderEngineScope, object> RealizeService(ServiceCallSite callSite)
- {
- return scope => null;
- }
-
- }
}
}