Skip to content

Commit 96423e2

Browse files
committed
PR feedback
1 parent 9a51025 commit 96423e2

File tree

9 files changed

+74
-28
lines changed

9 files changed

+74
-28
lines changed

src/Tools/dotnet-watch/src/BrowserRefreshServer.cs

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,17 @@
1919

2020
namespace Microsoft.DotNet.Watcher.Tools
2121
{
22-
public class BrowserRefreshServer : IDisposable
22+
public class BrowserRefreshServer : IAsyncDisposable
2323
{
2424
private readonly IReporter _reporter;
2525
private readonly TaskCompletionSource _taskCompletionSource;
2626
private IHost _refreshServer;
2727
private WebSocket _webSocket;
2828

29-
public BrowserRefreshServer(
30-
IReporter reporter)
29+
public BrowserRefreshServer(IReporter reporter)
3130
{
3231
_reporter = reporter;
33-
_taskCompletionSource = new TaskCompletionSource();
32+
_taskCompletionSource = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
3433
}
3534

3635
public string Start()
@@ -66,11 +65,11 @@ static void RunInBackgroundThread(IHost host)
6665
var isDone = new ManualResetEvent(false);
6766

6867
ExceptionDispatchInfo edi = null;
69-
Task.Run(() =>
68+
Task.Run(async () =>
7069
{
7170
try
7271
{
73-
host.Start();
72+
await host.StartAsync();
7473
}
7574
catch (Exception ex)
7675
{
@@ -91,7 +90,7 @@ static void RunInBackgroundThread(IHost host)
9190
}
9291
}
9392

94-
async Task WebSocketRequest(HttpContext context)
93+
private async Task WebSocketRequest(HttpContext context)
9594
{
9695
if (!context.WebSockets.IsWebSocketRequest)
9796
{
@@ -120,9 +119,20 @@ public async void SendMessage(byte[] messageBytes)
120119
}
121120
}
122121

123-
public void Dispose()
122+
public async ValueTask DisposeAsync()
124123
{
125-
_refreshServer?.Dispose();
124+
if (_webSocket != null)
125+
{
126+
await _webSocket.CloseOutputAsync(WebSocketCloseStatus.Empty, null, default);
127+
_webSocket.Dispose();
128+
}
129+
130+
if (_refreshServer != null)
131+
{
132+
await _refreshServer.StopAsync();
133+
_refreshServer.Dispose();
134+
}
135+
126136
_taskCompletionSource.TrySetResult();
127137
}
128138
}

src/Tools/dotnet-watch/src/DotNetWatcher.cs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
namespace Microsoft.DotNet.Watcher
1616
{
17-
public class DotNetWatcher : IDisposable
17+
public class DotNetWatcher : IAsyncDisposable
1818
{
1919
private readonly IReporter _reporter;
2020
private readonly ProcessRunner _processRunner;
@@ -142,14 +142,19 @@ public async Task WatchAsync(ProcessSpec processSpec, CancellationToken cancella
142142
}
143143
}
144144

145-
public void Dispose()
145+
public async ValueTask DisposeAsync()
146146
{
147147
foreach (var filter in _filters)
148148
{
149-
if (filter is IDisposable disposable)
149+
if (filter is IAsyncDisposable asyncDisposable)
150150
{
151-
disposable.Dispose();
151+
await asyncDisposable.DisposeAsync();
152152
}
153+
else if (filter is IDisposable diposable)
154+
{
155+
diposable.Dispose();
156+
}
157+
153158
}
154159
}
155160
}
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) .NET Foundation. All rights reserved.
1+
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System.Collections.Generic;
@@ -7,6 +7,8 @@ namespace Microsoft.DotNet.Watcher
77
{
88
public interface IFileSet : IEnumerable<string>
99
{
10+
bool IsNetCoreApp31OrNewer { get; }
11+
1012
bool Contains(string filePath);
1113
}
1214
}

src/Tools/dotnet-watch/src/Internal/FileSet.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,19 @@ public class FileSet : IFileSet
1111
{
1212
private readonly HashSet<string> _files;
1313

14-
public FileSet(IEnumerable<string> files)
14+
public FileSet(bool isNetCoreApp31OrNewer, IEnumerable<string> files)
1515
{
16+
IsNetCoreApp31OrNewer = isNetCoreApp31OrNewer;
1617
_files = new HashSet<string>(files, StringComparer.OrdinalIgnoreCase);
1718
}
1819

1920
public bool Contains(string filePath) => _files.Contains(filePath);
2021

2122
public int Count => _files.Count;
2223

23-
public static IFileSet Empty = new FileSet(Array.Empty<string>());
24+
public bool IsNetCoreApp31OrNewer { get; }
25+
26+
public static IFileSet Empty = new FileSet(false, Array.Empty<string>());
2427

2528
public IEnumerator<string> GetEnumerator() => _files.GetEnumerator();
2629
IEnumerator IEnumerable.GetEnumerator() => _files.GetEnumerator();

src/Tools/dotnet-watch/src/Internal/MsBuildFileSetFactory.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,12 @@ public async Task<IFileSet> CreateAsync(CancellationToken cancellationToken)
8585

8686
if (exitCode == 0 && File.Exists(watchList))
8787
{
88+
var lines = File.ReadAllLines(watchList);
89+
var isNetCoreApp31OrNewer = lines.FirstOrDefault() == "true";
90+
8891
var fileset = new FileSet(
89-
File.ReadAllLines(watchList)
92+
isNetCoreApp31OrNewer,
93+
lines.Skip(1)
9094
.Select(l => l?.Trim())
9195
.Where(l => !string.IsNullOrEmpty(l)));
9296

@@ -124,7 +128,7 @@ public async Task<IFileSet> CreateAsync(CancellationToken cancellationToken)
124128
{
125129
_reporter.Warn("Fix the error to continue or press Ctrl+C to exit.");
126130

127-
var fileSet = new FileSet(new[] { _projectFile });
131+
var fileSet = new FileSet(false, new[] { _projectFile });
128132

129133
using (var watcher = new FileSetWatcher(fileSet, _reporter))
130134
{

src/Tools/dotnet-watch/src/LaunchBrowserFilter.cs

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@
1515

1616
namespace Microsoft.DotNet.Watcher.Tools
1717
{
18-
public sealed class LaunchBrowserFilter : IWatchFilter, IDisposable
18+
public sealed class LaunchBrowserFilter : IWatchFilter, IAsyncDisposable
1919
{
2020
private readonly byte[] ReloadMessage = Encoding.UTF8.GetBytes("Reload");
2121
private readonly byte[] WaitMessage = Encoding.UTF8.GetBytes("Wait");
22-
private static readonly Regex NowListeningRegex = new Regex(@"^\s*Now listening on: (?<url>.*)$", RegexOptions.None, TimeSpan.FromSeconds(10));
23-
private static readonly Regex ApplicationStartedRegex = new Regex(@"^\s*Application started\. Press Ctrl\+C to shut down\.$", RegexOptions.None, TimeSpan.FromSeconds(10));
22+
private static readonly Regex NowListeningRegex = new Regex(@"^\s*Now listening on: (?<url>.*)$", RegexOptions.None | RegexOptions.Compiled, TimeSpan.FromSeconds(10));
23+
private static readonly Regex ApplicationStartedRegex = new Regex(@"^\s*Application started\. Press Ctrl\+C to shut down\.$", RegexOptions.None | RegexOptions.Compiled, TimeSpan.FromSeconds(10));
2424

2525
private readonly bool _runningInTest;
2626
private readonly bool _suppressLaunchBrowser;
@@ -135,7 +135,7 @@ private void LaunchBrowser(string launchUrl)
135135

136136
if (_runningInTest)
137137
{
138-
_reporter.Verbose($"Launching browser: {fileName} {args}");
138+
_reporter.Output($"Launching browser: {fileName} {args}");
139139
return;
140140
}
141141

@@ -151,6 +151,12 @@ private static bool CanLaunchBrowser(DotNetWatchContext context, out string laun
151151
{
152152
launchUrl = null;
153153

154+
if (!context.FileSet.IsNetCoreApp31OrNewer)
155+
{
156+
// Browser refresh middleware supports 3.1 or newer
157+
return false;
158+
}
159+
154160
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && !RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
155161
{
156162
// Launching a browser requires file associations that are not available in all operating systems.
@@ -194,10 +200,13 @@ private static bool CanLaunchBrowser(DotNetWatchContext context, out string laun
194200
return defaultProfile.LaunchBrowser;
195201
}
196202

197-
public void Dispose()
203+
public async ValueTask DisposeAsync()
198204
{
199205
_browserProcess?.Dispose();
200-
_refreshServer?.Dispose();
206+
if (_refreshServer != null)
207+
{
208+
await _refreshServer.DisposeAsync();
209+
}
201210
}
202211
}
203212
}

src/Tools/dotnet-watch/src/Program.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ private async Task<int> MainInternalAsync(
162162
_reporter.Output("Polling file watcher is enabled");
163163
}
164164

165-
using var watcher = new DotNetWatcher(reporter, fileSetFactory);
165+
await using var watcher = new DotNetWatcher(reporter, fileSetFactory);
166166
await watcher.WatchAsync(processInfo, cancellationToken);
167167

168168
return 0;

src/Tools/dotnet-watch/src/assets/DotNetWatch.targets

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,22 @@ them to a file.
99
-->
1010
<Target Name="GenerateWatchList"
1111
DependsOnTargets="_CollectWatchItems">
12+
13+
<PropertyGroup>
14+
<_IsMicrosoftNETCoreApp31OrNewer
15+
Condition="'$(TargetFrameworkIdentifier)' == '.NETCoreApp' And $([MSBuild]::VersionGreaterThanOrEquals($(TargetFrameworkVersion), '3.1'))">true</_IsMicrosoftNETCoreApp31OrNewer>
16+
17+
<_IsMicrosoftNETCoreApp31OrNewer Condition="'$(_IsMicrosoftNETCoreApp31OrNewer)' == ''">false</_IsMicrosoftNETCoreApp31OrNewer>
18+
</PropertyGroup>
19+
20+
<ItemGroup>
21+
<_WatchListLine Include="$(_IsMicrosoftNETCoreApp31OrNewer)" />
22+
<_WatchListLine Include="%(Watch.FullPath)" />
23+
</ItemGroup>
24+
1225
<WriteLinesToFile Overwrite="true"
1326
File="$(_DotNetWatchListFile)"
14-
Lines="@(Watch -> '%(FullPath)')" />
27+
Lines="@(_WatchListLine)" />
1528
</Target>
1629

1730
<!--

src/Tools/dotnet-watch/test/MSBuildEvaluationFilterTest.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ namespace Microsoft.DotNet.Watcher.Tools
1616
public class MSBuildEvaluationFilterTest
1717
{
1818
private readonly IFileSetFactory _fileSetFactory = Mock.Of<IFileSetFactory>(
19-
f => f.CreateAsync(It.IsAny<CancellationToken>()) == Task.FromResult<IFileSet>(new FileSet(Enumerable.Empty<string>())));
19+
f => f.CreateAsync(It.IsAny<CancellationToken>()) == Task.FromResult<IFileSet>(FileSet.Empty));
2020

2121
[Fact]
2222
public async Task ProcessAsync_EvaluatesFileSetIfProjFileChanges()
@@ -98,7 +98,7 @@ public async Task ProcessAsync_SetsEvaluationRequired_IfMSBuildFileChanges_ButIs
9898
// concurrent edits. MSBuildEvaluationFilter uses timestamps to additionally track changes to these files.
9999

100100
// Arrange
101-
var fileSet = new FileSet(new[] { "Controlller.cs", "Proj.csproj" });
101+
var fileSet = new FileSet(false, new[] { "Controlller.cs", "Proj.csproj" });
102102
var fileSetFactory = Mock.Of<IFileSetFactory>(f => f.CreateAsync(It.IsAny<CancellationToken>()) == Task.FromResult<IFileSet>(fileSet));
103103

104104
var filter = new TestableMSBuildEvaluationFilter(fileSetFactory)

0 commit comments

Comments
 (0)