未验证 提交 2a011f80 编写于 作者: D David Fowler 提交者: GitHub

Scope events to the execution of the entry point (#54090)

* Scope events to the execution of the entry point
- Today we're using the global event source and events that fire in the app domain get captured and this can result in capturing the wrong instances. This fix uses an async local to scope the events for the HostingEventListener to the execution of the application's entry point.
- Removed the RemoteExecutor as a result of this change
- Remove RequirementsMet property
上级 23336b89
......@@ -180,6 +180,7 @@ private class HostingListener : IObserver<DiagnosticListener>, IObserver<KeyValu
private IDisposable? _disposable;
private Action<object>? _configure;
private Action<Exception?>? _entrypointCompleted;
private static readonly AsyncLocal<HostingListener> _currentListener = new();
public HostingListener(string[] args, MethodInfo entryPoint, TimeSpan waitTimeout, bool stopApplication, Action<object>? configure, Action<Exception?>? entrypointCompleted)
{
......@@ -193,6 +194,10 @@ public HostingListener(string[] args, MethodInfo entryPoint, TimeSpan waitTimeou
public object CreateHost()
{
// Set the async local to the instance of the HostingListener so we can filter events that
// aren't scoped to this execution of the entry point.
_currentListener.Value = this;
using var subscription = DiagnosticListener.AllListeners.Subscribe(this);
// Kick off the entry point on a new thread so we don't block the current one
......@@ -279,6 +284,12 @@ public void OnError(Exception error)
public void OnNext(DiagnosticListener value)
{
if (_currentListener.Value != this)
{
// Ignore events that aren't for this listener
return;
}
if (value.Name == "Microsoft.Extensions.Hosting")
{
_disposable = value.Subscribe(this);
......@@ -287,6 +298,12 @@ public void OnNext(DiagnosticListener value)
public void OnNext(KeyValuePair<string, object?> value)
{
if (_currentListener.Value != this)
{
// Ignore events that aren't for this listener
return;
}
if (value.Key == "HostBuilding")
{
_configure?.Invoke(value.Value!);
......
......@@ -6,15 +6,12 @@
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Threading;
using Microsoft.DotNet.RemoteExecutor;
using Xunit;
namespace Microsoft.Extensions.Hosting.Tests
{
public class HostFactoryResolverTests
{
public static bool RequirementsMet => RemoteExecutor.IsSupported && PlatformDetection.IsThreadingSupported;
private static readonly TimeSpan s_WaitTimeout = TimeSpan.FromSeconds(20);
[Fact]
......@@ -126,162 +123,132 @@ public void CreateHostBuilderPattern__Invalid_CantFindHostBuilder()
Assert.Null(factory);
}
[ConditionalFact(nameof(RequirementsMet))]
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))]
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(CreateHostBuilderInvalidSignature.Program))]
public void CreateHostBuilderPattern__Invalid_CantFindServiceProvider()
{
using var _ = RemoteExecutor.Invoke(() =>
{
var factory = HostFactoryResolver.ResolveServiceProviderFactory(typeof(CreateHostBuilderInvalidSignature.Program).Assembly, s_WaitTimeout);
var factory = HostFactoryResolver.ResolveServiceProviderFactory(typeof(CreateHostBuilderInvalidSignature.Program).Assembly, s_WaitTimeout);
Assert.NotNull(factory);
Assert.Throws<InvalidOperationException>(() => factory(Array.Empty<string>()));
});
Assert.NotNull(factory);
Assert.Throws<InvalidOperationException>(() => factory(Array.Empty<string>()));
}
[ConditionalFact(nameof(RequirementsMet))]
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))]
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(NoSpecialEntryPointPattern.Program))]
public void NoSpecialEntryPointPattern()
{
using var _ = RemoteExecutor.Invoke(() =>
{
var factory = HostFactoryResolver.ResolveServiceProviderFactory(typeof(NoSpecialEntryPointPattern.Program).Assembly, s_WaitTimeout);
var factory = HostFactoryResolver.ResolveServiceProviderFactory(typeof(NoSpecialEntryPointPattern.Program).Assembly, s_WaitTimeout);
Assert.NotNull(factory);
Assert.IsAssignableFrom<IServiceProvider>(factory(Array.Empty<string>()));
});
Assert.NotNull(factory);
Assert.IsAssignableFrom<IServiceProvider>(factory(Array.Empty<string>()));
}
[ConditionalFact(nameof(RequirementsMet))]
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))]
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(NoSpecialEntryPointPattern.Program))]
public void NoSpecialEntryPointPatternHostBuilderConfigureHostBuilderCallbackIsCalled()
{
using var _ = RemoteExecutor.Invoke(() =>
bool called = false;
void ConfigureHostBuilder(object hostBuilder)
{
bool called = false;
void ConfigureHostBuilder(object hostBuilder)
{
Assert.IsAssignableFrom<IHostBuilder>(hostBuilder);
called = true;
}
var factory = HostFactoryResolver.ResolveHostFactory(typeof(NoSpecialEntryPointPattern.Program).Assembly, waitTimeout: s_WaitTimeout, configureHostBuilder: ConfigureHostBuilder);
Assert.NotNull(factory);
Assert.IsAssignableFrom<IHost>(factory(Array.Empty<string>()));
Assert.True(called);
});
Assert.IsAssignableFrom<IHostBuilder>(hostBuilder);
called = true;
}
var factory = HostFactoryResolver.ResolveHostFactory(typeof(NoSpecialEntryPointPattern.Program).Assembly, waitTimeout: s_WaitTimeout, configureHostBuilder: ConfigureHostBuilder);
Assert.NotNull(factory);
Assert.IsAssignableFrom<IHost>(factory(Array.Empty<string>()));
Assert.True(called);
}
[ConditionalFact(nameof(RequirementsMet))]
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))]
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(NoSpecialEntryPointPattern.Program))]
public void NoSpecialEntryPointPatternBuildsThenThrowsCallsEntryPointCompletedCallback()
{
using var _ = RemoteExecutor.Invoke(() =>
var wait = new ManualResetEventSlim(false);
Exception? entryPointException = null;
void EntryPointCompleted(Exception? exception)
{
var wait = new ManualResetEventSlim(false);
Exception? entryPointException = null;
void EntryPointCompleted(Exception? exception)
{
entryPointException = exception;
wait.Set();
}
var factory = HostFactoryResolver.ResolveHostFactory(typeof(NoSpecialEntryPointPattern.Program).Assembly, waitTimeout: s_WaitTimeout, stopApplication: false, entrypointCompleted: EntryPointCompleted);
Assert.NotNull(factory);
Assert.IsAssignableFrom<IHost>(factory(Array.Empty<string>()));
Assert.True(wait.Wait(s_WaitTimeout));
Assert.Null(entryPointException);
});
entryPointException = exception;
wait.Set();
}
var factory = HostFactoryResolver.ResolveHostFactory(typeof(NoSpecialEntryPointPattern.Program).Assembly, waitTimeout: s_WaitTimeout, stopApplication: false, entrypointCompleted: EntryPointCompleted);
Assert.NotNull(factory);
Assert.IsAssignableFrom<IHost>(factory(Array.Empty<string>()));
Assert.True(wait.Wait(s_WaitTimeout));
Assert.Null(entryPointException);
}
[ConditionalFact(nameof(RequirementsMet))]
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))]
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(NoSpecialEntryPointPatternBuildsThenThrows.Program))]
public void NoSpecialEntryPointPatternBuildsThenThrowsCallsEntryPointCompletedCallbackWithException()
{
using var _ = RemoteExecutor.Invoke(() =>
var wait = new ManualResetEventSlim(false);
Exception? entryPointException = null;
void EntryPointCompleted(Exception? exception)
{
var wait = new ManualResetEventSlim(false);
Exception? entryPointException = null;
void EntryPointCompleted(Exception? exception)
{
entryPointException = exception;
wait.Set();
}
var factory = HostFactoryResolver.ResolveHostFactory(typeof(NoSpecialEntryPointPatternBuildsThenThrows.Program).Assembly, waitTimeout: s_WaitTimeout, stopApplication: false, entrypointCompleted: EntryPointCompleted);
Assert.NotNull(factory);
Assert.IsAssignableFrom<IHost>(factory(Array.Empty<string>()));
Assert.True(wait.Wait(s_WaitTimeout));
Assert.NotNull(entryPointException);
});
entryPointException = exception;
wait.Set();
}
var factory = HostFactoryResolver.ResolveHostFactory(typeof(NoSpecialEntryPointPatternBuildsThenThrows.Program).Assembly, waitTimeout: s_WaitTimeout, stopApplication: false, entrypointCompleted: EntryPointCompleted);
Assert.NotNull(factory);
Assert.IsAssignableFrom<IHost>(factory(Array.Empty<string>()));
Assert.True(wait.Wait(s_WaitTimeout));
Assert.NotNull(entryPointException);
}
[ConditionalFact(nameof(RequirementsMet))]
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))]
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(NoSpecialEntryPointPatternThrows.Program))]
public void NoSpecialEntryPointPatternThrows()
{
using var _ = RemoteExecutor.Invoke(() =>
{
var factory = HostFactoryResolver.ResolveServiceProviderFactory(typeof(NoSpecialEntryPointPatternThrows.Program).Assembly, s_WaitTimeout);
var factory = HostFactoryResolver.ResolveServiceProviderFactory(typeof(NoSpecialEntryPointPatternThrows.Program).Assembly, s_WaitTimeout);
Assert.NotNull(factory);
Assert.Throws<Exception>(() => factory(Array.Empty<string>()));
});
Assert.NotNull(factory);
Assert.Throws<Exception>(() => factory(Array.Empty<string>()));
}
[ConditionalFact(nameof(RequirementsMet))]
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))]
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(NoSpecialEntryPointPatternExits.Program))]
public void NoSpecialEntryPointPatternExits()
{
using var _ = RemoteExecutor.Invoke(() =>
{
var factory = HostFactoryResolver.ResolveServiceProviderFactory(typeof(NoSpecialEntryPointPatternExits.Program).Assembly, s_WaitTimeout);
var factory = HostFactoryResolver.ResolveServiceProviderFactory(typeof(NoSpecialEntryPointPatternExits.Program).Assembly, s_WaitTimeout);
Assert.NotNull(factory);
Assert.Throws<InvalidOperationException>(() => factory(Array.Empty<string>()));
});
Assert.NotNull(factory);
Assert.Throws<InvalidOperationException>(() => factory(Array.Empty<string>()));
}
[ConditionalFact(nameof(RequirementsMet))]
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))]
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(NoSpecialEntryPointPatternHangs.Program))]
public void NoSpecialEntryPointPatternHangs()
{
using var _ = RemoteExecutor.Invoke(() =>
{
var factory = HostFactoryResolver.ResolveServiceProviderFactory(typeof(NoSpecialEntryPointPatternHangs.Program).Assembly, s_WaitTimeout);
var factory = HostFactoryResolver.ResolveServiceProviderFactory(typeof(NoSpecialEntryPointPatternHangs.Program).Assembly, s_WaitTimeout);
Assert.NotNull(factory);
Assert.Throws<InvalidOperationException>(() => factory(Array.Empty<string>()));
});
Assert.NotNull(factory);
Assert.Throws<InvalidOperationException>(() => factory(Array.Empty<string>()));
}
[ConditionalFact(nameof(RequirementsMet))]
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))]
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(NoSpecialEntryPointPatternMainNoArgs.Program))]
public void NoSpecialEntryPointPatternMainNoArgs()
{
using var _ = RemoteExecutor.Invoke(() =>
{
var factory = HostFactoryResolver.ResolveServiceProviderFactory(typeof(NoSpecialEntryPointPatternMainNoArgs.Program).Assembly, s_WaitTimeout);
var factory = HostFactoryResolver.ResolveServiceProviderFactory(typeof(NoSpecialEntryPointPatternMainNoArgs.Program).Assembly, s_WaitTimeout);
Assert.NotNull(factory);
Assert.IsAssignableFrom<IServiceProvider>(factory(Array.Empty<string>()));
});
Assert.NotNull(factory);
Assert.IsAssignableFrom<IServiceProvider>(factory(Array.Empty<string>()));
}
[ConditionalFact(nameof(RequirementsMet))]
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))]
public void TopLevelStatements()
{
using var _ = RemoteExecutor.Invoke(() =>
{
var assembly = Assembly.Load("TopLevelStatements");
var factory = HostFactoryResolver.ResolveServiceProviderFactory(assembly, s_WaitTimeout);
var assembly = Assembly.Load("TopLevelStatements");
var factory = HostFactoryResolver.ResolveServiceProviderFactory(assembly, s_WaitTimeout);
Assert.NotNull(factory);
Assert.IsAssignableFrom<IServiceProvider>(factory(Array.Empty<string>()));
});
Assert.NotNull(factory);
Assert.IsAssignableFrom<IServiceProvider>(factory(Array.Empty<string>()));
}
}
}
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>$(NetCoreAppCurrent);net461</TargetFrameworks>
<IncludeRemoteExecutor>true</IncludeRemoteExecutor>
</PropertyGroup>
<ItemGroup>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册