Skip to content

Commit

Permalink
Cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
tmat committed Nov 4, 2024
1 parent 4133f77 commit 3b6e0a8
Show file tree
Hide file tree
Showing 16 changed files with 252 additions and 321 deletions.
12 changes: 7 additions & 5 deletions src/BuiltInTools/BrowserRefresh/BlazorHotReload.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Use by older versions of Microsoft.AspNetCore.Components.WebAssembly.
// For back compat only.
// Used by older versions of Microsoft.AspNetCore.Components.WebAssembly.
// For back compat only until updated ASP.NET is inserted into the SDK.

export function receiveHotReload() {
return BINDING.js_to_mono_obj(new Promise((resolve) => receiveHotReloadAsync().then(resolve(0))));
Expand All @@ -8,10 +8,12 @@ export function receiveHotReload() {
export async function receiveHotReloadAsync() {
const response = await fetch('/_framework/blazor-hotreload');
if (response.status === 200) {
const deltas = await response.json();
if (deltas) {
const updates = await response.json();
if (updates) {
try {
deltas.forEach(d => window.Blazor._internal.applyHotReload(d.moduleId, d.metadataDelta, d.ilDelta, d.pdbDelta, d.updatedTypes));
updates.forEach(u => {
u.deltas.forEach(d => window.Blazor._internal.applyHotReload(d.moduleId, d.metadataDelta, d.ilDelta, d.pdbDelta, d.updatedTypes));
})
} catch (error) {
console.warn(error);
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ namespace Microsoft.AspNetCore.Watch.BrowserRefresh
/// A middleware that manages receiving and sending deltas from a BlazorWebAssembly app.
/// This assembly is shared between Visual Studio and dotnet-watch. By putting some of the complexity
/// in here, we can avoid duplicating work in watch and VS.
///
/// Mapped to <see cref="ApplicationPaths.BlazorHotReloadMiddleware"/>.
/// </summary>
internal sealed class BlazorWasmHotReloadMiddleware
{
Expand Down
48 changes: 24 additions & 24 deletions src/BuiltInTools/BrowserRefresh/BrowserRefreshMiddleware.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,39 +9,33 @@

namespace Microsoft.AspNetCore.Watch.BrowserRefresh
{
public class BrowserRefreshMiddleware
public sealed class BrowserRefreshMiddleware(RequestDelegate next, ILogger<BrowserRefreshMiddleware> logger)
{
private static readonly MediaTypeHeaderValue s_textHtmlMediaType = new("text/html");
private static readonly MediaTypeHeaderValue s_applicationJsonMediaType = new("application/json");
private static readonly string? s_dotnetModifiableAssemblies = GetNonEmptyEnvironmentVariableValue("DOTNET_MODIFIABLE_ASSEMBLIES");
private static readonly string? s_aspnetcoreBrowserTools = GetNonEmptyEnvironmentVariableValue("__ASPNETCORE_BROWSER_TOOLS");

private readonly RequestDelegate _next;
private readonly ILogger _logger;
private string? _dotnetModifiableAssemblies = GetNonEmptyEnvironmentVariableValue("DOTNET_MODIFIABLE_ASSEMBLIES");
private string? _aspnetcoreBrowserTools = GetNonEmptyEnvironmentVariableValue("__ASPNETCORE_BROWSER_TOOLS");

private static string? GetNonEmptyEnvironmentVariableValue(string name)
=> Environment.GetEnvironmentVariable(name) is { Length: > 0 } value ? value : null;

public BrowserRefreshMiddleware(RequestDelegate next, ILogger<BrowserRefreshMiddleware> logger) =>
(_next, _logger) = (next, logger);

public async Task InvokeAsync(HttpContext context)
{
if (IsWebAssemblyBootRequest(context))
{
AttachWebAssemblyHeaders(context);
await _next(context);
await next(context);
}
else if (IsBrowserDocumentRequest(context))
{
// Use a custom StreamWrapper to rewrite output on Write/WriteAsync
using var responseStreamWrapper = new ResponseStreamWrapper(context, _logger);
using var responseStreamWrapper = new ResponseStreamWrapper(context, logger);
var originalBodyFeature = context.Features.Get<IHttpResponseBodyFeature>();
context.Features.Set<IHttpResponseBodyFeature>(new StreamResponseBodyFeature(responseStreamWrapper));

try
{
await _next(context);
await next(context);
}
finally
{
Expand All @@ -52,21 +46,21 @@ public async Task InvokeAsync(HttpContext context)
{
if (responseStreamWrapper.ScriptInjectionPerformed)
{
Log.BrowserConfiguredForRefreshes(_logger);
Log.BrowserConfiguredForRefreshes(logger);
}
else if (context.Response.Headers.TryGetValue(HeaderNames.ContentEncoding, out var contentEncodings))
{
Log.ResponseCompressionDetected(_logger, contentEncodings);
Log.ResponseCompressionDetected(logger, contentEncodings);
}
else
{
Log.FailedToConfiguredForRefreshes(_logger);
Log.FailedToConfiguredForRefreshes(logger);
}
}
}
else
{
await _next(context);
await next(context);
}
}

Expand All @@ -76,34 +70,34 @@ private void AttachWebAssemblyHeaders(HttpContext context)
{
if (!context.Response.Headers.ContainsKey("DOTNET-MODIFIABLE-ASSEMBLIES"))
{
if(s_dotnetModifiableAssemblies != null)
if (_dotnetModifiableAssemblies != null)
{
context.Response.Headers.Add("DOTNET-MODIFIABLE-ASSEMBLIES", s_dotnetModifiableAssemblies);
context.Response.Headers.Add("DOTNET-MODIFIABLE-ASSEMBLIES", _dotnetModifiableAssemblies);
}
else
{
_logger.LogDebug("DOTNET_MODIFIABLE_ASSEMBLIES environment variable is not set, likely because hot reload is not enabled. The browser refresh feature may not work as expected.");
logger.LogDebug("DOTNET_MODIFIABLE_ASSEMBLIES environment variable is not set, likely because hot reload is not enabled. The browser refresh feature may not work as expected.");
}
}
else
{
_logger.LogDebug("DOTNET-MODIFIABLE-ASSEMBLIES header is already set.");
logger.LogDebug("DOTNET-MODIFIABLE-ASSEMBLIES header is already set.");
}

if (!context.Response.Headers.ContainsKey("ASPNETCORE-BROWSER-TOOLS"))
{
if (s_aspnetcoreBrowserTools != null)
if (_aspnetcoreBrowserTools != null)
{
context.Response.Headers.Add("ASPNETCORE-BROWSER-TOOLS", s_aspnetcoreBrowserTools);
context.Response.Headers.Add("ASPNETCORE-BROWSER-TOOLS", _aspnetcoreBrowserTools);
}
else
{
_logger.LogDebug("__ASPNETCORE_BROWSER_TOOLS environment variable is not set. The browser refresh feature may not work as expected.");
logger.LogDebug("__ASPNETCORE_BROWSER_TOOLS environment variable is not set. The browser refresh feature may not work as expected.");
}
}
else
{
_logger.LogDebug("ASPNETCORE-BROWSER-TOOLS header is already set.");
logger.LogDebug("ASPNETCORE-BROWSER-TOOLS header is already set.");
}

return Task.CompletedTask;
Expand Down Expand Up @@ -184,6 +178,12 @@ internal static bool IsBrowserDocumentRequest(HttpContext context)
return false;
}

internal void Test_SetEnvironment(string dotnetModifiableAssemblies, string aspnetcoreBrowserTools)
{
_dotnetModifiableAssemblies = dotnetModifiableAssemblies;
_aspnetcoreBrowserTools = aspnetcoreBrowserTools;
}

internal static class Log
{
private static readonly Action<ILogger, Exception?> _setupResponseForBrowserRefresh = LoggerMessage.Define(
Expand Down
4 changes: 4 additions & 0 deletions src/BuiltInTools/BrowserRefresh/HostingStartup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)

app.Map(ApplicationPaths.BrowserRefreshJS,
static app => app.UseMiddleware<BrowserScriptMiddleware>(BrowserScriptMiddleware.GetBrowserRefreshJS()));

// backwards compat only:
app.Map(ApplicationPaths.BlazorHotReloadJS,
static app => app.UseMiddleware<BrowserScriptMiddleware>(BrowserScriptMiddleware.GetBlazorHotReloadJS()));
});

app.UseMiddleware<BrowserRefreshMiddleware>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\DotNetWatchTasks\DotNetWatchTasks.csproj" />
<InternalsVisibleTo Include="Microsoft.AspNetCore.Watch.BrowserRefresh.Tests" />
</ItemGroup>

</Project>
4 changes: 2 additions & 2 deletions src/BuiltInTools/dotnet-watch/Browser/BrowserConnection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public BrowserConnection(WebSocket clientSocket, string? sharedSecret, IReporter
ClientSocket = clientSocket;
SharedSecret = sharedSecret;
Id = Interlocked.Increment(ref s_lastId);
Reporter = new MessagePrefixingReporter($"[Browser #{Id}] ", reporter);
Reporter = new BrowserSpecificReporter(Id, reporter);

Reporter.Verbose($"Connected to referesh server.");
}
Expand Down Expand Up @@ -52,7 +52,7 @@ internal async ValueTask<bool> TrySendMessageAsync(ReadOnlyMemory<byte> messageB

internal async ValueTask<bool> TryReceiveMessageAsync(Action<ReadOnlySpan<byte>, IReporter> receiver, CancellationToken cancellationToken)
{
var writer = new ArrayBufferWriter<byte>(initialCapacity: 10);
var writer = new ArrayBufferWriter<byte>(initialCapacity: 1024);

while (true)
{
Expand Down
4 changes: 2 additions & 2 deletions src/BuiltInTools/dotnet-watch/Browser/BrowserConnector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ await Task.WhenAll(serversToDispose.Select(async server =>
else
{
// Notify the browser of a project rebuild (delta applier notifies of updates):
await server.SendWaitMessage(cancellationToken);
await server.SendWaitMessageAsync(cancellationToken);
}

return server;
Expand Down Expand Up @@ -150,7 +150,7 @@ void handler(OutputLine line)
// Subsequent iterations (project has been rebuilt and relaunched).
// Use refresh server to reload the browser, if available.
context.Reporter.Verbose("Reloading browser.");
_ = server.Reload(cancellationToken);
_ = server.SendReloadMessageAsync(cancellationToken);
}
}
}
Expand Down
46 changes: 23 additions & 23 deletions src/BuiltInTools/dotnet-watch/Browser/BrowserRefreshServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ internal sealed class BrowserRefreshServer : IAsyncDisposable
private static readonly ReadOnlyMemory<byte> s_reloadMessage = Encoding.UTF8.GetBytes("Reload");
private static readonly ReadOnlyMemory<byte> s_waitMessage = Encoding.UTF8.GetBytes("Wait");
private static readonly JsonSerializerOptions s_jsonSerializerOptions = new(JsonSerializerDefaults.Web);

private readonly List<BrowserConnection> _activeConnections = [];
private readonly RSA _rsa;
private readonly IReporter _reporter;
Expand Down Expand Up @@ -95,7 +95,7 @@ public async ValueTask StartAsync(CancellationToken cancellationToken)

var hostName = _environmentHostName ?? "127.0.0.1";

var supportsTLS = await SupportsTLS();
var supportsTLS = await SupportsTlsAsync();

_refreshServer = new HostBuilder()
.ConfigureWebHost(builder =>
Expand All @@ -113,7 +113,7 @@ public async ValueTask StartAsync(CancellationToken cancellationToken)
builder.Configure(app =>
{
app.UseWebSockets();
app.Run(WebSocketRequest);
app.Run(WebSocketRequestAsync);
});
})
.Build();
Expand Down Expand Up @@ -151,7 +151,7 @@ private IEnumerable<string> GetServerUrls(IHost server)
];
}

private async Task WebSocketRequest(HttpContext context)
private async Task WebSocketRequestAsync(HttpContext context)
{
if (!context.WebSockets.IsWebSocketRequest)
{
Expand Down Expand Up @@ -188,7 +188,7 @@ internal void EmulateClientConnected()
_browserConnected.TrySetResult();
}

public async Task WaitForClientConnection(CancellationToken cancellationToken)
public async Task WaitForClientConnectionAsync(CancellationToken cancellationToken)
{
using var progressCancellationSource = new CancellationTokenSource();

Expand Down Expand Up @@ -235,7 +235,7 @@ private IReadOnlyCollection<BrowserConnection> GetOpenBrowserConnections()
}
}

private async ValueTask DisposeClosedBrowserConnections()
private async ValueTask DisposeClosedBrowserConnectionsAsync()
{
List<BrowserConnection>? lazyConnectionsToDispose = null;

Expand All @@ -252,7 +252,7 @@ private async ValueTask DisposeClosedBrowserConnections()
else
{
lazyConnectionsToDispose ??= [];
lazyConnectionsToDispose.Add(connection);
lazyConnectionsToDispose.Add(connection);
}
}

Expand All @@ -274,19 +274,19 @@ public static ReadOnlyMemory<byte> SerializeJson<TValue>(TValue value)
public static TValue DeserializeJson<TValue>(ReadOnlySpan<byte> value)
=> JsonSerializer.Deserialize<TValue>(value, s_jsonSerializerOptions) ?? throw new InvalidDataException("Unexpected null object");

public ValueTask SendJsonMessage<TValue>(TValue value, CancellationToken cancellationToken)
=> Send(SerializeJson(value), cancellationToken);
public ValueTask SendJsonMessageAsync<TValue>(TValue value, CancellationToken cancellationToken)
=> SendAsync(SerializeJson(value), cancellationToken);

public ValueTask Reload(CancellationToken cancellationToken)
=> Send(s_reloadMessage, cancellationToken);
public ValueTask SendReloadMessageAsync(CancellationToken cancellationToken)
=> SendAsync(s_reloadMessage, cancellationToken);

public ValueTask SendWaitMessage(CancellationToken cancellationToken)
=> Send(s_waitMessage, cancellationToken);
public ValueTask SendWaitMessageAsync(CancellationToken cancellationToken)
=> SendAsync(s_waitMessage, cancellationToken);

public ValueTask Send(ReadOnlyMemory<byte> messageBytes, CancellationToken cancellationToken)
=> SendAndReceive(request: _ => messageBytes, response: null, cancellationToken);
public ValueTask SendAsync(ReadOnlyMemory<byte> messageBytes, CancellationToken cancellationToken)
=> SendAndReceiveAsync(request: _ => messageBytes, response: null, cancellationToken);

public async ValueTask SendAndReceive<TRequest>(
public async ValueTask SendAndReceiveAsync<TRequest>(
Func<string?, TRequest> request,
Action<ReadOnlySpan<byte>, IReporter>? response,
CancellationToken cancellationToken)
Expand Down Expand Up @@ -316,10 +316,10 @@ public async ValueTask SendAndReceive<TRequest>(
_reporter.Verbose($"Failed to receive response from a connected browser.");
}

await DisposeClosedBrowserConnections();
await DisposeClosedBrowserConnectionsAsync();
}

private async Task<bool> SupportsTLS()
private async Task<bool> SupportsTlsAsync()
{
try
{
Expand All @@ -333,19 +333,19 @@ private async Task<bool> SupportsTLS()
}
}

public ValueTask RefreshBrowser(CancellationToken cancellationToken)
=> SendJsonMessage(new AspNetCoreHotReloadApplied(), cancellationToken);
public ValueTask RefreshBrowserAsync(CancellationToken cancellationToken)
=> SendJsonMessageAsync(new AspNetCoreHotReloadApplied(), cancellationToken);

public ValueTask ReportCompilationErrorsInBrowser(ImmutableArray<string> compilationErrors, CancellationToken cancellationToken)
public ValueTask ReportCompilationErrorsInBrowserAsync(ImmutableArray<string> compilationErrors, CancellationToken cancellationToken)
{
_reporter.Verbose($"Updating diagnostics in the browser.");
if (compilationErrors.IsEmpty)
{
return SendJsonMessage(new AspNetCoreHotReloadApplied(), cancellationToken);
return SendJsonMessageAsync(new AspNetCoreHotReloadApplied(), cancellationToken);
}
else
{
return SendJsonMessage(new HotReloadDiagnostics { Diagnostics = compilationErrors }, cancellationToken);
return SendJsonMessageAsync(new HotReloadDiagnostics { Diagnostics = compilationErrors }, cancellationToken);
}
}

Expand Down
Loading

0 comments on commit 3b6e0a8

Please sign in to comment.