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

Blazor Disable Non-WebSockets Transports by Default #34644

Merged
merged 16 commits into from
Jul 27, 2021

Conversation

TanayParikh
Copy link
Contributor

@TanayParikh TanayParikh commented Jul 23, 2021

This PR makes WebSockets the default HTTPTransportType.

Scenarios

Client Server Message
WS (without browser WS support) WebSockets Unable to connect, please ensure you are using an updated browser that supports WebSockets.
WS (with WS connection being rejected) WebSockets Unable to connect, please ensure WebSockets are available. A VPN or proxy may be blocking the connection.
WS LongPolling An unhandled error has occurred. Console Error: Unable to initiate a SignalR connection to the server. This might be because the server is not configured to support WebSockets. To troubleshoot this, visit https://aka.ms/blazor-server-websockets-error.
LongPolling WebSockets An unhandled error has occurred.

See this conversation on the last two error messages being unnecessary.

image

Custom Configuration

Server Side

In Startup.cs, replace endpoints.MapBlazorHub() with:

endpoints.MapBlazorHub(configureOptions: options => 
{ 
    options.Transports = HttpTransportType.WebSockets | HttpTransportType.LongPolling; 
});

Client Side

Add the following script to _Layout.cshtml before the closing </body> tag. WebSockets (1) and Long Polling (4) are the supported HTTPTransportTypes.

<script>
    (function start() {
        Blazor.start({
            configureSignalR: builder => builder.withUrl('_blazor', 4) // Long Polling
        });
    })()
</script>

Fixes: #33775

  • TODO: E2E tests.

@TanayParikh TanayParikh requested a review from a team as a code owner July 23, 2021 16:11
@ghost ghost added the area-blazor Includes: Blazor, Razor Components label Jul 23, 2021
@pranavkm
Copy link
Contributor

@TanayParikh, presumably the overload that does not require a path also works:

 endpoints.MapBlazorHub(configureOptions: options => 
    { 
        options.Transports = HttpTransportType.WebSockets | HttpTransportType.LongPolling; 
    });

?

@TanayParikh
Copy link
Contributor Author

@TanayParikh, presumably the overload that does not require a path also works:

Yep, you're absolutely right, will update the example. Thanks.

return;
}

if (ex.message.includes(`'WebSockets' is not supported in your environment.`)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Would we be able to change SignalR to throw a type and use that here instead of string sniffing: https://developer.mozilla.org/en-US/docs/web/javascript/reference/statements/throw#throw_an_object?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

cc/ @BrennanConroy would you be open to this change?

Copy link
Member

Choose a reason for hiding this comment

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

I'm not against throwing a specific error type at

return Promise.reject(new Error(`Unable to connect to the server with any of the available transports. ${transportExceptions.join(" ")}`));

Much better than doing string matching since those can change at any time.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Just added a Error.name here:

e03d084#diff-757d83bcf707b34888c824c952e4717638803af7b5372f6c5da1eb838f1a5814R450-R452

Due to the way exception nesting is done in the HttpConnection, having the name itself propagate up would likely require a lot more extensive changes. Instead, I'm still relying a bit on string sniffing, but I'm sniffing the custom Error.name instead of the message.

e03d084#diff-7c47c684c78e3f5b5eeecb28b249b03afcefcd90a925cc20b69ec2cdec261752R134

Copy link
Member

Choose a reason for hiding this comment

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

What was wrong with changing the type of exception we throw?

Copy link
Contributor Author

@TanayParikh TanayParikh Jul 23, 2021

Choose a reason for hiding this comment

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

If you're referring to here:

return Promise.reject(new Error(`Unable to connect to the server with any of the available transports. ${transportExceptions.join(" ")}`));

Several different issues can result in an exception being thrown there. So changing the exception type being thrown there wouldn't provide us with specific enough information (ie. diagnose a WS failed connection).

If it's for changing the exception type here instead of the name:
e03d084#diff-757d83bcf707b34888c824c952e4717638803af7b5372f6c5da1eb838f1a5814R451

I just wanted to avoid adding an additional exception type when the spec compliant Error.name would be sufficient for our purposes. Let me know if you feel otherwise and I can add it in.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated 895afb2.

@BrennanConroy
Copy link
Member

BrennanConroy commented Jul 23, 2021

builder.withUrl('_blazor', 4)

That's unfortunate 😢 would be nicer if you could do builder.withTransport(4) or something similar.

(Yes I know that's SignalR's fault)

@TanayParikh TanayParikh force-pushed the taparik/disableNonWSTransportsByDefault branch from 576ec75 to e03d084 Compare July 23, 2021 18:31
@TanayParikh TanayParikh requested a review from halter73 as a code owner July 23, 2021 18:31
@TanayParikh
Copy link
Contributor Author

E2E tests added, ready for review / merging.

src/Components/Web.JS/src/Boot.Server.ts Outdated Show resolved Hide resolved
src/Components/Web.JS/src/Boot.Server.ts Show resolved Hide resolved
builder.configureLogging("debug") // LogLevel.Debug
.withUrl('_blazor',
{
WebSocket: WebSocketNotAllowed,
Copy link
Contributor

Choose a reason for hiding this comment

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

Same for this one. A much more useful test is to have the server disable websockets which would simulates a misconfigured server.

Copy link
Contributor Author

@TanayParikh TanayParikh Jul 26, 2021

Choose a reason for hiding this comment

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

I'm inclined to keep this test as:

WebSocketNotAllowed approach should effectively be the same as the server rejecting a websocket request

I'd discussed testing VPN/proxy issues blocking WebSockets with Brennan, and this was the testing approach suggested. It's part of SignalR's testing mechanism that we're leveraging.

Copy link
Contributor

@pranavkm pranavkm left a comment

Choose a reason for hiding this comment

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

This is looking good. Feel free to IM me if you'd like to hash out the details.

src/Components/Web.JS/src/Boot.Server.ts Show resolved Hide resolved
src/SignalR/clients/ts/signalr/src/HttpConnection.ts Outdated Show resolved Hide resolved
@TanayParikh TanayParikh requested a review from pranavkm July 26, 2021 22:50
@TanayParikh
Copy link
Contributor Author

Breaking Change Announcement: aspnet/Announcements#470

@TanayParikh TanayParikh enabled auto-merge (squash) July 26, 2021 23:17
@TanayParikh TanayParikh disabled auto-merge July 26, 2021 23:18
src/Components/Web.JS/src/Boot.Server.ts Show resolved Hide resolved
Comment on lines +50 to +51
{
options.Transports = Microsoft.AspNetCore.Http.Connections.HttpTransportType.LongPolling;
Copy link
Contributor

Choose a reason for hiding this comment

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

👍🏽

@TanayParikh TanayParikh enabled auto-merge (squash) July 27, 2021 00:09
@TanayParikh TanayParikh merged commit a09fc71 into main Jul 27, 2021
@TanayParikh TanayParikh deleted the taparik/disableNonWSTransportsByDefault branch July 27, 2021 04:26
@ghost ghost added this to the 6.0-rc1 milestone Jul 27, 2021
@@ -650,6 +651,45 @@ export class TransportSendQueue {
}
}

class UnsupportedTransportError extends Error {
Copy link
Member

Choose a reason for hiding this comment

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

if (ex.innerErrors && ex.innerErrors.some(e => e.errorType === 'UnsupportedTransportError' && e.transport === 'WebSockets')) {
showErrorNotification('Unable to connect, please ensure you are using an updated browser that supports WebSockets.');
} else if (ex.innerErrors && ex.innerErrors.some(e => e.errorType === 'FailedToStartTransportError' && e.transport === 'WebSockets')) {
showErrorNotification('Unable to connect, please ensure WebSockets are available. A VPN or proxy may be blocking the connection.');
Copy link
Member

Choose a reason for hiding this comment

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

Unable to connect, please ensure WebSockets are available.

Unable to connect, please ensure WebSockets are available on the server.

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'm not so sure about this as this message is end-user facing and hence I would like to avoid "on the server" as it has no end user configurability. Additionally, it may not be a server issue if the local client VPN/proxy is blocking the connection.

showErrorNotification('Unable to connect, please ensure WebSockets are available. A VPN or proxy may be blocking the connection.');
} else if (ex.innerErrors && ex.innerErrors.some(e => e.errorType === 'DisabledTransportError' && e.transport === 'LongPolling')) {
logger.log(LogLevel.Error, 'Unable to initiate a SignalR connection to the server. This might be because the server is not configured to support WebSockets. To troubleshoot this, visit https://aka.ms/blazor-server-websockets-error.');
showErrorNotification();
Copy link
Member

Choose a reason for hiding this comment

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

Why doesn't this one get a nice UI message?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This represents the case when the client is attempting WS and the server only supports long polling. There's no remedial action the end-user can take here so we just present the generic "Unhandled exception has occurred". Note the developer will be presented a message to check the console and they'll see this error message to resolve the issue.

dougbu pushed a commit that referenced this pull request Sep 18, 2021
* Revert Enforce WebSockets Transport for Blazor (changes introduced in #34644)
* Updated Release JS Files
dougbu added a commit that referenced this pull request Sep 22, 2021
* [release/6.0-rc2] Update dependencies from dotnet/efcore (#36635)

[release/6.0-rc2] Update dependencies from dotnet/efcore

* [release/6.0-rc2] Handle JsonExceptions in RequestDelegateFactory (#36627)

* Handle JsonExceptions like InvalidDataExceptions in RequestDelegateFactory

* Don't catch InvalidDataExceptions when reading JSON

* [release/6.0-rc2] Update dependencies from dotnet/runtime dotnet/efcore (#36651)

[release/6.0-rc2] Update dependencies from dotnet/runtime dotnet/efcore

* Avoid using invalid content type for ValidationProblemDetails (#36618)

Co-authored-by: Safia Abdalla <[email protected]>

* Update dependencies from https://github.com/dotnet/efcore build 20210917.6 (#36667)

[release/6.0-rc2] Update dependencies from dotnet/efcore

* Use a fake clock in the test (#36626)

Co-authored-by: Chris R <[email protected]>

* Update dependencies from https://github.com/dotnet/runtime build 20210917.8 (#36675)

[release/6.0-rc2] Update dependencies from dotnet/runtime

* [release/6.0-rc2] Throw for invalid TryParse and BindAsync (#36662)

* Backport of #36628 to release/6.0-rc2
* Throw for invalid TryParse and BindAsync
* nit
* use TypeNameHelper
* nit

Co-authored-by: Brennan <[email protected]>

* Update dependencies from https://github.com/dotnet/efcore build 20210917.8 (#36681)

[release/6.0-rc2] Update dependencies from dotnet/efcore

* Revert Enforce WebSockets Transport for Blazor (#36656)

* Revert Enforce WebSockets Transport for Blazor (changes introduced in #34644)
* Updated Release JS Files

* [release/6.0-rc2] Update dependencies from dotnet/runtime dotnet/efcore (#36687)

[release/6.0-rc2] Update dependencies from dotnet/runtime dotnet/efcore

* Update dependencies from https://github.com/dotnet/runtime build 20210917.25 (#36699)

[release/6.0-rc2] Update dependencies from dotnet/runtime

* Update dependencies from https://github.com/dotnet/efcore build 20210917.18 (#36701)

[release/6.0-rc2] Update dependencies from dotnet/efcore

* [release/6.0-rc2] Update dependencies from dotnet/efcore dotnet/runtime (#36706)

[release/6.0-rc2] Update dependencies from dotnet/efcore dotnet/runtime

* [Release/6.0-rc2] Fix and test HttpSys delegation (#36698)

* Out of proc delegation tests
* Troubleshoot IsFeatureSupported
* Fix test
* Fix formatting
* Seperate tests
* Cleanup
* Fix SLN

* Update dependencies from https://github.com/dotnet/efcore build 20210918.7 (#36715)

[release/6.0-rc2] Update dependencies from dotnet/efcore

* Find inherited TryParse and BindAsync (#36694)

Co-authored-by: Brennan <[email protected]>

* [release/6.0-rc2] Use minimal APIs for F# project templates (#36660)

* [release/6.0-rc2] Retarget DOTNETHOME when installing x64 on ARM64 (#36695)

* Retarget DOTNETHOME when installing x64 on ARM64

* Make platform comparison case insenstive

* Address feedback

* Install x64 registry keys to different path on ARM64 machine

Co-authored-by: Eric StJohn <[email protected]>

* Pin analyzers that ship in the SDK (#36690) (#36754)

* Pin analyzers that ship in the SDK (#36690)

* Pin analyzers that ship in the SDK

ASP.NET Core produces a few analyzer assemblies that are shipped as part of the .NET SDK. These analyzers are added to web projects targeting 3.1 and newer.
In 6.0, we (unintentionally) bumped the version of Microsoft.CodeAnalysis that these projects referenced to a 4.0 version. This causes warnings when opening
a 3.1 or 5.0 app in VS 2019 as it does not support these versions.

Additionally update the version of Microsoft.CodeAnalysis.* packages used in tests, Razor, and framework analyzers that are only expected to run with VS 2020 to a more recent build. This is largely book-keeping, but allows us
to write a test for file scoped namespaces.

Fixes #36552

* Apply suggestions from code review

* [release/6.0-rc2] Rename and consolidate  "DelegateEndpoint" types (#36578)

* Call AddEndpointsApiExplorer() in controllers Web API template (#36753)

- backport of #36752 to release/6.0-rc2

Co-authored-by: DamianEdwards <[email protected]>

* [release/6.0-rc2] Update dependencies from dotnet/efcore dotnet/runtime (#36769)

[release/6.0-rc2] Update dependencies from dotnet/efcore dotnet/runtime

* Update dependencies from https://github.com/dotnet/efcore build 20210920.20 (#36778)

[release/6.0-rc2] Update dependencies from dotnet/efcore

Co-authored-by: dotnet-maestro[bot] <42748379+dotnet-maestro[bot]@users.noreply.github.com>
Co-authored-by: Stephen Halter <[email protected]>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Safia Abdalla <[email protected]>
Co-authored-by: Chris R <[email protected]>
Co-authored-by: Brennan <[email protected]>
Co-authored-by: Tanay Parikh <[email protected]>
Co-authored-by: Chris Ross <[email protected]>
Co-authored-by: Eric StJohn <[email protected]>
Co-authored-by: Pranav K <[email protected]>
Co-authored-by: DamianEdwards <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-blazor Includes: Blazor, Razor Components
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Disable non-websocket transports for Blazor Server
4 participants