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:
Steve Sanderson 2019-07-22 07:52:20 -07:00 committed by GitHub
parent 330a7708c0
commit 178374d228
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 31 additions and 16 deletions

File diff suppressed because one or more lines are too long

View File

@ -105,7 +105,10 @@ async function initializeConnection(options: BlazorOptions, logger: Logger): Pro
});
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();
@ -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.
if (connection) {
renderingFailed = true;
connection.stop();
}
}

View File

@ -9,6 +9,8 @@ export class DefaultReconnectDisplay implements ReconnectDisplay {
addedToDom: boolean = false;
reloadParagraph: HTMLParagraphElement;
constructor(dialogId: string, private document: Document) {
this.modal = this.document.createElement('div');
this.modal.id = dialogId;
@ -29,11 +31,13 @@ export class DefaultReconnectDisplay implements ReconnectDisplay {
];
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.button = this.modal.querySelector('button')!;
this.reloadParagraph = this.modal.querySelector('p')!;
this.button.addEventListener('click', () => window['Blazor'].reconnect());
this.reloadParagraph.querySelector('a')!.addEventListener('click', () => location.reload());
}
show(): void {
@ -43,6 +47,7 @@ export class DefaultReconnectDisplay implements ReconnectDisplay {
}
this.modal.style.display = 'block';
this.button.style.display = 'none';
this.reloadParagraph.style.display = 'none';
this.message.textContent = 'Attempting to reconnect to the server...';
}
@ -52,6 +57,7 @@ export class DefaultReconnectDisplay implements ReconnectDisplay {
failed(): void {
this.button.style.display = 'block';
this.reloadParagraph.style.display = 'block';
this.message.textContent = 'Failed to reconnect to the server.';
}
}

View File

@ -6,19 +6,26 @@ import { Logger, LogLevel } from '../Logging/Logger';
export class DefaultReconnectionHandler implements ReconnectionHandler {
private readonly _logger: Logger;
private readonly _overrideDisplay?: ReconnectDisplay;
private readonly _reconnectCallback: () => Promise<boolean>;
private _currentReconnectionProcess: ReconnectionProcess | null = null;
private _reconnectionDisplay?: ReconnectDisplay;
constructor(logger: Logger, overrideDisplay?: ReconnectDisplay, reconnectCallback?: () => Promise<boolean>) {
this._logger = logger;
this._overrideDisplay = overrideDisplay;
this._reconnectionDisplay = overrideDisplay;
this._reconnectCallback = reconnectCallback || (() => window['Blazor'].reconnect());
}
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) {
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;
isDisposed = false;
constructor(options: ReconnectionOptions, private logger: Logger, private reconnectCallback: () => Promise<boolean>, display?: ReconnectDisplay) {
const modal = document.getElementById(options.dialogId);
this.reconnectDisplay = display || (modal
? new UserSpecifiedDisplay(modal)
: new DefaultReconnectDisplay(options.dialogId, document));
constructor(options: ReconnectionOptions, private logger: Logger, private reconnectCallback: () => Promise<boolean>, display: ReconnectDisplay) {
this.reconnectDisplay = display;
this.reconnectDisplay.show();
this.attemptPeriodicReconnection(options);
}

View File

@ -20,7 +20,11 @@
configureSignalR: function (builder) {
builder.configureLogging(2); // LogLevel.Information
},
logLevel: 2 // LogLevel.Information
logLevel: 2, // LogLevel.Information
reconnectionOptions: {
maxRetries: 3,
retryIntervalMilliseconds: 2000,
}
}).then(function () {
window['__aspnetcore__testing__blazor__started__'] = true;
});