dotnet watch ignores StaticWebAssetPath metadata on @(Watch) items, preventing custom static file hot reload
- Dominant language
- C#
- Stars
- 3.2k
- Forks
- 1.3k
- PR merge metrics
- PR metrics pending
Description
I'm not finding a ton of documentation out there, but I've been trying to wire up dotnet watch to look at a separate folder than wwwroot that would trigger a browser refresh, but I'm stuck.
It seems the` StaticWebAssetPath` metadata on MSBuild `@(Watch)` items is silently ignored by dotnet watch. This prevents users from enabling static file hot reload (browser refresh without rebuild) for custom file types outside of wwwroot/.
## Repro Steps
1. Create an ASP.NET Core 10 project
2. Add a markdown file outside wwwroot (e.g., Content/docs/readme.md)
3. Add the following to the .csproj:
```xml
```
4. Run dotnet watch
5. Edit the markdown file
**Expected Behavior**
The file change should trigger a browser refresh via the `UpdateStaticFile` WebSocket message (same as files under wwwroot/), without triggering "No C# changes to apply."
## Actual Behavior
```
dotnet watch ⌚ File updated: .\Content\docs\readme.md
dotnet watch ⌚ No C# changes to apply.
```
The file is watched, but goes through the managed code change handler instead of the static file handler.
My understand is that the routing decision happens in https://github.com/dotnet/sdk/blob/main/src/BuiltInTools/Watch/HotReload/StaticFileHandler.cs, lines 22-26:
```csharp
if (file.StaticWebAssetPath is null)
{
allFilesHandled = false; // File passes through to managed code handler
continue; // Skip static file handling
}
```
When StaticWebAssetPath is set:
1. Line 28: Logs "Handling file change event for static content"
2. Line 49: Adds file to browser refresh request list
3. Line 64: Calls `UpdateStaticAssetsAsync()` → sends WebSocket `UpdateStaticFile` message to browser
4. Line 68: Logs "Hot reload of static assets succeeded"
When StaticWebAssetPath is null (current behavior):
- File is skipped (allFilesHandled = false)
- Falls through to `CompilationHandler.HandleManagedCodeChangesAsync()`
- Results in "No C# changes to apply."
## Root Cause
In https://github.com/dotnet/sdk/blob/main/src/BuiltInTools/Watch/Build/EvaluationResult.cs, lines 120-127:
```csharp
var items = projectInstance.GetItems(ItemNames.Compile)
.Concat(projectInstance.GetItems(ItemNames.AdditionalFiles))
.Concat(projectInstance.GetItems(ItemNames.Watch));
foreach (var item in items)
{
AddFile(item.EvaluatedInclude, staticWebAssetPath: null); // <-- BUG maybe?? Always null
}
```
The `StaticWebAssetPath` metadata is always passed as null for `@(Watch)` items. Compare this to the `@(Content)` item handling (lines 129-144), which correctly reads and passes the metadata.
Meanwhile, the MSBuild targets file https://github.com/dotnet/sdk/blob/main/src/BuiltInTools/dotnet-watch/Watch/DotNetWatch.targets (lines 70-73) does set `StaticWebAssetPath` on `@(Watch)` items for content files:
```xml
```
This metadata is populated but never read.
I haven't tested this yet, but it looks like a tweak might be in EvaluationResult.cs, read the `StaticWebAssetPath` metadata from `@(Watch` items:
```csharp
var items = projectInstance.GetItems(ItemNames.Compile)
.Concat(projectInstance.GetItems(ItemNames.AdditionalFiles))
.Concat(projectInstance.GetItems(ItemNames.Watch));
foreach (var item in items)
{
var staticWebAssetPath = item.GetMetadataValue(MetadataNames.StaticWebAssetPath);
AddFile(item.EvaluatedInclude,
staticWebAssetPath: string.IsNullOrEmpty(staticWebAssetPath) ? null : staticWebAssetPath);
}
```
This would allow users to:
1. Enable static file hot reload for files outside wwwroot/
2. Mark any file type (markdown, json, xml, etc.) as a static asset
3. Use the existing `StaticWebAssetPath` metadata that's already documented in the targets file
I think this is only on .NET 10. I believe some enhancements were made that prevent refresh when there are no code changes, but the scenario where we are watching stuff that is not in wwwroot, c#, CSS or wwwroot was missed.
Environment
- .NET SDK version: 10.0.101
- OS: Windows
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.