From 073582cee08fb62d9bc5668e57595267c41fb8d9 Mon Sep 17 00:00:00 2001 From: Eric Erhardt Date: Thu, 8 Jul 2021 10:53:24 -0500 Subject: [PATCH 1/3] Fix NullReferenceException in background thread emitting IL in DependencyInjection When ILEmitResolverBuilder is getting created, it grabs the "Root" scope off of the ServiceProvider. However, the Root scope isn't set on ServiceProvider yet. So later when it tries to get used, it null refs. But this exception gets caught an eaten since it happens on a background thread. The fix is to set Root before creating the ServiceProviderEngine. --- .../src/ServiceProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceProvider.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceProvider.cs index b93a11d9566192..d22599c4a492ff 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceProvider.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceProvider.cs @@ -32,11 +32,11 @@ public sealed class ServiceProvider : IServiceProvider, IDisposable, IAsyncDispo internal ServiceProvider(IEnumerable serviceDescriptors, ServiceProviderOptions options) { + Root = new ServiceProviderEngineScope(this, isRootScope: true); _engine = GetEngine(); _createServiceAccessor = CreateServiceAccessor; _realizedServices = new ConcurrentDictionary>(); - Root = new ServiceProviderEngineScope(this, isRootScope: true); CallSiteFactory = new CallSiteFactory(serviceDescriptors); // The list of built in services that aren't part of the list of service descriptors // keep this in sync with CallSiteFactory.IsService From 4da743803bfd094f5dd3833670fba8da8bc7ea5c Mon Sep 17 00:00:00 2001 From: Eric Erhardt Date: Thu, 8 Jul 2021 11:00:01 -0500 Subject: [PATCH 2/3] add a comment explaining the ordering --- .../src/ServiceProvider.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceProvider.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceProvider.cs index d22599c4a492ff..afe118acf79093 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceProvider.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceProvider.cs @@ -32,6 +32,7 @@ public sealed class ServiceProvider : IServiceProvider, IDisposable, IAsyncDispo internal ServiceProvider(IEnumerable serviceDescriptors, ServiceProviderOptions options) { + // note that Root needs to be set before calling GetEngine(), because the engine may need to access Root Root = new ServiceProviderEngineScope(this, isRootScope: true); _engine = GetEngine(); _createServiceAccessor = CreateServiceAccessor; From 7c3ef6c9fb8791d543e914548fdb680369625129 Mon Sep 17 00:00:00 2001 From: Eric Erhardt Date: Thu, 8 Jul 2021 11:15:26 -0500 Subject: [PATCH 3/3] Add a debug assert that we shouldn't get exceptions from the background compilation thread --- .../src/ServiceLookup/DynamicServiceProviderEngine.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/DynamicServiceProviderEngine.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/DynamicServiceProviderEngine.cs index ee124f31be8eff..0237e8ad096b74 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/DynamicServiceProviderEngine.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/DynamicServiceProviderEngine.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Diagnostics; using System.Threading; namespace Microsoft.Extensions.DependencyInjection.ServiceLookup @@ -37,6 +38,8 @@ public override Func RealizeService(ServiceC catch (Exception ex) { DependencyInjectionEventSource.Log.ServiceRealizationFailed(ex); + + Debug.Fail($"We should never get exceptions from the background compilation.{Environment.NewLine}{ex}"); } }, null);