| File: Watch\StaticFileHandler.cs | Web Access |
| Project: src\sdk\src\Dotnet.Watch\dotnet-watch\dotnet-watch.csproj (dotnet-watch) |
// 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.Build.Graph; using Microsoft.DotNet.HotReload; using Microsoft.Extensions.Logging; namespace Microsoft.DotNet.Watch; internal sealed class StaticFileHandler(ILogger logger, LoadedProjectGraph projectGraph, BrowserRefreshServerFactory browserConnector) { public async ValueTask<bool> HandleFileChangesAsync(IReadOnlyList<ChangedFile> files, CancellationToken cancellationToken) { var stopwatch = Stopwatch.StartNew(); var allFilesHandled = true; var refreshRequests = new Dictionary<BrowserRefreshServer, List<string>>(); var projectsWithoutRefreshServer = new HashSet<ProjectGraphNode>(); for (int i = 0; i < files.Count; i++) { var file = files[i].Item; if (file.StaticWebAssetRelativeUrl is null) { allFilesHandled = false; continue; } logger.LogDebug("Handling file change event for static content {FilePath}.", file.FilePath); foreach (var containingProjectPath in file.ContainingProjectPaths) { foreach (var projectNode in projectGraph.GetProjectNodes(containingProjectPath)) { if (browserConnector.TryGetRefreshServer(projectNode, out var refreshServer)) { if (!refreshRequests.TryGetValue(refreshServer, out var filesPerServer)) { logger.LogDebug("[{ProjectName}] Refreshing browser.", projectNode.GetDisplayName()); refreshRequests.Add(refreshServer, filesPerServer = []); } filesPerServer.Add(StaticWebAsset.WebRoot + "/" + file.StaticWebAssetRelativeUrl); } else if (projectsWithoutRefreshServer.Add(projectNode)) { logger.LogDebug("[{ProjectName}] No refresh server.", projectNode.GetDisplayName()); } } } } if (refreshRequests.Count == 0) { return allFilesHandled; } var tasks = refreshRequests.Select(request => request.Key.UpdateStaticAssetsAsync(request.Value, cancellationToken).AsTask()); await Task.WhenAll(tasks).WaitAsync(cancellationToken); logger.Log(MessageDescriptor.StaticAssetsChangesApplied, stopwatch.ElapsedMilliseconds); return allFilesHandled; } private readonly struct UpdateStaticFileMessage { public string Type => "UpdateStaticFile"; public string Path { get; init; } } }