Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1279,6 +1279,14 @@
<Build Solution="Checked|x64" Project="false" />
<Build Solution="Checked|x86" Project="false" />
</Project>
<Project Path="tests/ArbitraryDiagnosticEventPatternTestSite/ArbitraryDiagnosticEventPatternTestSite.csproj">
<BuildType Solution="Checked|*" Project="Debug" />
<Build Solution="*|arm" Project="false" />
<Build Solution="*|arm64" Project="false" />
<Build Solution="Checked|Any CPU" Project="false" />
<Build Solution="Checked|x64" Project="false" />
<Build Solution="Checked|x86" Project="false" />
</Project>
<Project Path="tests/BuildWebHostInvalidSignature/BuildWebHostInvalidSignature.csproj">
<BuildType Solution="Checked|*" Project="Debug" />
<Build Solution="*|arm" Project="false" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ private static TimeSpan SetupDefaultTimeout()
TimeSpan? waitTimeout = null,
bool stopApplication = true,
Action<object>? configureHostBuilder = null,
Action<Exception?>? entrypointCompleted = null)
Action<Exception?>? entrypointCompleted = null,
IDictionary<string, Action<object?>>? arbitraryActions = null)
{
if (assembly.EntryPoint is null)
{
Expand All @@ -89,7 +90,7 @@ private static TimeSpan SetupDefaultTimeout()
return null;
}

return args => new HostingListener(args, assembly.EntryPoint, waitTimeout ?? s_defaultWaitTimeout, stopApplication, configureHostBuilder, entrypointCompleted).CreateHost();
return args => new HostingListener(args, assembly.EntryPoint, waitTimeout ?? s_defaultWaitTimeout, stopApplication, configureHostBuilder, entrypointCompleted, arbitraryActions).CreateHost();
}

private static Func<string[], T>? ResolveFactory<T>(Assembly assembly, string name)
Expand Down Expand Up @@ -204,16 +205,25 @@ private sealed class HostingListener : IObserver<DiagnosticListener>, IObserver<
private IDisposable? _disposable;
private readonly Action<object>? _configure;
private readonly Action<Exception?>? _entrypointCompleted;
private readonly IDictionary<string, Action<object?>>? _arbitraryActions;
private static readonly AsyncLocal<HostingListener> _currentListener = new();

public HostingListener(string[] args, MethodInfo entryPoint, TimeSpan waitTimeout, bool stopApplication, Action<object>? configure, Action<Exception?>? entrypointCompleted)
public HostingListener(
string[] args,
MethodInfo entryPoint,
TimeSpan waitTimeout,
bool stopApplication,
Action<object>? configure,
Action<Exception?>? entrypointCompleted,
IDictionary<string, Action<object?>>? arbitraryActions)
{
_args = args;
_entryPoint = entryPoint;
_waitTimeout = waitTimeout;
_stopApplication = stopApplication;
_configure = configure;
_entrypointCompleted = entrypointCompleted;
_arbitraryActions = arbitraryActions;
}

public object CreateHost()
Expand Down Expand Up @@ -332,8 +342,7 @@ public void OnNext(KeyValuePair<string, object?> value)
{
_configure?.Invoke(value.Value!);
}

if (value.Key == "HostBuilt")
else if (value.Key == "HostBuilt")
{
_hostTcs.TrySetResult(value.Value!);

Expand All @@ -343,6 +352,10 @@ public void OnNext(KeyValuePair<string, object?> value)
ThrowHostAborted();
}
}
else if (_arbitraryActions?.TryGetValue(value.Key, out var arbitraryAction) == true)
{
arbitraryAction.Invoke(value.Value);
Comment thread
Youssef1313 marked this conversation as resolved.
}
Comment thread
Youssef1313 marked this conversation as resolved.
Comment thread
Youssef1313 marked this conversation as resolved.
Comment thread
Youssef1313 marked this conversation as resolved.
}

// HostFactoryResolver is used by tools that explicitly don't want to reference Microsoft.Extensions.Hosting assemblies.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>$(NetCoreAppCurrent);$(NetFrameworkCurrent)</TargetFrameworks>
<EnableDefaultItems>true</EnableDefaultItems>
<OutputType>Exe</OutputType>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\MockHostTypes\MockHostTypes.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics;
using Microsoft.Extensions.Hosting;

namespace ArbitraryDiagnosticEventPatternTestSite
{
public class Program
{
public static void Main(string[] args)
{
using var listener = new DiagnosticListener("Microsoft.Extensions.Hosting");
listener.Write("CustomEvent", 42);

new HostBuilder().Build().Dispose();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using Microsoft.Extensions.Configuration;
using MockHostTypes;
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Threading;
Expand Down Expand Up @@ -163,6 +164,57 @@ void ConfigureHostBuilder(object hostBuilder)
Assert.True(called);
}

[ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsMultithreadingSupported))]
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(ArbitraryDiagnosticEventPatternTestSite.Program))]
[InlineData(true)]
[InlineData(false)]
public void ArbitraryActionsCustomEventCallbackIsCalled(bool stopApplication)
{
using var callbackCalled = new ManualResetEventSlim(false);
object? callbackValue = null;
void CustomCallback(object? value)
{
callbackValue = value;
callbackCalled.Set();
}

var arbitraryActions = new Dictionary<string, Action<object?>>
{
["CustomEvent"] = CustomCallback
};

var factory = HostFactoryResolver.ResolveHostFactory(
typeof(ArbitraryDiagnosticEventPatternTestSite.Program).Assembly,
waitTimeout: s_WaitTimeout,
stopApplication: stopApplication,
arbitraryActions: arbitraryActions);

Assert.NotNull(factory);
using var host = Assert.IsAssignableFrom<IHost>(factory(Array.Empty<string>()));
Assert.True(callbackCalled.Wait(s_WaitTimeout));
Assert.Equal(42, callbackValue);
}

[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsMultithreadingSupported))]
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(ArbitraryDiagnosticEventPatternTestSite.Program))]
public void ArbitraryActionsExceptionIsPropagated()
{
var arbitraryActions = new Dictionary<string, Action<object?>>
{
["CustomEvent"] = _ => throw new InvalidOperationException("arbitrary action failed")
};

var factory = HostFactoryResolver.ResolveHostFactory(
typeof(ArbitraryDiagnosticEventPatternTestSite.Program).Assembly,
waitTimeout: s_WaitTimeout,
stopApplication: true,
arbitraryActions: arbitraryActions);

Assert.NotNull(factory);
var exception = Assert.Throws<InvalidOperationException>(() => factory(Array.Empty<string>()));
Assert.Equal("arbitrary action failed", exception.Message);
}

[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsMultithreadingSupported))]
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(NoSpecialEntryPointPattern.Program))]
public void NoSpecialEntryPointPatternBuildsThenThrowsCallsEntryPointCompletedCallback()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
<ProjectReference Include="CreateHostBuilderPatternTestSite\CreateHostBuilderPatternTestSite.csproj" />
<ProjectReference Include="CreateWebHostBuilderInvalidSignature\CreateWebHostBuilderInvalidSignature.csproj" />
<ProjectReference Include="CreateWebHostBuilderPatternTestSite\CreateWebHostBuilderPatternTestSite.csproj" />
<ProjectReference Include="ArbitraryDiagnosticEventPatternTestSite\ArbitraryDiagnosticEventPatternTestSite.csproj" />
<ProjectReference Include="NoSpecialEntryPointPattern\NoSpecialEntryPointPattern.csproj" />
<ProjectReference Include="NoSpecialEntryPointPatternBuildsThenThrows\NoSpecialEntryPointPatternBuildsThenThrows.csproj" />
<ProjectReference Include="NoSpecialEntryPointPatternThrows\NoSpecialEntryPointPatternThrows.csproj" />
Expand Down
Loading