Skip to content
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

Add a middleware for browser refresh. #24574

Merged
merged 8 commits into from
Aug 7, 2020

Conversation

pranavkm
Copy link
Contributor

@pranavkm pranavkm commented Aug 5, 2020

  • Introduce a middleware that can connect to the dotnet-watch change server
  • dotnet-watch: Inject the middleware in 3.1 or apps using start hooks \ hosting startup

#23412

@pranavkm pranavkm force-pushed the prkrishn/browser-refresh branch 3 times, most recently from b401d73 to 004d735 Compare August 5, 2020 16:50
@pranavkm pranavkm marked this pull request as ready for review August 5, 2020 17:21
@BrennanConroy
Copy link
Member

Did you mean to put this in preview8?

Tactics Ask Mode - ship blocking only

* Introduce a middleware that can connect to the dotnet-watch change server
* dotnet-watch: Inject the middleware in 3.1 or apps using start hooks \ hosting startup

#23412
@pranavkm pranavkm force-pushed the prkrishn/browser-refresh branch from 004d735 to 54ad088 Compare August 5, 2020 17:40
@@ -20,7 +20,7 @@
The web sdk adds an implicit framework reference. This removes it until we can update our build to use framework references.
-->
<ItemGroup>
<FrameworkReference Remove="Microsoft.AspNetCore.App" />
<FrameworkReference Remove="Microsoft.AspNetCore.App" Condition="'$(DoNotApplyWorkaroundsToMicrosoftAspNetCoreApp)' != 'true'" />
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI @wtgodbe

@@ -147,7 +147,7 @@
<KnownFrameworkReference Condition="'$(UseAspNetCoreSharedRuntime)' != 'true'" Remove="Microsoft.AspNetCore.App" />
<KnownFrameworkReference Remove="Microsoft.WindowsDesktop.App" />

<KnownFrameworkReference Condition="'$(UseAspNetCoreSharedRuntime)' == 'true'" Update="Microsoft.AspNetCore.App">
<KnownFrameworkReference Condition="'$(UseAspNetCoreSharedRuntime)' == 'true' AND '$(DoNotApplyWorkaroundsToMicrosoftAspNetCoreApp)' != 'true'" Update="Microsoft.AspNetCore.App">
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI @wtgodbe

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remind me what the motivation was for this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We wanted a middleware that targeted netcoreapp3.1 and compiled against M.AspNetCore.App. UseAspNetCoreSharedRuntime is required to keep the shared runtime reference around, but I didn't want to compile against 5.0.0-dev.

{
public static void Initialize()
{
// We're in!
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe a bit more details here 😄

@Pilchie Pilchie added the area-commandlinetools Includes: Command line tools, dotnet-dev-certs, dotnet-user-jwts, and OpenAPI label Aug 5, 2020

private static string GetWebSocketClientJavaScript()
{
var hostString = Environment.GetEnvironmentVariable("ASPNETCORE_AUTO_RELOAD_WS_ENDPOINT");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this really be pulling direct from env variables vs reading through config and/or options?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The middleware doesn't really interact with the remainder of the user app so an option definitely seems overkill. There isn't really a scenario where we'd want to use values that dotnet-watch did not set. Do you think it's still useful for us to use config here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At a minimum some indirection would make it easier to test.

@mkArtakMSFT mkArtakMSFT added ask-mode This issue / PR is a patch candidate which we will bar-check internally before patching it. Servicing-consider Shiproom approval is required for the issue labels Aug 5, 2020
@ghost
Copy link

ghost commented Aug 5, 2020

Hello human! Please make sure you've included the Shiproom Template in a comment or (preferably) the PR description. Also, make sure this PR is not marked as a draft and is ready-to-merge.

@mkArtakMSFT mkArtakMSFT added this to the 5.0.0-preview8 milestone Aug 5, 2020
@pranavkm
Copy link
Contributor Author

pranavkm commented Aug 5, 2020

🆙 📅

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

public async Task InvokeAsync(HttpContext context)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do I disable this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are environment switches for dotnet-watch to turn this off:

DOTNET_WATCH_SUPPRESS_BROWSER_REFRESH=0. I should update the documentation for this.

return false;
}

var typedHeaders = request.GetTypedHeaders();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you do a fast path check for a text\html content type


if (IsHtmlResponse && !ScriptInjectionPerformed)
{
ScriptInjectionPerformed = await WebSocketScriptInjection.Instance.TryInjectLiveReloadScriptAsync(_baseStream, buffer, offset, count);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
ScriptInjectionPerformed = await WebSocketScriptInjection.Instance.TryInjectLiveReloadScriptAsync(_baseStream, buffer, offset, count);
ScriptInjectionPerformed = await WebSocketScriptInjection.Instance.TryInjectLiveReloadScriptAsync(_baseStream, buffer, offset, count, cancellationToken);

_baseStream,
materialized,
0,
materialized.Length);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
materialized.Length);
materialized.Length,
cancellationToken);

@pranavkm
Copy link
Contributor Author

pranavkm commented Aug 5, 2020

Description

As of 5.0-preview8, dotnet-watch run supports launching the browser as part of starting an application. This change further enhances the experience by refreshing the browser on file changes.

Customer impact

Changes to dotnet-watch come from our CLI user testing. We think these are compelling scenarios we'd like to get early feedback for.

Regression

No

Risk

Medium. This change includes injecting code in to a user's app launched via dotnet watch run and rewriting the output. There's a chance that we break the user output, however we'd like to find these out sooner so we can address it for rc1 and there are switches to turn off this behavior if it affects developers.

// <autogenerated />
using System;
using System.Reflection;
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v5.0", FrameworkDisplayName = "")]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These shouldn't be checked in should they?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope. I should get to the bottom of why they get generated in these path.

Copy link
Member

@dougbu dougbu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First comment is the most important

PrivateAssets="All"
ReferenceOutputAssembly="false"
SkipGetTargetFrameworkProperties="true"
UndefineProperties="TargetFramework;TargetFrameworks" />
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not now (because the metadata won't be handled correctly) but when this is merging into 'master', switch to use a @(Reference) item instead. We're avoiding direct project references as much as possible.

<Target Name="_FixupRuntimeConfig" BeforeTargets="_GenerateRuntimeConfigurationFilesInputCache">
<ItemGroup>
<_RuntimeFramework Include="@(RuntimeFramework)" />
<RuntimeFramework Remove="@(RuntimeFramework)" />
<RuntimeFramework Include="Microsoft.AspNetCore.App" FrameworkName="Microsoft.AspNetCore.App" Version="5.0.0-preview" />
<RuntimeFramework Include="Microsoft.AspNetCore.App" FrameworkName="Microsoft.AspNetCore.App" Version="5.0.0-preview.7.20329.4" />
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this specific version instead of letting it float? This looks odd outside eng/Versions.props in any case.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed this back to the earlier version. I had an earlier build of the runtime locally which didn't have some of the newer runtime types such as the non-generic TaskCompletionSource. I need to sort this out soon for rc1 since it also affects blazor

@pranavkm pranavkm force-pushed the prkrishn/browser-refresh branch from cfae514 to fa40263 Compare August 6, 2020 00:18
@mkArtakMSFT mkArtakMSFT added Servicing-approved Shiproom has approved the issue and removed Servicing-consider Shiproom approval is required for the issue labels Aug 6, 2020
@danroth27 danroth27 mentioned this pull request Aug 6, 2020
4 tasks
@mkArtakMSFT mkArtakMSFT merged commit 146d316 into release/5.0-preview8 Aug 7, 2020
@mkArtakMSFT mkArtakMSFT deleted the prkrishn/browser-refresh branch August 7, 2020 00:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-commandlinetools Includes: Command line tools, dotnet-dev-certs, dotnet-user-jwts, and OpenAPI ask-mode This issue / PR is a patch candidate which we will bar-check internally before patching it. Servicing-approved Shiproom has approved the issue
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants