Skip to content

Commit 0cd1ddd

Browse files
committed
Refactor SignalR Transports Errors
Fixes: #34765
1 parent ac3a403 commit 0cd1ddd

File tree

5 files changed

+113
-49
lines changed

5 files changed

+113
-49
lines changed

src/Components/Web.JS/dist/Release/blazor.server.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Components/Web.JS/src/Boot.Server.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { DotNet } from '@microsoft/dotnet-js-interop';
22
import { Blazor } from './GlobalExports';
3-
import { HubConnectionBuilder, HubConnection, HttpTransportType } from '@microsoft/signalr';
3+
import { HubConnectionBuilder, HubConnection, HttpTransportType, AggregateErrors, DisabledTransportError, FailedToStartTransportError, UnsupportedTransportError } from '@microsoft/signalr';
44
import { MessagePackHubProtocol } from '@microsoft/signalr-protocol-msgpack';
55
import { showErrorNotification } from './BootErrors';
66
import { shouldAutoStart } from './BootCommon';
@@ -131,11 +131,11 @@ async function initializeConnection(options: CircuitStartOptions, logger: Logger
131131
} catch (ex) {
132132
unhandledError(connection, ex, logger);
133133

134-
if (ex.innerErrors && ex.innerErrors.some(e => e.errorType === 'UnsupportedTransportError' && e.transport === 'WebSockets')) {
134+
if (ex instanceof AggregateErrors && ex.innerErrors.some(e => e instanceof UnsupportedTransportError && e.transport === HttpTransportType.WebSockets)) {
135135
showErrorNotification('Unable to connect, please ensure you are using an updated browser that supports WebSockets.');
136-
} else if (ex.innerErrors && ex.innerErrors.some(e => e.errorType === 'FailedToStartTransportError' && e.transport === 'WebSockets')) {
136+
} else if (ex instanceof AggregateErrors && ex.innerErrors.some(e => e instanceof FailedToStartTransportError && e.transport === HttpTransportType.WebSockets)) {
137137
showErrorNotification('Unable to connect, please ensure WebSockets are available. A VPN or proxy may be blocking the connection.');
138-
} else if (ex.innerErrors && ex.innerErrors.some(e => e.errorType === 'DisabledTransportError' && e.transport === 'LongPolling')) {
138+
} else if (ex instanceof AggregateErrors && ex.innerErrors.some(e => e instanceof DisabledTransportError && e.transport === HttpTransportType.LongPolling)) {
139139
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.');
140140
showErrorNotification();
141141
} else {

src/SignalR/clients/ts/signalr/src/Errors.ts

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
import { HttpTransportType } from "./ITransport";
5+
46
/** Error thrown when an HTTP request fails. */
57
export class HttpError extends Error {
68
// @ts-ignore: Intentionally unused.
@@ -65,3 +67,104 @@ export class AbortError extends Error {
6567
this.__proto__ = trueProto;
6668
}
6769
}
70+
71+
/** Error thrown when the selected transport is unsupported by the browser. */
72+
export class UnsupportedTransportError extends Error {
73+
// @ts-ignore: Intentionally unused.
74+
// eslint-disable-next-line @typescript-eslint/naming-convention
75+
private __proto__: Error;
76+
77+
/** The {@link @microsoft/signalr.HttpTransportType} this error occured on. */
78+
public transport: HttpTransportType;
79+
80+
/** Constructs a new instance of {@link @microsoft/signalr.UnsupportedTransportError}.
81+
*
82+
* @param {string} message A descriptive error message.
83+
* @param {HttpTransportType} transport The {@link @microsoft/signalr.HttpTransportType} this error occured on.
84+
*/
85+
constructor(message: string, transport: HttpTransportType) {
86+
const trueProto = new.target.prototype;
87+
super(message);
88+
this.transport = transport;
89+
90+
// Workaround issue in Typescript compiler
91+
// https://github.com/Microsoft/TypeScript/issues/13965#issuecomment-278570200
92+
this.__proto__ = trueProto;
93+
}
94+
}
95+
96+
/** Error thrown when the selected transport is disabled by the browser. */
97+
export class DisabledTransportError extends Error {
98+
// @ts-ignore: Intentionally unused.
99+
// eslint-disable-next-line @typescript-eslint/naming-convention
100+
private __proto__: Error;
101+
102+
/** The {@link @microsoft/signalr.HttpTransportType} this error occured on. */
103+
public transport: HttpTransportType;
104+
105+
/** Constructs a new instance of {@link @microsoft/signalr.DisabledTransportError}.
106+
*
107+
* @param {string} message A descriptive error message.
108+
* @param {HttpTransportType} transport The {@link @microsoft/signalr.HttpTransportType} this error occured on.
109+
*/
110+
constructor(message: string, transport: HttpTransportType) {
111+
const trueProto = new.target.prototype;
112+
super(message);
113+
this.transport = transport;
114+
115+
// Workaround issue in Typescript compiler
116+
// https://github.com/Microsoft/TypeScript/issues/13965#issuecomment-278570200
117+
this.__proto__ = trueProto;
118+
}
119+
}
120+
121+
/** Error thrown when the selected transport cannot be started. */
122+
export class FailedToStartTransportError extends Error {
123+
// @ts-ignore: Intentionally unused.
124+
// eslint-disable-next-line @typescript-eslint/naming-convention
125+
private __proto__: Error;
126+
127+
/** The {@link @microsoft/signalr.HttpTransportType} this error occured on. */
128+
public transport: HttpTransportType;
129+
130+
/** Constructs a new instance of {@link @microsoft/signalr.FailedToStartTransportError}.
131+
*
132+
* @param {string} message A descriptive error message.
133+
* @param {HttpTransportType} transport The {@link @microsoft/signalr.HttpTransportType} this error occured on.
134+
*/
135+
constructor(message: string, transport: HttpTransportType) {
136+
const trueProto = new.target.prototype;
137+
super(message);
138+
this.transport = transport;
139+
140+
// Workaround issue in Typescript compiler
141+
// https://github.com/Microsoft/TypeScript/issues/13965#issuecomment-278570200
142+
this.__proto__ = trueProto;
143+
}
144+
}
145+
146+
/** Error thrown when multiple errors have occured. */
147+
export class AggregateErrors extends Error {
148+
// @ts-ignore: Intentionally unused.
149+
// eslint-disable-next-line @typescript-eslint/naming-convention
150+
private __proto__: Error;
151+
152+
/** The collection of errors this error is aggregating. */
153+
public innerErrors: Error[];
154+
155+
/** Constructs a new instance of {@link @microsoft/signalr.AggregateErrors}.
156+
*
157+
* @param {string} message A descriptive error message.
158+
* @param {Error[]} innerErrors The collection of errors this error is aggregating.
159+
*/
160+
constructor(message: string, innerErrors: Error[]) {
161+
const trueProto = new.target.prototype;
162+
super(message);
163+
164+
this.innerErrors = innerErrors;
165+
166+
// Workaround issue in Typescript compiler
167+
// https://github.com/Microsoft/TypeScript/issues/13965#issuecomment-278570200
168+
this.__proto__ = trueProto;
169+
}
170+
}

src/SignalR/clients/ts/signalr/src/HttpConnection.ts

Lines changed: 4 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
import { DefaultHttpClient } from "./DefaultHttpClient";
5-
import { HttpError } from "./Errors";
5+
import { AggregateErrors, DisabledTransportError, FailedToStartTransportError, HttpError, UnsupportedTransportError } from "./Errors";
66
import { HeaderNames } from "./HeaderNames";
77
import { HttpClient } from "./HttpClient";
88
import { IConnection } from "./IConnection";
@@ -394,7 +394,7 @@ export class HttpConnection implements IConnection {
394394
} catch (ex) {
395395
this._logger.log(LogLevel.Error, `Failed to start the transport '${endpoint.transport}': ${ex}`);
396396
negotiate = undefined;
397-
transportExceptions.push(new FailedToStartTransportError(`${endpoint.transport} failed: ${ex}`, endpoint.transport));
397+
transportExceptions.push(new FailedToStartTransportError(`${endpoint.transport} failed: ${ex}`, HttpTransportType[endpoint.transport]));
398398

399399
if (this._connectionState !== ConnectionState.Connecting) {
400400
const message = "Failed to select transport before stop() was called.";
@@ -448,7 +448,7 @@ export class HttpConnection implements IConnection {
448448
if ((transport === HttpTransportType.WebSockets && !this._options.WebSocket) ||
449449
(transport === HttpTransportType.ServerSentEvents && !this._options.EventSource)) {
450450
this._logger.log(LogLevel.Debug, `Skipping transport '${HttpTransportType[transport]}' because it is not supported in your environment.'`);
451-
return new UnsupportedTransportError(`'${HttpTransportType[transport]}' is not supported in your environment.`, HttpTransportType[transport]);
451+
return new UnsupportedTransportError(`'${HttpTransportType[transport]}' is not supported in your environment.`, transport);
452452
} else {
453453
this._logger.log(LogLevel.Debug, `Selecting transport '${HttpTransportType[transport]}'.`);
454454
try {
@@ -463,7 +463,7 @@ export class HttpConnection implements IConnection {
463463
}
464464
} else {
465465
this._logger.log(LogLevel.Debug, `Skipping transport '${HttpTransportType[transport]}' because it was disabled by the client.`);
466-
return new DisabledTransportError(`'${HttpTransportType[transport]}' is disabled by the client.`, HttpTransportType[transport]);
466+
return new DisabledTransportError(`'${HttpTransportType[transport]}' is disabled by the client.`, transport);
467467
}
468468
}
469469
}
@@ -651,45 +651,6 @@ export class TransportSendQueue {
651651
}
652652
}
653653

654-
class UnsupportedTransportError extends Error {
655-
public errorType: string;
656-
public transport: string;
657-
658-
constructor(public message: string, transport: string) {
659-
super(message);
660-
this.errorType = 'UnsupportedTransportError';
661-
this.transport = transport;
662-
}
663-
}
664-
665-
class DisabledTransportError extends Error {
666-
public errorType: string;
667-
public transport: string;
668-
669-
constructor(public message: string, transport: string) {
670-
super(message);
671-
this.errorType = 'DisabledTransportError';
672-
this.transport = transport;
673-
}
674-
}
675-
676-
class FailedToStartTransportError extends Error {
677-
public errorType: string;
678-
public transport: string;
679-
680-
constructor(public message: string, transport: string) {
681-
super(message);
682-
this.errorType = 'FailedToStartTransportError';
683-
this.transport = transport;
684-
}
685-
}
686-
687-
class AggregateErrors extends Error {
688-
constructor(public message: string, public innerErrors: Error[]) {
689-
super(message);
690-
}
691-
}
692-
693654
class PromiseSource {
694655
private _resolver?: () => void;
695656
private _rejecter!: (reason?: any) => void;

src/SignalR/clients/ts/signalr/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
// Everything that users need to access must be exported here. Including interfaces.
55
export { AbortSignal } from "./AbortController";
6-
export { AbortError, HttpError, TimeoutError } from "./Errors";
6+
export { AbortError, HttpError, TimeoutError, AggregateErrors, DisabledTransportError, FailedToStartTransportError, UnsupportedTransportError } from "./Errors";
77
export { HttpClient, HttpRequest, HttpResponse } from "./HttpClient";
88
export { DefaultHttpClient } from "./DefaultHttpClient";
99
export { IHttpConnectionOptions } from "./IHttpConnectionOptions";

0 commit comments

Comments
 (0)