Make reconnection work more realistically (#12420)
* Support reconnection even if an earlier attempt failed * Add "reload" button to reconnect dialog on failure * Update blazor.*.js
This commit is contained in:
parent
330a7708c0
commit
178374d228
File diff suppressed because one or more lines are too long
|
|
@ -105,7 +105,10 @@ async function initializeConnection(options: BlazorOptions, logger: Logger): Pro
|
||||||
});
|
});
|
||||||
|
|
||||||
connection.onclose(error => !renderingFailed && options.reconnectionHandler!.onConnectionDown(options.reconnectionOptions, error));
|
connection.onclose(error => !renderingFailed && options.reconnectionHandler!.onConnectionDown(options.reconnectionOptions, error));
|
||||||
connection.on('JS.Error', error => unhandledError(connection, error, logger));
|
connection.on('JS.Error', error => {
|
||||||
|
renderingFailed = true;
|
||||||
|
unhandledError(connection, error, logger);
|
||||||
|
});
|
||||||
|
|
||||||
window['Blazor']._internal.forceCloseConnection = () => connection.stop();
|
window['Blazor']._internal.forceCloseConnection = () => connection.stop();
|
||||||
|
|
||||||
|
|
@ -134,7 +137,6 @@ function unhandledError(connection: signalR.HubConnection, err: Error, logger: L
|
||||||
//
|
//
|
||||||
// Trying to call methods on the connection after its been closed will throw.
|
// Trying to call methods on the connection after its been closed will throw.
|
||||||
if (connection) {
|
if (connection) {
|
||||||
renderingFailed = true;
|
|
||||||
connection.stop();
|
connection.stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,8 @@ export class DefaultReconnectDisplay implements ReconnectDisplay {
|
||||||
|
|
||||||
addedToDom: boolean = false;
|
addedToDom: boolean = false;
|
||||||
|
|
||||||
|
reloadParagraph: HTMLParagraphElement;
|
||||||
|
|
||||||
constructor(dialogId: string, private document: Document) {
|
constructor(dialogId: string, private document: Document) {
|
||||||
this.modal = this.document.createElement('div');
|
this.modal = this.document.createElement('div');
|
||||||
this.modal.id = dialogId;
|
this.modal.id = dialogId;
|
||||||
|
|
@ -29,11 +31,13 @@ export class DefaultReconnectDisplay implements ReconnectDisplay {
|
||||||
];
|
];
|
||||||
|
|
||||||
this.modal.style.cssText = modalStyles.join(';');
|
this.modal.style.cssText = modalStyles.join(';');
|
||||||
this.modal.innerHTML = '<h5 style="margin-top: 20px"></h5><button style="margin:5px auto 5px">Retry?</button>';
|
this.modal.innerHTML = '<h5 style="margin-top: 20px"></h5><button style="margin:5px auto 5px">Retry?</button><p>Alternatively, <a href>reload</a></p>';
|
||||||
this.message = this.modal.querySelector('h5')!;
|
this.message = this.modal.querySelector('h5')!;
|
||||||
this.button = this.modal.querySelector('button')!;
|
this.button = this.modal.querySelector('button')!;
|
||||||
|
this.reloadParagraph = this.modal.querySelector('p')!;
|
||||||
|
|
||||||
this.button.addEventListener('click', () => window['Blazor'].reconnect());
|
this.button.addEventListener('click', () => window['Blazor'].reconnect());
|
||||||
|
this.reloadParagraph.querySelector('a')!.addEventListener('click', () => location.reload());
|
||||||
}
|
}
|
||||||
|
|
||||||
show(): void {
|
show(): void {
|
||||||
|
|
@ -43,6 +47,7 @@ export class DefaultReconnectDisplay implements ReconnectDisplay {
|
||||||
}
|
}
|
||||||
this.modal.style.display = 'block';
|
this.modal.style.display = 'block';
|
||||||
this.button.style.display = 'none';
|
this.button.style.display = 'none';
|
||||||
|
this.reloadParagraph.style.display = 'none';
|
||||||
this.message.textContent = 'Attempting to reconnect to the server...';
|
this.message.textContent = 'Attempting to reconnect to the server...';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -52,6 +57,7 @@ export class DefaultReconnectDisplay implements ReconnectDisplay {
|
||||||
|
|
||||||
failed(): void {
|
failed(): void {
|
||||||
this.button.style.display = 'block';
|
this.button.style.display = 'block';
|
||||||
|
this.reloadParagraph.style.display = 'block';
|
||||||
this.message.textContent = 'Failed to reconnect to the server.';
|
this.message.textContent = 'Failed to reconnect to the server.';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,19 +6,26 @@ import { Logger, LogLevel } from '../Logging/Logger';
|
||||||
|
|
||||||
export class DefaultReconnectionHandler implements ReconnectionHandler {
|
export class DefaultReconnectionHandler implements ReconnectionHandler {
|
||||||
private readonly _logger: Logger;
|
private readonly _logger: Logger;
|
||||||
private readonly _overrideDisplay?: ReconnectDisplay;
|
|
||||||
private readonly _reconnectCallback: () => Promise<boolean>;
|
private readonly _reconnectCallback: () => Promise<boolean>;
|
||||||
private _currentReconnectionProcess: ReconnectionProcess | null = null;
|
private _currentReconnectionProcess: ReconnectionProcess | null = null;
|
||||||
|
private _reconnectionDisplay?: ReconnectDisplay;
|
||||||
|
|
||||||
constructor(logger: Logger, overrideDisplay?: ReconnectDisplay, reconnectCallback?: () => Promise<boolean>) {
|
constructor(logger: Logger, overrideDisplay?: ReconnectDisplay, reconnectCallback?: () => Promise<boolean>) {
|
||||||
this._logger = logger;
|
this._logger = logger;
|
||||||
this._overrideDisplay = overrideDisplay;
|
this._reconnectionDisplay = overrideDisplay;
|
||||||
this._reconnectCallback = reconnectCallback || (() => window['Blazor'].reconnect());
|
this._reconnectCallback = reconnectCallback || (() => window['Blazor'].reconnect());
|
||||||
}
|
}
|
||||||
|
|
||||||
onConnectionDown (options: ReconnectionOptions, error?: Error) {
|
onConnectionDown (options: ReconnectionOptions, error?: Error) {
|
||||||
|
if (!this._reconnectionDisplay) {
|
||||||
|
const modal = document.getElementById(options.dialogId);
|
||||||
|
this._reconnectionDisplay = modal
|
||||||
|
? new UserSpecifiedDisplay(modal)
|
||||||
|
: new DefaultReconnectDisplay(options.dialogId, document);
|
||||||
|
}
|
||||||
|
|
||||||
if (!this._currentReconnectionProcess) {
|
if (!this._currentReconnectionProcess) {
|
||||||
this._currentReconnectionProcess = new ReconnectionProcess(options, this._logger, this._reconnectCallback, this._overrideDisplay);
|
this._currentReconnectionProcess = new ReconnectionProcess(options, this._logger, this._reconnectCallback, this._reconnectionDisplay!);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -34,12 +41,8 @@ class ReconnectionProcess {
|
||||||
readonly reconnectDisplay: ReconnectDisplay;
|
readonly reconnectDisplay: ReconnectDisplay;
|
||||||
isDisposed = false;
|
isDisposed = false;
|
||||||
|
|
||||||
constructor(options: ReconnectionOptions, private logger: Logger, private reconnectCallback: () => Promise<boolean>, display?: ReconnectDisplay) {
|
constructor(options: ReconnectionOptions, private logger: Logger, private reconnectCallback: () => Promise<boolean>, display: ReconnectDisplay) {
|
||||||
const modal = document.getElementById(options.dialogId);
|
this.reconnectDisplay = display;
|
||||||
this.reconnectDisplay = display || (modal
|
|
||||||
? new UserSpecifiedDisplay(modal)
|
|
||||||
: new DefaultReconnectDisplay(options.dialogId, document));
|
|
||||||
|
|
||||||
this.reconnectDisplay.show();
|
this.reconnectDisplay.show();
|
||||||
this.attemptPeriodicReconnection(options);
|
this.attemptPeriodicReconnection(options);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,11 @@
|
||||||
configureSignalR: function (builder) {
|
configureSignalR: function (builder) {
|
||||||
builder.configureLogging(2); // LogLevel.Information
|
builder.configureLogging(2); // LogLevel.Information
|
||||||
},
|
},
|
||||||
logLevel: 2 // LogLevel.Information
|
logLevel: 2, // LogLevel.Information
|
||||||
|
reconnectionOptions: {
|
||||||
|
maxRetries: 3,
|
||||||
|
retryIntervalMilliseconds: 2000,
|
||||||
|
}
|
||||||
}).then(function () {
|
}).then(function () {
|
||||||
window['__aspnetcore__testing__blazor__started__'] = true;
|
window['__aspnetcore__testing__blazor__started__'] = true;
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue