Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
660d667
Add OTel telemetry to AOT library entrypoint with trace correlation
baronfel Jun 1, 2026
1267a00
Remove redundant Activity.Stop() call
baronfel Jun 1, 2026
d9f7dec
Enable Azure Monitor exporter in AOT mode
baronfel Jun 1, 2026
0d3d4fe
Enable CurrentSessionId and common properties in AOT mode
baronfel Jun 1, 2026
f8a824c
Remove unnecessary NativeWrapper alias, use fully-qualified Constants
baronfel Jun 1, 2026
f5e34bd
Use CliFolderPathCalculatorCore for storage directory in both paths
baronfel Jun 1, 2026
1b9d857
Enable runtime instrumentation in AOT mode
baronfel Jun 1, 2026
efba412
Make TelemetryCommonProperties AOT-compatible
baronfel Jun 1, 2026
17c6b19
Make CliFolderPathCalculator AOT-compatible instead of using Core var…
baronfel Jun 1, 2026
e79f768
Use FrozenDictionary for common properties in both AOT and managed
baronfel Jun 1, 2026
e5600f4
Enable disk logging in AOT mode
baronfel Jun 1, 2026
35fd2b5
Reference Microsoft.DotNet.Configurer from AOT, remove CLI_AOT guards
baronfel Jun 1, 2026
692c31b
Remove TelemetryCommonProperties duplication — use managed impl in AOT
baronfel Jun 1, 2026
a84fedc
Remove all CLI_AOT guards from TelemetryClient.cs
baronfel Jun 1, 2026
7153f10
Minimize stylistic differences in TelemetryClient and TelemetryCommon…
baronfel Jun 1, 2026
4d89ae2
odds and ends to make native tracing work in local testing
baronfel Jun 1, 2026
66afcab
respond to some feedback, add more AOT-side spans
baronfel Jun 1, 2026
6dbe5fa
make ProcessReaper platform-aware and use cswin32 API for ctrl handler
baronfel Jun 2, 2026
ab9a5ab
fix ifdef bounds for unix processreaper
baronfel Jun 2, 2026
76f0492
use new BCL apis to prevent the need to PInvoke to libc
baronfel Jun 2, 2026
220e661
adjust tests to account for native entrypoint logic changes
baronfel Jun 3, 2026
118b477
fix parser exception handling to align with managed parser, so we can…
baronfel Jun 3, 2026
7c4aeba
Address some code review feedback, fix test output reporting
baronfel Jun 4, 2026
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
4 changes: 2 additions & 2 deletions eng/build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ if ($test) { $arguments += " -test" }
if ($pack) {
$arguments += " -pack"
if (-not $skipCrossgen) { $arguments += " /p:SkipUsingCrossgen=false" }
if (-not $skipInstallers) { $arguments += " /p:SkipBuildingInstallers=false" }
if (-not $skipInstallers) { $arguments += " /p:SkipBuildingInstallers=false /p:SkipBuildingArchives=false" }

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a convenience thing that I added because creating the tarballs was painful on the inner loop

} else {
$arguments += " /p:SkipUsingCrossgen=true /p:SkipBuildingInstallers=true"
$arguments += " /p:SkipUsingCrossgen=true /p:SkipBuildingInstallers=true /p:SkipBuildingArchives=true "
}

if ($properties) { $arguments += " " + ($properties -join " ") }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@

<ItemGroup>
<InternalsVisibleTo Include="dotnet" />
<InternalsVisibleTo Include="dotnet-aot" />
<InternalsVisibleTo Include="dotnet-aot.Tests" />
Comment thread
baronfel marked this conversation as resolved.
<InternalsVisibleTo Include="dotnet-watch" />
<InternalsVisibleTo Include="dotnet.Tests" />
</ItemGroup>
Expand Down
18 changes: 0 additions & 18 deletions src/Cli/Microsoft.DotNet.Cli.Utils/NativeMethods.cs

This file was deleted.

1 change: 1 addition & 0 deletions src/Cli/Microsoft.DotNet.Cli.Utils/NativeMethods.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ SafeArrayPutElement
SafeArrayUnlock
SendMessageTimeout
SetInformationJobObject
SetConsoleCtrlHandler
WinVerifyTrust

// Interfaces
Expand Down
25 changes: 10 additions & 15 deletions src/Cli/Microsoft.DotNet.Cli.Utils/ProcessReaper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ internal class ProcessReaper : IDisposable
{
private readonly Process _process;

#if TARGET_WINDOWS
private sealed class WindowsProcessReaper : ProcessReaper
{
public WindowsProcessReaper(Process process) : base(process)
Expand All @@ -44,15 +45,11 @@ public WindowsProcessReaper(Process process) : base(process)
EnableWindowsCtrlCHandling();
}

private static void EnableWindowsCtrlCHandling()
private unsafe static void EnableWindowsCtrlCHandling()
{
SetConsoleCtrlHandler(null, false);

[DllImport("kernel32.dll", SetLastError = true)]
static extern bool SetConsoleCtrlHandler(Delegate? handler, bool add);
PInvoke.SetConsoleCtrlHandler(null, false);
}

#if TARGET_WINDOWS
private SafeWaitHandle? _job;

public override void NotifyProcessStarted()
Expand Down Expand Up @@ -124,9 +121,10 @@ public override void Dispose()

base.Dispose();
}
#endif
}
#endif

#if !TARGET_WINDOWS
private sealed class UnixProcessReaper : ProcessReaper
{
private readonly Mutex _shutdownMutex;
Expand Down Expand Up @@ -170,31 +168,28 @@ private void HandleProcessExit(object? sender, EventArgs args)
_shutdownMutex?.WaitOne();

#if NET
if (!_process.WaitForExit(0) && NativeMethods.Posix.kill(processId, NativeMethods.Posix.SIGTERM) != 0)
if (!_process.WaitForExit(0) && _process.SafeHandle.Signal(PosixSignal.SIGTERM))
{
// Couldn't send the signal, don't wait
return;
}
#endif

// If SIGTERM was ignored by the target, then we'll still wait
_process.WaitForExit();

Environment.ExitCode = _process.ExitCode;
}
}
#endif

/// <inheritdoc cref="ProcessReaper(Process)"/>
public static ProcessReaper Create(Process process)
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
#if TARGET_WINDOWS
return new WindowsProcessReaper(process);
}
else
{
#else
return new UnixProcessReaper(process);
}
#endif
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

[assembly: AssemblyMetadataAttribute("Serviceable", "True")]
[assembly: InternalsVisibleTo("dotnet, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("dotnet-aot, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("dotnet-aot.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("dotnet.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("dotnet-run.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.DotNet.Configurer, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
Expand Down
18 changes: 16 additions & 2 deletions src/Cli/dotnet-aot/AotSourceFiles.props
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,22 @@
<Compile Include="$(MSBuildThisFileDirectory)..\dotnet\CommandParsingException.cs" Link="CommandParsingException.cs" />
<Compile Include="$(MSBuildThisFileDirectory)..\dotnet\CommandNotAvailableInAotException.cs" Link="CommandNotAvailableInAotException.cs" />
<Compile Include="$(RepoRoot)src\Common\EnvironmentVariableNames.cs" LinkBase="Common" />
<Compile Include="$(RepoRoot)src\Common\CompileOptions.cs" LinkBase="Common" />
<Compile Include="$(RepoRoot)src\Common\CliFolderPathCalculatorCore.cs" LinkBase="Common" />
<Compile Include="$(MSBuildThisFileDirectory)..\dotnet\Telemetry\TelemetryClient.cs" Link="TelemetryClient.cs" />
<Compile Include="$(MSBuildThisFileDirectory)..\dotnet\Telemetry\TelemetryCommonProperties.cs" Link="TelemetryCommonProperties.cs" />
<Compile Include="$(MSBuildThisFileDirectory)..\dotnet\Telemetry\ITelemetryClient.cs" Link="ITelemetryClient.cs" />
<Compile Include="$(MSBuildThisFileDirectory)..\dotnet\Telemetry\TelemetryDiskLogger.cs" Link="TelemetryDiskLogger.cs" />
<Compile Include="$(MSBuildThisFileDirectory)..\dotnet\Telemetry\IDockerContainerDetector.cs" Link="Telemetry\IDockerContainerDetector.cs" />
<Compile Include="$(MSBuildThisFileDirectory)..\dotnet\Telemetry\DockerContainerDetectorForTelemetry.cs" Link="Telemetry\DockerContainerDetectorForTelemetry.cs" />
<Compile Include="$(MSBuildThisFileDirectory)..\dotnet\Telemetry\ILLMEnvironmentDetector.cs" Link="Telemetry\ILLMEnvironmentDetector.cs" />
<Compile Include="$(MSBuildThisFileDirectory)..\dotnet\Telemetry\LLMEnvironmentDetectorForTelemetry.cs" Link="Telemetry\LLMEnvironmentDetectorForTelemetry.cs" />
<Compile Include="$(MSBuildThisFileDirectory)..\dotnet\Telemetry\MacAddressGetter.cs" Link="Telemetry\MacAddressGetter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)..\dotnet\Telemetry\DevDeviceIDGetter.cs" Link="Telemetry\DevDeviceIDGetter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)..\dotnet\Telemetry\ExternalTelemetryProperties.cs" Link="Telemetry\ExternalTelemetryProperties.cs" />
<Compile Include="$(MSBuildThisFileDirectory)..\dotnet\Extensions\ActivityExtensions.cs" Link="ActivityExtensions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)..\dotnet\Extensions\ParseResultExtensions.cs" Link="ParseResultExtensions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)..\Microsoft.TemplateEngine.Cli\SymbolExtensions.cs" Link="SymbolExtensions.cs" />
Comment on lines +34 to +49

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bunch of the telemetry-related code as well as a few extensions files that are used in computing some of the telemetry data.

</ItemGroup>

<!-- Common AOT scaffolding: generated string resources referenced by command sources. -->
Expand All @@ -44,7 +60,6 @@
<Compile Include="$(MSBuildThisFileDirectory)..\dotnet\SlnFileFactory.cs" Link="SlnFileFactory.cs" />
<Compile Include="$(MSBuildThisFileDirectory)..\dotnet\SlnfFileHelper.cs" Link="SlnfFileHelper.cs" />
<Compile Include="$(MSBuildThisFileDirectory)..\dotnet\MsbuildProject.cs" Link="MsbuildProject.cs" />
<Compile Include="$(MSBuildThisFileDirectory)..\Microsoft.DotNet.FileBasedPrograms\ProjectLocator.cs" Link="ProjectLocator.cs" />

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These two removals are because I added a project reference to the actual ProjectTools/FileBasedPrograms code as part of this work, so there were build-time type-load conflicts.

<Compile Include="$(MSBuildThisFileDirectory)..\dotnet\Commands\Solution\SolutionCommandParser.cs" Link="Commands\Solution\SolutionCommandParser.cs" />
<Compile Include="$(MSBuildThisFileDirectory)..\dotnet\Commands\Solution\SolutionArgumentValidator.cs" Link="Commands\Solution\SolutionArgumentValidator.cs" />
<Compile Include="$(MSBuildThisFileDirectory)..\dotnet\Commands\Solution\List\SolutionListCommand.cs" Link="Commands\Solution\List\SolutionListCommand.cs" />
Expand All @@ -54,7 +69,6 @@

<!-- 'dotnet sln' command: command-specific dependencies. -->
<ItemGroup>
<EmbeddedResource Include="$(MSBuildThisFileDirectory)..\Microsoft.DotNet.FileBasedPrograms\FileBasedProgramsResources.resx" Link="FileBasedProgramsResources.resx" GenerateSource="true" Namespace="Microsoft.DotNet.FileBasedPrograms" />
<ProjectReference Include="$(MSBuildThisFileDirectory)..\Microsoft.DotNet.Cli.Definitions\Microsoft.DotNet.Cli.Definitions.csproj" GlobalPropertiesToRemove="PublishDir" />
<PackageReference Include="Microsoft.VisualStudio.SolutionPersistence" />
</ItemGroup>
Expand Down
31 changes: 29 additions & 2 deletions src/Cli/dotnet-aot/ManagedHost.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

extern alias NativeWrapper;

using System.Diagnostics;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.NativeWrapper;
using NativeConstants = NativeWrapper::Microsoft.DotNet.NativeWrapper.Constants;

namespace Microsoft.DotNet.Cli;

Expand Down Expand Up @@ -122,6 +127,7 @@ public static int RunApp(string hostPath, string dotnetRoot, string hostfxrPath,

try
{
var _init = Activities.Source.StartActivity("aot-hostfxr-initialization");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit, _ is for member variables only.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be init, not _init.

StatusCode result = Interop.hostfxr_initialize_for_dotnet_command_line(
args.Length,
args,
Expand All @@ -130,8 +136,15 @@ public static int RunApp(string hostPath, string dotnetRoot, string hostfxrPath,

if (result != StatusCode.Success && handle == 0)
{
_init?.SetStatus(ActivityStatusCode.Error);
_init?.Stop();
throw new InvalidOperationException($"hostfxr_initialize_for_dotnet_command_line failed. Status: {result} (0x{(uint)result:X8})");
}
else
{
_init?.SetStatus(ActivityStatusCode.Ok);
_init?.Stop();
}

try
{
Expand All @@ -141,14 +154,28 @@ public static int RunApp(string hostPath, string dotnetRoot, string hostfxrPath,
if (!string.IsNullOrEmpty(hostfxrPath))
{
StatusCode propertyResult = Interop.hostfxr_set_runtime_property_value(
handle, Constants.RuntimeProperty.HostFxrPath, hostfxrPath);
handle, NativeConstants.RuntimeProperty.HostFxrPath, hostfxrPath);
if (propertyResult != StatusCode.Success)
{
throw new InvalidOperationException(
$"hostfxr_set_runtime_property_value failed for {Constants.RuntimeProperty.HostFxrPath}. Status: {propertyResult} (0x{(uint)propertyResult:X8})");
$"hostfxr_set_runtime_property_value failed for {NativeConstants.RuntimeProperty.HostFxrPath}. Status: {propertyResult} (0x{(uint)propertyResult:X8})");
}
}

// Propagate OTel trace context to the managed CLI so that its spans
// become children of the AOT-side main activity.
if (Activity.Current is { } currentActivity)
{
string traceparent = $"00-{currentActivity.Context.TraceId}-{currentActivity.Context.SpanId}-{(currentActivity.Context.TraceFlags == ActivityTraceFlags.Recorded ? "01" : "00")}";
Interop.hostfxr_set_runtime_property_value(handle, Activities.TRACEPARENT, traceparent);

if (!string.IsNullOrEmpty(currentActivity.Context.TraceState))
{
Interop.hostfxr_set_runtime_property_value(handle, Activities.TRACESTATE, currentActivity.Context.TraceState);
Comment on lines +167 to +174

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted to ensure that if we were tracking OTel activities, the 'inner' managed call would recognize that and configure itself as a 'child' of the caller. To do this, I needed to somehow communicate the 'trace parent' and 'trace state' concepts to the child.

We already had a way of pulling traceparent/tracestate data from env vars, but I didn't want the managed host to set env vars - that is 'leaky' to other processes that are spawned from the managed cli. These runtime properties seemed like a nice compromise.

}
}

using var invoke = Activities.Source.StartActivity("aot-coreclr-invocation");
StatusCode appResult = Interop.hostfxr_run_app(handle);
return (int)appResult;
}
Expand Down
107 changes: 75 additions & 32 deletions src/Cli/dotnet-aot/NativeEntryPoint.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.DotNet.Cli.Extensions;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.Cli.Utils.Extensions;
using Microsoft.DotNet.Cli.Telemetry;
using System.Diagnostics;
using Microsoft.DotNet.NativeWrapper;

namespace Microsoft.DotNet.Cli;
Expand Down Expand Up @@ -40,49 +43,89 @@ internal static int ExecuteCore(
string hostPath, string dotnetRoot, string sdkDir,
string hostfxrPath, string[] args)
{
// Make hostfxr discoverable for NativeWrapper P/Invokes (required on non-Windows)
if (!string.IsNullOrEmpty(hostfxrPath))
DateTime preTelemetry = DateTime.UtcNow;
// Initialize OTel telemetry (mirrors managed Program.cs setup).
var telemetryClient = new TelemetryClient(sessionId: null);
DateTime postTelemetry = DateTime.UtcNow;
var mainActivity = Activities.Source.StartActivity("native-entrypoint", TelemetryClient.ActivityKind, TelemetryClient.ParentActivityContext);
Comment thread
baronfel marked this conversation as resolved.
Comment thread
baronfel marked this conversation as resolved.

// Backdate the activity start to process start time for accurate timing.
if (mainActivity is not null)
{
AppContext.SetData("HOSTFXR_PATH", hostfxrPath);
mainActivity.SetStartTime(Process.GetCurrentProcess().StartTime.ToUniversalTime());
using var telemetryActivity = Activities.Source.StartActivity("aot-telemetry-setup");
telemetryActivity?.SetStartTime(preTelemetry);
telemetryActivity?.SetEndTime(postTelemetry);
}
Comment thread
baronfel marked this conversation as resolved.

// Try the AOT-compiled path for supported commands (if enabled)
if (EnvironmentVariableParser.ParseBool(Environment.GetEnvironmentVariable(EnvironmentVariableNames.DOTNET_CLI_ENABLEAOT), defaultValue: false))
int exitCode = 1;
bool success = false;

try
{
var parseResult = Parser.Parse(args);
if (parseResult.Errors.Count == 0)
// Make hostfxr discoverable for NativeWrapper P/Invokes (required on non-Windows)
if (!string.IsNullOrEmpty(hostfxrPath))
{
try
{
return Parser.Invoke(parseResult);
}
catch (CommandNotAvailableInAotException)
{
// Command requires managed CLI — fall through to managed fallback below.
}
catch (Utils.GracefulException ex)
AppContext.SetData("HOSTFXR_PATH", hostfxrPath);
}

// Try the AOT-compiled path for supported commands (if enabled)
if (EnvironmentVariableParser.ParseBool(Environment.GetEnvironmentVariable(EnvironmentVariableNames.DOTNET_CLI_ENABLEAOT), defaultValue: false))
{
var parse = Activities.Source.StartActivity("aot-parsing");
var parseResult = Parser.Parse(args);
parse?.Stop();
mainActivity?.SetDisplayName(parseResult);
if (parseResult.Errors.Count == 0)
{
Reporter.Error.WriteLine(ex.Message.Red());
return 1;
using var invoke = Activities.Source.StartActivity("aot-invocation");
try
{
exitCode = Parser.Invoke(parseResult);
success = true;
return exitCode;
}
catch (Utils.GracefulException ex)
{
Reporter.Error.WriteLine(ex.Message.Red());
invoke?.SetStatus(ActivityStatusCode.Error);
invoke?.AddException(ex);
success = false;
exitCode = 1;
return exitCode;
}
catch (CommandNotAvailableInAotException)
{
// Command requires managed CLI — fall through to managed fallback below.
}
}
}
}

// Fall back to the fully managed dotnet CLI by hosting .NET
string dotnetDll = Path.Join(sdkDir, "dotnet.dll");
string runtimeConfig = Path.Join(sdkDir, "dotnet.runtimeconfig.json");
// Fall back to the fully managed dotnet CLI by hosting .NET
string dotnetDll = Path.Join(sdkDir, "dotnet.dll");
string runtimeConfig = Path.Join(sdkDir, "dotnet.runtimeconfig.json");

if (File.Exists(dotnetDll) && File.Exists(runtimeConfig))
if (File.Exists(dotnetDll) && File.Exists(runtimeConfig))
{
// Use the command-line hosting path to run dotnet.dll
string[] appArgs = new string[args.Length + 1];
appArgs[0] = dotnetDll;
Array.Copy(args, 0, appArgs, 1, args.Length);
exitCode = ManagedHost.RunApp(hostPath, dotnetRoot, hostfxrPath, appArgs);
success = true;
return exitCode;
}

// No managed fallback available
Console.Error.WriteLine($"The managed fallback could not be located. Expected '{dotnetDll}' and '{runtimeConfig}'.");
return exitCode;
}
finally
{
// Use the command-line hosting path to run dotnet.dll
string[] appArgs = new string[args.Length + 1];
appArgs[0] = dotnetDll;
Array.Copy(args, 0, appArgs, 1, args.Length);
return ManagedHost.RunApp(hostPath, dotnetRoot, hostfxrPath, appArgs);
mainActivity?.AddTag("process.exit.code", exitCode);
mainActivity?.SetStatus(success ? ActivityStatusCode.Ok : ActivityStatusCode.Error);
mainActivity?.Stop();
TelemetryClient.FlushProviders();
}

// No managed fallback available
Console.Error.WriteLine($"The managed fallback could not be located. Expected '{dotnetDll}' and '{runtimeConfig}'.");
return 1;
}
}
Loading
Loading