You could go with what @DavidBrowne suggests in his answer. Using System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName
"knowing" that it is dotnet.exe
(with full path) and then using that. And mind you, depending on your situation that might be "good enough" and below is too complicated. Having that said...
However, that has two issues:
- What if the process trying to execute another is itself not a .NET Core process (but a .NET Framework based one, or some IIS/ASP.NET Core in-process hosted app)?
- What if the process trying to execute another is itself based on .NET Core 3.x executable (that is is started via
MyProc.exe
and not dotnet.exe MyProc.dll
)?
If you write an application that only executes other executables that you also control, you can at least circumvent the 2nd issue by just making sure that everything is build the same way (using dotnet.exe
or using .NET Core 3.x executables).
However, if that is not possible for some reason (e.g. issue one above), then you need to find the location of dotnet.exe
on a system. The logic to do so is not super trivial and existing code on GitHub shows how it is done. Lookup DotNetMuxer.cs
and you'll get some implementations. For example the one of ASP.NET Core.
A even more involved one, would also consider the FX_DEPS_FILE
environment variable and could look like this:
// One of the many muxer-locator implementations that can be found on github.com
// (Example azure-sdk, asp.net core sources, etc.)
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
namespace ProcessIsolation
{
/// <summary>
/// Utilities for finding the "dotnet.exe" file from the currently running .NET Core application
/// </summary>
internal static class DotNetMuxer
{
private const string MuxerName = "dotnet";
static DotNetMuxer()
{
MuxerPath = TryFindMuxerPath();
}
/// <summary>
/// The full filepath to the .NET Core muxer.
/// </summary>
public static string MuxerPath { get; }
/// <summary>
/// Finds the full filepath to the .NET Core muxer,
/// or returns a string containing the default name of the .NET Core muxer ('dotnet').
/// </summary>
/// <returns>The path to <c>dotnet.exe</c> or <c>null</c> if not found.</returns>
public static string MuxerPathOrDefault()
=> MuxerPath ?? MuxerName;
private static string TryFindMuxerPath()
{
var fileName = MuxerName;
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
fileName += ".exe";
}
var mainModule = Process.GetCurrentProcess().MainModule;
if (!string.IsNullOrEmpty(mainModule?.FileName)
&& Path.GetFileName(mainModule.FileName).Equals(fileName, StringComparison.OrdinalIgnoreCase))
{
return mainModule.FileName;
}
// if Process.MainModule is not available or it does not equal "dotnet(.exe)?", fallback to navigating to the muxer
// by using the location of the shared framework
var fxDepsFile = AppContext.GetData("FX_DEPS_FILE") as string;
if (string.IsNullOrEmpty(fxDepsFile))
{
return null;
}
var muxerDir = new FileInfo(fxDepsFile) // Microsoft.NETCore.App.deps.json
.Directory? // (version)
.Parent? // Microsoft.NETCore.App
.Parent? // shared
.Parent; // DOTNET_HOME
if (muxerDir == null)
{
return null;
}
var muxer = Path.Combine(muxerDir.FullName, fileName);
return File.Exists(muxer)
? muxer
: null;
}
}
}