diff --git a/sdk.slnx b/sdk.slnx
index 5077b0285a6c..40c831048edc 100644
--- a/sdk.slnx
+++ b/sdk.slnx
@@ -23,6 +23,7 @@
+
@@ -57,10 +58,10 @@
-
-
+
+
diff --git a/src/BuiltInTools/Watch/Microsoft.DotNet.HotReload.Watch.csproj b/src/BuiltInTools/Watch/Microsoft.DotNet.HotReload.Watch.csproj
index 48e96f316ba5..aa3590c0c328 100644
--- a/src/BuiltInTools/Watch/Microsoft.DotNet.HotReload.Watch.csproj
+++ b/src/BuiltInTools/Watch/Microsoft.DotNet.HotReload.Watch.csproj
@@ -36,4 +36,8 @@
+
+
+
+
diff --git a/src/BuiltInTools/Watch/Process/LaunchSettingsProfile.cs b/src/BuiltInTools/Watch/Process/LaunchSettingsProfile.cs
index 1ec08ab04ea2..90dbadffb2cb 100644
--- a/src/BuiltInTools/Watch/Process/LaunchSettingsProfile.cs
+++ b/src/BuiltInTools/Watch/Process/LaunchSettingsProfile.cs
@@ -1,10 +1,9 @@
// 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 System.Text.Json;
using System.Text.Json.Serialization;
+using Microsoft.DotNet.ProjectTools;
using Microsoft.Extensions.Logging;
namespace Microsoft.DotNet.Watch
@@ -26,28 +25,19 @@ internal sealed class LaunchSettingsProfile
internal static LaunchSettingsProfile? ReadLaunchProfile(string projectPath, string? launchProfileName, ILogger logger)
{
- var projectDirectory = Path.GetDirectoryName(projectPath);
- Debug.Assert(projectDirectory != null);
-
- var launchSettingsPath = GetPropertiesLaunchSettingsPath(projectDirectory, "Properties");
- bool hasLaunchSettings = File.Exists(launchSettingsPath);
-
- var projectNameWithoutExtension = Path.GetFileNameWithoutExtension(projectPath);
- var runJsonPath = GetFlatLaunchSettingsPath(projectDirectory, projectNameWithoutExtension);
- bool hasRunJson = File.Exists(runJsonPath);
-
- if (hasLaunchSettings)
+ var launchSettingsPath = LaunchSettingsLocator.TryFindLaunchSettings(projectPath, launchProfileName, (message, isError) =>
{
- if (hasRunJson)
+ if (isError)
{
- logger.LogWarning("Warning: Settings from '{JsonPath}' are not used because '{LaunchSettingsPath}' has precedence.", runJsonPath, launchSettingsPath);
+ logger.LogError(message);
}
- }
- else if (hasRunJson)
- {
- launchSettingsPath = runJsonPath;
- }
- else
+ else
+ {
+ logger.LogWarning(message);
+ }
+ });
+
+ if (launchSettingsPath == null)
{
return null;
}
@@ -96,12 +86,6 @@ internal sealed class LaunchSettingsProfile
return namedProfile;
}
- private static string GetPropertiesLaunchSettingsPath(string directoryPath, string propertiesDirectoryName)
- => Path.Combine(directoryPath, propertiesDirectoryName, "launchSettings.json");
-
- private static string GetFlatLaunchSettingsPath(string directoryPath, string projectNameWithoutExtension)
- => Path.Join(directoryPath, $"{projectNameWithoutExtension}.run.json");
-
private static LaunchSettingsProfile? ReadDefaultLaunchProfile(LaunchSettingsJson? launchSettings, ILogger logger)
{
if (launchSettings is null || launchSettings.Profiles is null)
diff --git a/src/BuiltInTools/dotnet-watch.slnf b/src/BuiltInTools/dotnet-watch.slnf
index 8e454226e0d0..181ae2f51023 100644
--- a/src/BuiltInTools/dotnet-watch.slnf
+++ b/src/BuiltInTools/dotnet-watch.slnf
@@ -23,6 +23,7 @@
"src\\BuiltInTools\\Watch.Aspire\\Microsoft.DotNet.HotReload.Watch.Aspire.csproj",
"src\\BuiltInTools\\Watch\\Microsoft.DotNet.HotReload.Watch.csproj",
"src\\BuiltInTools\\dotnet-watch\\dotnet-watch.csproj",
+ "src\\Microsoft.DotNet.ProjectTools\\Microsoft.DotNet.ProjectTools.csproj",
"test\\Microsoft.AspNetCore.Watch.BrowserRefresh.Tests\\Microsoft.AspNetCore.Watch.BrowserRefresh.Tests.csproj",
"test\\Microsoft.DotNet.HotReload.Client.Tests\\Microsoft.DotNet.HotReload.Client.Tests.csproj",
"test\\Microsoft.Extensions.DotNetDeltaApplier.Tests\\Microsoft.Extensions.DotNetDeltaApplier.Tests.csproj",
diff --git a/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.cs.xlf b/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.cs.xlf
new file mode 100644
index 000000000000..0acffa5e309e
--- /dev/null
+++ b/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.cs.xlf
@@ -0,0 +1,19 @@
+
+
+
+
+
+ Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried:
+{1}
+ Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried:
+{1}
+
+
+
+ Warning: Settings from '{0}' are not used because '{1}' has precedence.
+ Warning: Settings from '{0}' are not used because '{1}' has precedence.
+ {0} is an app.run.json file path. {1} is a launchSettings.json file path.
+
+
+
+
\ No newline at end of file
diff --git a/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.de.xlf b/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.de.xlf
new file mode 100644
index 000000000000..222ad213cc7c
--- /dev/null
+++ b/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.de.xlf
@@ -0,0 +1,19 @@
+
+
+
+
+
+ Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried:
+{1}
+ Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried:
+{1}
+
+
+
+ Warning: Settings from '{0}' are not used because '{1}' has precedence.
+ Warning: Settings from '{0}' are not used because '{1}' has precedence.
+ {0} is an app.run.json file path. {1} is a launchSettings.json file path.
+
+
+
+
\ No newline at end of file
diff --git a/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.es.xlf b/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.es.xlf
new file mode 100644
index 000000000000..aac33465eda7
--- /dev/null
+++ b/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.es.xlf
@@ -0,0 +1,19 @@
+
+
+
+
+
+ Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried:
+{1}
+ Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried:
+{1}
+
+
+
+ Warning: Settings from '{0}' are not used because '{1}' has precedence.
+ Warning: Settings from '{0}' are not used because '{1}' has precedence.
+ {0} is an app.run.json file path. {1} is a launchSettings.json file path.
+
+
+
+
\ No newline at end of file
diff --git a/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.fr.xlf b/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.fr.xlf
new file mode 100644
index 000000000000..37db8eede2f2
--- /dev/null
+++ b/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.fr.xlf
@@ -0,0 +1,19 @@
+
+
+
+
+
+ Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried:
+{1}
+ Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried:
+{1}
+
+
+
+ Warning: Settings from '{0}' are not used because '{1}' has precedence.
+ Warning: Settings from '{0}' are not used because '{1}' has precedence.
+ {0} is an app.run.json file path. {1} is a launchSettings.json file path.
+
+
+
+
\ No newline at end of file
diff --git a/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.it.xlf b/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.it.xlf
new file mode 100644
index 000000000000..59d52e5ed8b6
--- /dev/null
+++ b/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.it.xlf
@@ -0,0 +1,19 @@
+
+
+
+
+
+ Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried:
+{1}
+ Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried:
+{1}
+
+
+
+ Warning: Settings from '{0}' are not used because '{1}' has precedence.
+ Warning: Settings from '{0}' are not used because '{1}' has precedence.
+ {0} is an app.run.json file path. {1} is a launchSettings.json file path.
+
+
+
+
\ No newline at end of file
diff --git a/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.ja.xlf b/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.ja.xlf
new file mode 100644
index 000000000000..03d8fb57849b
--- /dev/null
+++ b/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.ja.xlf
@@ -0,0 +1,19 @@
+
+
+
+
+
+ Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried:
+{1}
+ Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried:
+{1}
+
+
+
+ Warning: Settings from '{0}' are not used because '{1}' has precedence.
+ Warning: Settings from '{0}' are not used because '{1}' has precedence.
+ {0} is an app.run.json file path. {1} is a launchSettings.json file path.
+
+
+
+
\ No newline at end of file
diff --git a/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.ko.xlf b/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.ko.xlf
new file mode 100644
index 000000000000..e8f5349a61f3
--- /dev/null
+++ b/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.ko.xlf
@@ -0,0 +1,19 @@
+
+
+
+
+
+ Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried:
+{1}
+ Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried:
+{1}
+
+
+
+ Warning: Settings from '{0}' are not used because '{1}' has precedence.
+ Warning: Settings from '{0}' are not used because '{1}' has precedence.
+ {0} is an app.run.json file path. {1} is a launchSettings.json file path.
+
+
+
+
\ No newline at end of file
diff --git a/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.pl.xlf b/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.pl.xlf
new file mode 100644
index 000000000000..fd5dd04c8e3b
--- /dev/null
+++ b/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.pl.xlf
@@ -0,0 +1,19 @@
+
+
+
+
+
+ Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried:
+{1}
+ Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried:
+{1}
+
+
+
+ Warning: Settings from '{0}' are not used because '{1}' has precedence.
+ Warning: Settings from '{0}' are not used because '{1}' has precedence.
+ {0} is an app.run.json file path. {1} is a launchSettings.json file path.
+
+
+
+
\ No newline at end of file
diff --git a/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.pt-BR.xlf b/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.pt-BR.xlf
new file mode 100644
index 000000000000..cf75b96d20cb
--- /dev/null
+++ b/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.pt-BR.xlf
@@ -0,0 +1,19 @@
+
+
+
+
+
+ Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried:
+{1}
+ Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried:
+{1}
+
+
+
+ Warning: Settings from '{0}' are not used because '{1}' has precedence.
+ Warning: Settings from '{0}' are not used because '{1}' has precedence.
+ {0} is an app.run.json file path. {1} is a launchSettings.json file path.
+
+
+
+
\ No newline at end of file
diff --git a/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.ru.xlf b/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.ru.xlf
new file mode 100644
index 000000000000..e785452d408c
--- /dev/null
+++ b/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.ru.xlf
@@ -0,0 +1,19 @@
+
+
+
+
+
+ Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried:
+{1}
+ Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried:
+{1}
+
+
+
+ Warning: Settings from '{0}' are not used because '{1}' has precedence.
+ Warning: Settings from '{0}' are not used because '{1}' has precedence.
+ {0} is an app.run.json file path. {1} is a launchSettings.json file path.
+
+
+
+
\ No newline at end of file
diff --git a/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.tr.xlf b/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.tr.xlf
new file mode 100644
index 000000000000..b535535503ac
--- /dev/null
+++ b/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.tr.xlf
@@ -0,0 +1,19 @@
+
+
+
+
+
+ Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried:
+{1}
+ Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried:
+{1}
+
+
+
+ Warning: Settings from '{0}' are not used because '{1}' has precedence.
+ Warning: Settings from '{0}' are not used because '{1}' has precedence.
+ {0} is an app.run.json file path. {1} is a launchSettings.json file path.
+
+
+
+
\ No newline at end of file
diff --git a/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.zh-Hans.xlf b/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.zh-Hans.xlf
new file mode 100644
index 000000000000..498ecf30dc47
--- /dev/null
+++ b/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.zh-Hans.xlf
@@ -0,0 +1,19 @@
+
+
+
+
+
+ Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried:
+{1}
+ Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried:
+{1}
+
+
+
+ Warning: Settings from '{0}' are not used because '{1}' has precedence.
+ Warning: Settings from '{0}' are not used because '{1}' has precedence.
+ {0} is an app.run.json file path. {1} is a launchSettings.json file path.
+
+
+
+
\ No newline at end of file
diff --git a/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.zh-Hant.xlf b/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.zh-Hant.xlf
new file mode 100644
index 000000000000..5d1edadd8e3f
--- /dev/null
+++ b/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.zh-Hant.xlf
@@ -0,0 +1,19 @@
+
+
+
+
+
+ Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried:
+{1}
+ Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried:
+{1}
+
+
+
+ Warning: Settings from '{0}' are not used because '{1}' has precedence.
+ Warning: Settings from '{0}' are not used because '{1}' has precedence.
+ {0} is an app.run.json file path. {1} is a launchSettings.json file path.
+
+
+
+
\ No newline at end of file
diff --git a/src/Cli/dotnet/Commands/Run/CommonRunHelpers.cs b/src/Cli/dotnet/Commands/Run/CommonRunHelpers.cs
index 64d2b8a1075a..7c163bc64206 100644
--- a/src/Cli/dotnet/Commands/Run/CommonRunHelpers.cs
+++ b/src/Cli/dotnet/Commands/Run/CommonRunHelpers.cs
@@ -1,6 +1,7 @@
// 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.DotNet.Cli.Utils;
namespace Microsoft.DotNet.Cli.Commands.Run;
@@ -21,13 +22,6 @@ public static Dictionary GetGlobalPropertiesFromArgs(MSBuildArgs
return globalProperties;
}
- public static string GetPropertiesLaunchSettingsPath(string directoryPath, string propertiesDirectoryName)
- => Path.Combine(directoryPath, propertiesDirectoryName, "launchSettings.json");
-
- public static string GetFlatLaunchSettingsPath(string directoryPath, string projectNameWithoutExtension)
- => Path.Join(directoryPath, $"{projectNameWithoutExtension}.run.json");
-
-
///
/// Applies adjustments to MSBuild arguments to better suit LLM/agentic environments, if such an environment is detected.
///
diff --git a/src/Cli/dotnet/Commands/Run/RunCommand.cs b/src/Cli/dotnet/Commands/Run/RunCommand.cs
index ba57cb7e44f4..e31fa2fcd626 100644
--- a/src/Cli/dotnet/Commands/Run/RunCommand.cs
+++ b/src/Cli/dotnet/Commands/Run/RunCommand.cs
@@ -19,6 +19,7 @@
using Microsoft.DotNet.Cli.Extensions;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.Cli.Utils.Extensions;
+using Microsoft.DotNet.ProjectTools;
namespace Microsoft.DotNet.Cli.Commands.Run;
@@ -217,7 +218,13 @@ internal bool TryGetLaunchProfileSettingsIfNeeded(out ProjectLaunchSettingsModel
return true;
}
- var launchSettingsPath = ReadCodeFromStdin ? null : TryFindLaunchSettings(projectOrEntryPointFilePath: ProjectFileFullPath ?? EntryPointFileFullPath!, launchProfile: LaunchProfile);
+ var launchSettingsPath = ReadCodeFromStdin
+ ? null
+ : LaunchSettingsLocator.TryFindLaunchSettings(
+ projectOrEntryPointFilePath: ProjectFileFullPath ?? EntryPointFileFullPath!,
+ launchProfile: LaunchProfile,
+ static (message, isError) => (isError ? Reporter.Error : Reporter.Output).WriteLine(message));
+
if (launchSettingsPath is null)
{
return true;
@@ -250,57 +257,6 @@ internal bool TryGetLaunchProfileSettingsIfNeeded(out ProjectLaunchSettingsModel
}
return true;
-
- static string? TryFindLaunchSettings(string projectOrEntryPointFilePath, string? launchProfile)
- {
- var buildPathContainer = Path.GetDirectoryName(projectOrEntryPointFilePath)!;
-
- string propsDirectory;
-
- // VB.NET projects store the launch settings file in the
- // "My Project" directory instead of a "Properties" directory.
- // TODO: use the `AppDesignerFolder` MSBuild property instead, which captures this logic already
- if (string.Equals(Path.GetExtension(projectOrEntryPointFilePath), ".vbproj", StringComparison.OrdinalIgnoreCase))
- {
- propsDirectory = "My Project";
- }
- else
- {
- propsDirectory = "Properties";
- }
-
- string launchSettingsPath = CommonRunHelpers.GetPropertiesLaunchSettingsPath(buildPathContainer, propsDirectory);
- bool hasLaunchSetttings = File.Exists(launchSettingsPath);
-
- string appName = Path.GetFileNameWithoutExtension(projectOrEntryPointFilePath);
- string runJsonPath = CommonRunHelpers.GetFlatLaunchSettingsPath(buildPathContainer, appName);
- bool hasRunJson = File.Exists(runJsonPath);
-
- if (hasLaunchSetttings)
- {
- if (hasRunJson)
- {
- Reporter.Output.WriteLine(string.Format(CliCommandStrings.RunCommandWarningRunJsonNotUsed, runJsonPath, launchSettingsPath).Yellow());
- }
-
- return launchSettingsPath;
- }
-
- if (hasRunJson)
- {
- return runJsonPath;
- }
-
- if (!string.IsNullOrEmpty(launchProfile))
- {
- Reporter.Error.WriteLine(string.Format(CliCommandStrings.RunCommandExceptionCouldNotLocateALaunchSettingsFile, launchProfile, $"""
- {launchSettingsPath}
- {runJsonPath}
- """).Bold().Red());
- }
-
- return null;
- }
}
private void EnsureProjectIsBuilt(out Func? projectFactory, out RunProperties? cachedRunProperties, out VirtualProjectBuildingCommand? virtualCommand)
diff --git a/src/Cli/dotnet/Commands/Test/MTP/SolutionAndProjectUtility.cs b/src/Cli/dotnet/Commands/Test/MTP/SolutionAndProjectUtility.cs
index 11cbadbcaa66..8b54283b842f 100644
--- a/src/Cli/dotnet/Commands/Test/MTP/SolutionAndProjectUtility.cs
+++ b/src/Cli/dotnet/Commands/Test/MTP/SolutionAndProjectUtility.cs
@@ -10,6 +10,7 @@
using Microsoft.DotNet.Cli.Commands.Run.LaunchSettings;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.Cli.Utils.Extensions;
+using Microsoft.DotNet.ProjectTools;
namespace Microsoft.DotNet.Cli.Commands.Test;
@@ -345,10 +346,10 @@ static RunProperties GetRunProperties(ProjectInstance project)
return null;
}
- var launchSettingsPath = CommonRunHelpers.GetPropertiesLaunchSettingsPath(projectDirectory, appDesignerFolder);
+ var launchSettingsPath = LaunchSettingsLocator.GetPropertiesLaunchSettingsPath(projectDirectory, appDesignerFolder);
bool hasLaunchSettings = File.Exists(launchSettingsPath);
- var runJsonPath = CommonRunHelpers.GetFlatLaunchSettingsPath(projectDirectory, projectNameWithoutExtension);
+ var runJsonPath = LaunchSettingsLocator.GetFlatLaunchSettingsPath(projectDirectory, projectNameWithoutExtension);
bool hasRunJson = File.Exists(runJsonPath);
if (hasLaunchSettings)
diff --git a/src/Cli/dotnet/dotnet.csproj b/src/Cli/dotnet/dotnet.csproj
index 3cdb3b20beeb..f9eddfaa7400 100644
--- a/src/Cli/dotnet/dotnet.csproj
+++ b/src/Cli/dotnet/dotnet.csproj
@@ -45,6 +45,7 @@
+
diff --git a/src/Microsoft.DotNet.ProjectTools/LaunchSettings/LaunchSettingsLocator.cs b/src/Microsoft.DotNet.ProjectTools/LaunchSettings/LaunchSettingsLocator.cs
new file mode 100644
index 000000000000..f20e3445dbfe
--- /dev/null
+++ b/src/Microsoft.DotNet.ProjectTools/LaunchSettings/LaunchSettingsLocator.cs
@@ -0,0 +1,60 @@
+// 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;
+
+namespace Microsoft.DotNet.ProjectTools;
+
+public static class LaunchSettingsLocator
+{
+ public static string GetPropertiesLaunchSettingsPath(string directoryPath, string propertiesDirectoryName)
+ => Path.Combine(directoryPath, propertiesDirectoryName, "launchSettings.json");
+
+ public static string GetFlatLaunchSettingsPath(string directoryPath, string projectNameWithoutExtension)
+ => Path.Join(directoryPath, $"{projectNameWithoutExtension}.run.json");
+
+ public static string? TryFindLaunchSettings(string projectOrEntryPointFilePath, string? launchProfile, Action report)
+ {
+ var buildPathContainer = Path.GetDirectoryName(projectOrEntryPointFilePath);
+ Debug.Assert(buildPathContainer != null);
+
+ // VB.NET projects store the launch settings file in the
+ // "My Project" directory instead of a "Properties" directory.
+ // TODO: use the `AppDesignerFolder` MSBuild property instead, which captures this logic already
+ var propsDirectory = string.Equals(Path.GetExtension(projectOrEntryPointFilePath), ".vbproj", StringComparison.OrdinalIgnoreCase)
+ ? "My Project"
+ : "Properties";
+
+ string launchSettingsPath = GetPropertiesLaunchSettingsPath(buildPathContainer, propsDirectory);
+ bool hasLaunchSetttings = File.Exists(launchSettingsPath);
+
+ string appName = Path.GetFileNameWithoutExtension(projectOrEntryPointFilePath);
+ string runJsonPath = GetFlatLaunchSettingsPath(buildPathContainer, appName);
+ bool hasRunJson = File.Exists(runJsonPath);
+
+ if (hasLaunchSetttings)
+ {
+ if (hasRunJson)
+ {
+ report(string.Format(Resources.RunCommandWarningRunJsonNotUsed, runJsonPath, launchSettingsPath), false);
+ }
+
+ return launchSettingsPath;
+ }
+
+ if (hasRunJson)
+ {
+ return runJsonPath;
+ }
+
+ if (!string.IsNullOrEmpty(launchProfile))
+ {
+ report(string.Format(Resources.RunCommandExceptionCouldNotLocateALaunchSettingsFile, launchProfile, $"""
+ {launchSettingsPath}
+ {runJsonPath}
+ """), true);
+ }
+
+ return null;
+ }
+}
diff --git a/src/Microsoft.DotNet.ProjectTools/Microsoft.DotNet.ProjectTools.csproj b/src/Microsoft.DotNet.ProjectTools/Microsoft.DotNet.ProjectTools.csproj
new file mode 100644
index 000000000000..a9e03b8a4cd5
--- /dev/null
+++ b/src/Microsoft.DotNet.ProjectTools/Microsoft.DotNet.ProjectTools.csproj
@@ -0,0 +1,11 @@
+
+
+ $(SdkTargetFramework)
+ enable
+ true
+
+
+
+
+
+
diff --git a/src/Microsoft.DotNet.ProjectTools/Resources.resx b/src/Microsoft.DotNet.ProjectTools/Resources.resx
new file mode 100644
index 000000000000..9de7f944cb9e
--- /dev/null
+++ b/src/Microsoft.DotNet.ProjectTools/Resources.resx
@@ -0,0 +1,128 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ Warning: Settings from '{0}' are not used because '{1}' has precedence.
+ {0} is an app.run.json file path. {1} is a launchSettings.json file path.
+
+
+ Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried:
+{1}
+
+
diff --git a/src/Microsoft.DotNet.ProjectTools/xlf/Resources.cs.xlf b/src/Microsoft.DotNet.ProjectTools/xlf/Resources.cs.xlf
new file mode 100644
index 000000000000..f8d9db92ba48
--- /dev/null
+++ b/src/Microsoft.DotNet.ProjectTools/xlf/Resources.cs.xlf
@@ -0,0 +1,19 @@
+
+
+
+
+
+ Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried:
+{1}
+ Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried:
+{1}
+
+
+
+ Warning: Settings from '{0}' are not used because '{1}' has precedence.
+ Warning: Settings from '{0}' are not used because '{1}' has precedence.
+ {0} is an app.run.json file path. {1} is a launchSettings.json file path.
+
+
+
+
\ No newline at end of file
diff --git a/src/Microsoft.DotNet.ProjectTools/xlf/Resources.de.xlf b/src/Microsoft.DotNet.ProjectTools/xlf/Resources.de.xlf
new file mode 100644
index 000000000000..ac6216d4b292
--- /dev/null
+++ b/src/Microsoft.DotNet.ProjectTools/xlf/Resources.de.xlf
@@ -0,0 +1,19 @@
+
+
+
+
+
+ Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried:
+{1}
+ Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried:
+{1}
+
+
+
+ Warning: Settings from '{0}' are not used because '{1}' has precedence.
+ Warning: Settings from '{0}' are not used because '{1}' has precedence.
+ {0} is an app.run.json file path. {1} is a launchSettings.json file path.
+
+
+
+
\ No newline at end of file
diff --git a/src/Microsoft.DotNet.ProjectTools/xlf/Resources.es.xlf b/src/Microsoft.DotNet.ProjectTools/xlf/Resources.es.xlf
new file mode 100644
index 000000000000..217f925c00e3
--- /dev/null
+++ b/src/Microsoft.DotNet.ProjectTools/xlf/Resources.es.xlf
@@ -0,0 +1,19 @@
+
+
+
+
+
+ Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried:
+{1}
+ Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried:
+{1}
+
+
+
+ Warning: Settings from '{0}' are not used because '{1}' has precedence.
+ Warning: Settings from '{0}' are not used because '{1}' has precedence.
+ {0} is an app.run.json file path. {1} is a launchSettings.json file path.
+
+
+
+
\ No newline at end of file
diff --git a/src/Microsoft.DotNet.ProjectTools/xlf/Resources.fr.xlf b/src/Microsoft.DotNet.ProjectTools/xlf/Resources.fr.xlf
new file mode 100644
index 000000000000..e133378ad4e1
--- /dev/null
+++ b/src/Microsoft.DotNet.ProjectTools/xlf/Resources.fr.xlf
@@ -0,0 +1,19 @@
+
+
+
+
+
+ Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried:
+{1}
+ Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried:
+{1}
+
+
+
+ Warning: Settings from '{0}' are not used because '{1}' has precedence.
+ Warning: Settings from '{0}' are not used because '{1}' has precedence.
+ {0} is an app.run.json file path. {1} is a launchSettings.json file path.
+
+
+
+
\ No newline at end of file
diff --git a/src/Microsoft.DotNet.ProjectTools/xlf/Resources.it.xlf b/src/Microsoft.DotNet.ProjectTools/xlf/Resources.it.xlf
new file mode 100644
index 000000000000..5620ef6944b3
--- /dev/null
+++ b/src/Microsoft.DotNet.ProjectTools/xlf/Resources.it.xlf
@@ -0,0 +1,19 @@
+
+
+
+
+
+ Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried:
+{1}
+ Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried:
+{1}
+
+
+
+ Warning: Settings from '{0}' are not used because '{1}' has precedence.
+ Warning: Settings from '{0}' are not used because '{1}' has precedence.
+ {0} is an app.run.json file path. {1} is a launchSettings.json file path.
+
+
+
+
\ No newline at end of file
diff --git a/src/Microsoft.DotNet.ProjectTools/xlf/Resources.ja.xlf b/src/Microsoft.DotNet.ProjectTools/xlf/Resources.ja.xlf
new file mode 100644
index 000000000000..7dd1492ebe32
--- /dev/null
+++ b/src/Microsoft.DotNet.ProjectTools/xlf/Resources.ja.xlf
@@ -0,0 +1,19 @@
+
+
+
+
+
+ Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried:
+{1}
+ Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried:
+{1}
+
+
+
+ Warning: Settings from '{0}' are not used because '{1}' has precedence.
+ Warning: Settings from '{0}' are not used because '{1}' has precedence.
+ {0} is an app.run.json file path. {1} is a launchSettings.json file path.
+
+
+
+
\ No newline at end of file
diff --git a/src/Microsoft.DotNet.ProjectTools/xlf/Resources.ko.xlf b/src/Microsoft.DotNet.ProjectTools/xlf/Resources.ko.xlf
new file mode 100644
index 000000000000..162f27b4efb9
--- /dev/null
+++ b/src/Microsoft.DotNet.ProjectTools/xlf/Resources.ko.xlf
@@ -0,0 +1,19 @@
+
+
+
+
+
+ Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried:
+{1}
+ Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried:
+{1}
+
+
+
+ Warning: Settings from '{0}' are not used because '{1}' has precedence.
+ Warning: Settings from '{0}' are not used because '{1}' has precedence.
+ {0} is an app.run.json file path. {1} is a launchSettings.json file path.
+
+
+
+
\ No newline at end of file
diff --git a/src/Microsoft.DotNet.ProjectTools/xlf/Resources.pl.xlf b/src/Microsoft.DotNet.ProjectTools/xlf/Resources.pl.xlf
new file mode 100644
index 000000000000..6f0cecb49573
--- /dev/null
+++ b/src/Microsoft.DotNet.ProjectTools/xlf/Resources.pl.xlf
@@ -0,0 +1,19 @@
+
+
+
+
+
+ Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried:
+{1}
+ Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried:
+{1}
+
+
+
+ Warning: Settings from '{0}' are not used because '{1}' has precedence.
+ Warning: Settings from '{0}' are not used because '{1}' has precedence.
+ {0} is an app.run.json file path. {1} is a launchSettings.json file path.
+
+
+
+
\ No newline at end of file
diff --git a/src/Microsoft.DotNet.ProjectTools/xlf/Resources.pt-BR.xlf b/src/Microsoft.DotNet.ProjectTools/xlf/Resources.pt-BR.xlf
new file mode 100644
index 000000000000..4d381aba1acf
--- /dev/null
+++ b/src/Microsoft.DotNet.ProjectTools/xlf/Resources.pt-BR.xlf
@@ -0,0 +1,19 @@
+
+
+
+
+
+ Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried:
+{1}
+ Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried:
+{1}
+
+
+
+ Warning: Settings from '{0}' are not used because '{1}' has precedence.
+ Warning: Settings from '{0}' are not used because '{1}' has precedence.
+ {0} is an app.run.json file path. {1} is a launchSettings.json file path.
+
+
+
+
\ No newline at end of file
diff --git a/src/Microsoft.DotNet.ProjectTools/xlf/Resources.ru.xlf b/src/Microsoft.DotNet.ProjectTools/xlf/Resources.ru.xlf
new file mode 100644
index 000000000000..20c6d3be68ad
--- /dev/null
+++ b/src/Microsoft.DotNet.ProjectTools/xlf/Resources.ru.xlf
@@ -0,0 +1,19 @@
+
+
+
+
+
+ Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried:
+{1}
+ Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried:
+{1}
+
+
+
+ Warning: Settings from '{0}' are not used because '{1}' has precedence.
+ Warning: Settings from '{0}' are not used because '{1}' has precedence.
+ {0} is an app.run.json file path. {1} is a launchSettings.json file path.
+
+
+
+
\ No newline at end of file
diff --git a/src/Microsoft.DotNet.ProjectTools/xlf/Resources.tr.xlf b/src/Microsoft.DotNet.ProjectTools/xlf/Resources.tr.xlf
new file mode 100644
index 000000000000..ff180d8a45c3
--- /dev/null
+++ b/src/Microsoft.DotNet.ProjectTools/xlf/Resources.tr.xlf
@@ -0,0 +1,19 @@
+
+
+
+
+
+ Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried:
+{1}
+ Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried:
+{1}
+
+
+
+ Warning: Settings from '{0}' are not used because '{1}' has precedence.
+ Warning: Settings from '{0}' are not used because '{1}' has precedence.
+ {0} is an app.run.json file path. {1} is a launchSettings.json file path.
+
+
+
+
\ No newline at end of file
diff --git a/src/Microsoft.DotNet.ProjectTools/xlf/Resources.zh-Hans.xlf b/src/Microsoft.DotNet.ProjectTools/xlf/Resources.zh-Hans.xlf
new file mode 100644
index 000000000000..7225552ec73b
--- /dev/null
+++ b/src/Microsoft.DotNet.ProjectTools/xlf/Resources.zh-Hans.xlf
@@ -0,0 +1,19 @@
+
+
+
+
+
+ Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried:
+{1}
+ Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried:
+{1}
+
+
+
+ Warning: Settings from '{0}' are not used because '{1}' has precedence.
+ Warning: Settings from '{0}' are not used because '{1}' has precedence.
+ {0} is an app.run.json file path. {1} is a launchSettings.json file path.
+
+
+
+
\ No newline at end of file
diff --git a/src/Microsoft.DotNet.ProjectTools/xlf/Resources.zh-Hant.xlf b/src/Microsoft.DotNet.ProjectTools/xlf/Resources.zh-Hant.xlf
new file mode 100644
index 000000000000..c99df83fdd56
--- /dev/null
+++ b/src/Microsoft.DotNet.ProjectTools/xlf/Resources.zh-Hant.xlf
@@ -0,0 +1,19 @@
+
+
+
+
+
+ Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried:
+{1}
+ Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried:
+{1}
+
+
+
+ Warning: Settings from '{0}' are not used because '{1}' has precedence.
+ Warning: Settings from '{0}' are not used because '{1}' has precedence.
+ {0} is an app.run.json file path. {1} is a launchSettings.json file path.
+
+
+
+
\ No newline at end of file