diff --git a/src/Assets/TestProjects/WatchAppWithLaunchSettings/Program.cs b/src/Assets/TestProjects/WatchAppWithLaunchSettings/Program.cs new file mode 100644 index 000000000000..143f5183dfec --- /dev/null +++ b/src/Assets/TestProjects/WatchAppWithLaunchSettings/Program.cs @@ -0,0 +1,2 @@ +Console.WriteLine("Started"); +Console.WriteLine($"Environment: {Environment.GetEnvironmentVariable("EnvironmentFromProfile")}"); diff --git a/src/Assets/TestProjects/WatchAppWithLaunchSettings/Properties/launchSettings.json b/src/Assets/TestProjects/WatchAppWithLaunchSettings/Properties/launchSettings.json new file mode 100644 index 000000000000..f8b1abd49b2b --- /dev/null +++ b/src/Assets/TestProjects/WatchAppWithLaunchSettings/Properties/launchSettings.json @@ -0,0 +1,10 @@ +{ + "profiles": { + "app": { + "commandName": "Project", + "environmentVariables": { + "EnvironmentFromProfile": "Development" + } + } + } + } diff --git a/src/Assets/TestProjects/WatchAppWithLaunchSettings/WatchAppWithLaunchSettings.csproj b/src/Assets/TestProjects/WatchAppWithLaunchSettings/WatchAppWithLaunchSettings.csproj new file mode 100644 index 000000000000..74abf5c97664 --- /dev/null +++ b/src/Assets/TestProjects/WatchAppWithLaunchSettings/WatchAppWithLaunchSettings.csproj @@ -0,0 +1,10 @@ + + + + Exe + net6.0 + enable + enable + + + diff --git a/src/BuiltInTools/dotnet-watch/HotReload/BlazorWebAssemblyDeltaApplier.cs b/src/BuiltInTools/dotnet-watch/HotReload/BlazorWebAssemblyDeltaApplier.cs index 54aac04ef06f..c65ab9789b2e 100644 --- a/src/BuiltInTools/dotnet-watch/HotReload/BlazorWebAssemblyDeltaApplier.cs +++ b/src/BuiltInTools/dotnet-watch/HotReload/BlazorWebAssemblyDeltaApplier.cs @@ -10,11 +10,9 @@ using System.Linq; using System.Net.WebSockets; using System.Text; -using System.Text.Json; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.ExternalAccess.Watch.Api; -using Microsoft.Extensions.HotReload; using Microsoft.Extensions.Tools.Internal; namespace Microsoft.DotNet.Watcher.Tools @@ -22,6 +20,7 @@ namespace Microsoft.DotNet.Watcher.Tools internal class BlazorWebAssemblyDeltaApplier : IDeltaApplier { private static Task>? _cachedCapabilties; + private static readonly ImmutableArray _baselineCapabilities = ImmutableArray.Create("Baseline"); private readonly IReporter _reporter; private int _sequenceId; @@ -48,7 +47,7 @@ async Task> GetApplyUpdateCapabilitiesCoreAsync() { if (context.BrowserRefreshServer is null) { - return ImmutableArray.Empty; + return _baselineCapabilities; } await context.BrowserRefreshServer.WaitForClientConnectionAsync(cancellationToken); @@ -58,14 +57,14 @@ async Task> GetApplyUpdateCapabilitiesCoreAsync() var buffer = ArrayPool.Shared.Rent(32 * 1024); try { - // We'll query the browser and ask it send capabilities. If the browser does not respond in 10s, we'll assume something is amiss and return - // no capabilities. This should give you baseline hot reload capabilties. + // We'll query the browser and ask it send capabilities. If the browser does not respond in a short duration, we'll assume something is amiss and return + // baseline capabilities. var response = await context.BrowserRefreshServer.ReceiveAsync(buffer, cancellationToken) .AsTask() - .WaitAsync(TimeSpan.FromSeconds(10), cancellationToken); + .WaitAsync(TimeSpan.FromSeconds(15), cancellationToken); if (!response.HasValue || !response.Value.EndOfMessage || response.Value.MessageType != WebSocketMessageType.Text) { - return ImmutableArray.Empty; + return _baselineCapabilities; } var values = Encoding.UTF8.GetString(buffer.AsSpan(0, response.Value.Count)); @@ -83,7 +82,7 @@ async Task> GetApplyUpdateCapabilitiesCoreAsync() ArrayPool.Shared.Return(buffer); } - return ImmutableArray.Empty; + return _baselineCapabilities; } } diff --git a/src/BuiltInTools/dotnet-watch/Program.cs b/src/BuiltInTools/dotnet-watch/Program.cs index a60b3de5d031..246f07e76291 100644 --- a/src/BuiltInTools/dotnet-watch/Program.cs +++ b/src/BuiltInTools/dotnet-watch/Program.cs @@ -278,7 +278,7 @@ private async Task MainInternalAsync(IReporter reporter, CommandLineOptions _reporter.Output("Polling file watcher is enabled"); } - var defaultProfile = LaunchSettingsProfile.ReadDefaultProfile(_workingDirectory, reporter) ?? new(); + var defaultProfile = LaunchSettingsProfile.ReadDefaultProfile(processInfo.WorkingDirectory, reporter) ?? new(); var context = new DotNetWatchContext { diff --git a/src/Tests/dotnet-watch.Tests/DotNetWatcherTests.cs b/src/Tests/dotnet-watch.Tests/DotNetWatcherTests.cs index fc71b74b3f3b..e1eb948f67e8 100644 --- a/src/Tests/dotnet-watch.Tests/DotNetWatcherTests.cs +++ b/src/Tests/dotnet-watch.Tests/DotNetWatcherTests.cs @@ -129,5 +129,44 @@ public async Task RunsWithRestoreIfCsprojChanges() message = await app.Process.GetOutputLineStartsWithAsync(messagePrefix, TimeSpan.FromMinutes(2)); Assert.Equal(messagePrefix + " --no-restore -- wait", message.Trim()); } + + [CoreMSBuildOnlyFact] + public async Task Run_WithHotReloadEnabled_ReadsLaunchSettings() + { + var testAsset = _testAssetsManager.CopyTestAsset("WatchAppWithLaunchSettings") + .WithSource() + .Path; + + using var app = new WatchableApp(testAsset, _logger); + + app.DotnetWatchArgs.Add("--verbose"); + + await app.StartWatcherAsync(); + + await app.Process.GetOutputLineAsync("Environment: Development", TimeSpan.FromSeconds(10)); + } + + [CoreMSBuildOnlyFact] + public async Task Run_WithHotReloadEnabled_ReadsLaunchSettings_WhenUsingProjectOption() + { + var testAsset = _testAssetsManager.CopyTestAsset("WatchAppWithLaunchSettings") + .WithSource() + .Path; + + var directoryInfo = new DirectoryInfo(testAsset); + using var app = new WatchableApp(testAsset, _logger) + { + // Configure the working directory to be one level above the test app directory. + WorkingDirectory = Path.GetFullPath(directoryInfo.Parent.FullName), + }; + + app.DotnetWatchArgs.Add("--verbose"); + app.DotnetWatchArgs.Add("--project"); + app.DotnetWatchArgs.Add(Path.Combine(directoryInfo.Name, "WatchAppWithLaunchSettings.csproj")); + + await app.StartWatcherAsync(); + + await app.Process.GetOutputLineAsync("Environment: Development", TimeSpan.FromSeconds(10)); + } } } diff --git a/src/Tests/dotnet-watch.Tests/Utilities/WatchableApp.cs b/src/Tests/dotnet-watch.Tests/Utilities/WatchableApp.cs index d8a036559988..415f9b802219 100644 --- a/src/Tests/dotnet-watch.Tests/Utilities/WatchableApp.cs +++ b/src/Tests/dotnet-watch.Tests/Utilities/WatchableApp.cs @@ -38,6 +38,8 @@ public WatchableApp(string sourceDirectory, ITestOutputHelper logger) public string SourceDirectory { get; } + public string WorkingDirectory { get; set; } + public Task HasRestarted() => HasRestarted(DefaultMessageTimeOut); @@ -76,7 +78,7 @@ public void Start(IEnumerable arguments, [CallerMemberName] string name var commandSpec = new DotnetCommand(_logger, args.ToArray()) { - WorkingDirectory = SourceDirectory, + WorkingDirectory = WorkingDirectory ?? SourceDirectory, }; commandSpec.WithEnvironmentVariable("DOTNET_USE_POLLING_FILE_WATCHER", "true"); commandSpec.WithEnvironmentVariable("__DOTNET_WATCH_RUNNING_AS_TEST", "true");