Skip to content

Hot Reload doen't work with UseResponseCompression Enabled #38832

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
xrkolovos opened this issue Dec 5, 2021 · 4 comments
Closed

Hot Reload doen't work with UseResponseCompression Enabled #38832

xrkolovos opened this issue Dec 5, 2021 · 4 comments
Labels
area-commandlinetools Includes: Command line tools, dotnet-dev-certs, dotnet-user-jwts, and OpenAPI feature-dotnetwatch This issue is related to the dotnet-watch command-line tool (now external) feature-hot-reload This issue is related to the Hot Reload feaature ✔️ Resolution: Duplicate Resolved as a duplicate of another issue Status: Resolved

Comments

@xrkolovos
Copy link

xrkolovos commented Dec 5, 2021

Hot Reload doen't work with UseResponseCompression Enabled.
It took me 3 hours to find it. If you don't plan to fix it please improve the docs.

hot-reload docs

related : 28293

@pranavkm pranavkm added area-commandlinetools Includes: Command line tools, dotnet-dev-certs, dotnet-user-jwts, and OpenAPI feature-dotnetwatch This issue is related to the dotnet-watch command-line tool (now external) feature-hot-reload This issue is related to the Hot Reload feaature labels Dec 6, 2021
@rjgotten
Copy link

rjgotten commented Dec 8, 2021

Hot Reload is a hot mess.

The reason it doesn't work with response compression enabled, is that there's an injector middleware at play which has to wedge a script tag into your response which loads the JavaScript-side of the hot reload infrastructure. It can't do that properly with response bodies which are compressed.

With the SDK shipping with the release version of VS 2022 it actually does still attempt to do that and as a consequence will corrupt the compressed data stream in the response when it can find something resembling the insertion point it is written to check for in the compressed data.

It's an input-dependent bug. Depending on how the compressor compresses your HTML output you'll see different misbehavior from this injector middleware:
either it can still find something resembling the insertion point in the compressed data, inserts its scripts and corrupts the response;
or it cannot, doesn't insert its scripts, and then 'does not work.'

It also completely breaks any and all responses that are type text/html but are not meant as actual top-level pages. For instance: what if I have an authoring application with an HTML editor which wants to load another HTML document via fetch?

There isn't even a proper way to turn the ASP.NET add-ons off and retain only the server-side C# hot reloading features. Even if you switch off the Hot Reload features under Tools -> Projects and Solutions -> ASP.NET Core -> Hot Reload in VS 2022, the script injector will still run. The only way to turn it off 'from the outside' is to configure VS 2022 to turn off the entire hot reloading feature as well as the legacy edit & continue feature, under Tools -> Debugging -> .NET / C++ Hot Reload.

Imho this 'automagical' nature of wiring in a feature which applies potentially destructive mutations to markup and the browser runtime environment is return to WebForms mistakes from the past and whoever decided it was a good idea to include this injector middleware as part of defaults should get a boot up their ass.

With the way they chose to integrate this, Microsoft managed to deliver a feature that is so broken you have to disable it and in doing so actually LOSE functionality (namely - the legacy edit & continue) compared to VS 2019 in the process. It's downright stupid.

@DamianEdwards DamianEdwards added the ✔️ Resolution: Duplicate Resolved as a duplicate of another issue label Jan 21, 2022
@DamianEdwards
Copy link
Member

Duped to #38454.
We'll add logging to ensure finding these incompatibilities is easier.

@rjgotten
Copy link

rjgotten commented Jan 24, 2022

@DamianEdwards
So, let me get this straight: you're marking this as a dupe of an issue that was pushed out to the planning phase for .NET 7, for consideration/evaluation?

You're marking what is clearly a hideous bug in .NET 6 that corrupts response bodies when debugging from VS 2022 with response compression enabled; for which the only simple workaround is to disable and remove feature functionality from Visual Studio 2022, including features that worked fine in VS 2019 and earlier (namely: basic Edit & Continue) -- as a dupe of something that will only potentially be fixed with .NET 7?

When .NET 6 is the actual LTS?

Wow.

Just let me ask here; what is wrong with a very basic

Host
  .CreateDefaultBuilder(args)
  .ConfigureWebHostDefaults(builder => builder
    .UseHotReload(false) // <--- (!!)
    .UseStartup<Startup>()
  );

to prevent the ASP.NET hot-reload middleware features from being used for applications where they would be incompatible?
What ever happened to the philosophy that the developer should be in full control of what gets folded into the application pipeline?
Isn't that why there is a middleware pipeline?
Isn't that why everything is opt-in?

Defaults; sure.
But offer a way to TURN THEM OFF, or a developer-ergonomic path to avoid opting into them in the first place.

[EDIT]
Looks like I have my answer, after some serious snooping through the actual source code to find how this thing was implemented exactly:

Host
  .CreateDefaultBuilder(args)
  .ConfigureWebBuilder(builder => builder
    .UseSetting(WebHostDefaults.HostingStartupExcludeAssembliesKey, "Microsoft.AspNetCore.Watch.BrowserRefresh")
    .UseStartup<Startup>()
  );

Or if anyone else comes across this and is looking for something a bit more ergonomic:

/// <summary>
/// Extends <see cref="IWebHostBuilder" /> with methods to allow or disallow the use
/// of the BrowserRefresh extensions that power the client-side ASP.NET parts of C# hot
/// reloading when connected to a compatible debugging host, like Visual Studio 2022.
/// </summary>
public static class BrowserRefreshWebHostBuilderExtensions
{
  private const string ASSEMBLY_NAME = "Microsoft.AspNetCore.Watch.BrowserRefresh";
  private static string ExclusionKey { get; } = WebHostDefaults.HostingStartupExcludeAssembliesKey;

  /// <summary>
  /// Specifies whether to allow use of the BrowserRefresh extensions that power the client-side
  /// ASP.NET parts of C# hot reloading when connected to a compatible debugging host, like
  /// Visual Studio 2022.
  /// </summary>
  /// <param name="hostBuilder">The <see cref="IWebHostBuilder"/> to configure.</param>
  /// <param name="enabled">Whether the extensions should be enabled or not.</param>
  /// <returns>The <see cref="IWebHostBuilder"/> to configure.</returns>
  /// <exception cref="ArgumentNullException"><paramref name="hostBuilder"/> is <c>null</c>.</exception>
  public static IWebHostBuilder UseBrowserRefresh(this IWebHostBuilder hostBuilder, bool enabled)
  {
    if (hostBuilder is null) throw new ArgumentNullException(nameof(hostBuilder));

    var setting = hostBuilder.GetSetting(ExclusionKey) ?? "";
    var excluded = setting
      .Split(";", StringSplitOptions.RemoveEmptyEntries)
      .ToHashSet(StringComparer.OrdinalIgnoreCase);

    if (
         (  enabled && excluded.Remove(ASSEMBLY_NAME))
      || ( !enabled && excluded.Add(ASSEMBLY_NAME))
    )
    {
      hostBuilder.UseSetting(ExclusionKey, string.Join(";", excluded));
    }

    return hostBuilder;
  }
}

@DamianEdwards
Copy link
Member

Please see my comment in #32767 (comment)

One can disable Hot Reload in the launch/debug profile of the project so that Edit and Continue keeps working but the browser refresh script is not injected.

@ghost ghost locked as resolved and limited conversation to collaborators Feb 23, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-commandlinetools Includes: Command line tools, dotnet-dev-certs, dotnet-user-jwts, and OpenAPI feature-dotnetwatch This issue is related to the dotnet-watch command-line tool (now external) feature-hot-reload This issue is related to the Hot Reload feaature ✔️ Resolution: Duplicate Resolved as a duplicate of another issue Status: Resolved
Projects
None yet
Development

No branches or pull requests

4 participants