aspnetcore/src/Components/Server/src/Circuits/CircuitHost.cs

871 lines
43 KiB
C#

// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Security.Claims;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.Web.Rendering;
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.JSInterop;
namespace Microsoft.AspNetCore.Components.Server.Circuits
{
internal class CircuitHost : IAsyncDisposable
{
private readonly IServiceScope _scope;
private readonly CircuitOptions _options;
private readonly CircuitHandler[] _circuitHandlers;
private readonly ILogger _logger;
private bool _initialized;
private bool _disposed;
/// <summary>
/// Sets the <see cref="IJSRuntime"/> for the current excution context.
/// </summary>
public void SetCurrentJSRuntime() => JSInterop.JSRuntime.SetCurrentJSRuntime(JSRuntime);
// This event is fired when there's an unrecoverable exception coming from the circuit, and
// it need so be torn down. The registry listens to this even so that the circuit can
// be torn down even when a client is not connected.
//
// We don't expect the registry to do anything with the exception. We only provide it here
// for testability.
public event UnhandledExceptionEventHandler UnhandledException;
public CircuitHost(
string circuitId,
IServiceScope scope,
CircuitOptions options,
CircuitClientProxy client,
RemoteRenderer renderer,
IReadOnlyList<ComponentDescriptor> descriptors,
RemoteJSRuntime jsRuntime,
CircuitHandler[] circuitHandlers,
ILogger logger)
{
CircuitId = circuitId ?? throw new ArgumentNullException(nameof(circuitId));
_scope = scope ?? throw new ArgumentNullException(nameof(scope));
_options = options ?? throw new ArgumentNullException(nameof(options));
Client = client ?? throw new ArgumentNullException(nameof(client));
Renderer = renderer ?? throw new ArgumentNullException(nameof(renderer));
Descriptors = descriptors ?? throw new ArgumentNullException(nameof(descriptors));
JSRuntime = jsRuntime ?? throw new ArgumentNullException(nameof(jsRuntime));
_circuitHandlers = circuitHandlers ?? throw new ArgumentNullException(nameof(circuitHandlers));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
Services = scope.ServiceProvider;
Circuit = new Circuit(this);
Handle = new CircuitHandle() { CircuitHost = this, };
Renderer.UnhandledException += Renderer_UnhandledException;
Renderer.UnhandledSynchronizationException += SynchronizationContext_UnhandledException;
}
public CircuitHandle Handle { get; }
public string CircuitId { get; }
public Circuit Circuit { get; }
public CircuitClientProxy Client { get; set; }
public RemoteJSRuntime JSRuntime { get; }
public RemoteRenderer Renderer { get; }
public IReadOnlyList<ComponentDescriptor> Descriptors { get; }
public IServiceProvider Services { get; }
// InitializeAsync is used in a fire-and-forget context, so it's responsible for its own
// error handling.
public Task InitializeAsync(CancellationToken cancellationToken)
{
Log.InitializationStarted(_logger);
return Renderer.Dispatcher.InvokeAsync(async () =>
{
if (_initialized)
{
throw new InvalidOperationException("The circuit host is already initialized.");
}
try
{
SetCurrentJSRuntime();
_initialized = true; // We're ready to accept incoming JSInterop calls from here on
await OnCircuitOpenedAsync(cancellationToken);
await OnConnectionUpAsync(cancellationToken);
// We add the root components *after* the circuit is flagged as open.
// That's because AddComponentAsync waits for quiescence, which can take
// arbitrarily long. In the meantime we might need to be receiving and
// processing incoming JSInterop calls or similar.
var count = Descriptors.Count;
for (var i = 0; i < count; i++)
{
var (componentType, domElementSelector) = Descriptors[i];
await Renderer.AddComponentAsync(componentType, domElementSelector);
}
Log.InitializationSucceeded(_logger);
}
catch (Exception ex)
{
// Report errors asynchronously. InitializeAsync is designed not to throw.
Log.InitializationFailed(_logger, ex);
UnhandledException?.Invoke(this, new UnhandledExceptionEventArgs(ex, isTerminating: false));
}
});
}
// We handle errors in DisposeAsync because there's no real value in letting it propagate.
// We run user code here (CircuitHandlers) and it's reasonable to expect some might throw, however,
// there isn't anything better to do than log when one of these exceptions happens - because the
// client is already gone.
public async ValueTask DisposeAsync()
{
Log.DisposeStarted(_logger, CircuitId);
await Renderer.Dispatcher.InvokeAsync(async () =>
{
if (_disposed)
{
return;
}
// Make sure that no hub or connection can refer to this circuit anymore now that it's shutting down.
Handle.CircuitHost = null;
_disposed = true;
try
{
await OnConnectionDownAsync(CancellationToken.None);
}
catch
{
// Individual exceptions logged as part of OnConnectionDownAsync - nothing to do here
// since we're already shutting down.
}
try
{
await OnCircuitDownAsync(CancellationToken.None);
}
catch
{
// Individual exceptions logged as part of OnCircuitDownAsync - nothing to do here
// since we're already shutting down.
}
try
{
Renderer.Dispose();
// This cast is needed because it's possible the scope may not support async dispose.
// Our DI container does, but other DI systems may not.
if (_scope is IAsyncDisposable asyncDisposable)
{
await asyncDisposable.DisposeAsync();
}
else
{
_scope.Dispose();
}
Log.DisposeSucceeded(_logger, CircuitId);
}
catch (Exception ex)
{
Log.DisposeFailed(_logger, CircuitId, ex);
}
});
}
// Note: we log exceptions and re-throw while running handlers, because there may be multiple
// exceptions.
private async Task OnCircuitOpenedAsync(CancellationToken cancellationToken)
{
Log.CircuitOpened(_logger, Circuit.Id);
Renderer.Dispatcher.AssertAccess();
List<Exception> exceptions = null;
for (var i = 0; i < _circuitHandlers.Length; i++)
{
var circuitHandler = _circuitHandlers[i];
try
{
await circuitHandler.OnCircuitOpenedAsync(Circuit, cancellationToken);
}
catch (Exception ex)
{
Log.CircuitHandlerFailed(_logger, circuitHandler, nameof(CircuitHandler.OnCircuitOpenedAsync), ex);
exceptions ??= new List<Exception>();
exceptions.Add(ex);
}
}
if (exceptions != null)
{
throw new AggregateException("Encountered exceptions while executing circuit handlers.", exceptions);
}
}
public async Task OnConnectionUpAsync(CancellationToken cancellationToken)
{
Log.ConnectionUp(_logger, Circuit.Id, Client.ConnectionId);
Renderer.Dispatcher.AssertAccess();
List<Exception> exceptions = null;
for (var i = 0; i < _circuitHandlers.Length; i++)
{
var circuitHandler = _circuitHandlers[i];
try
{
await circuitHandler.OnConnectionUpAsync(Circuit, cancellationToken);
}
catch (Exception ex)
{
Log.CircuitHandlerFailed(_logger, circuitHandler, nameof(CircuitHandler.OnConnectionUpAsync), ex);
exceptions ??= new List<Exception>();
exceptions.Add(ex);
}
}
if (exceptions != null)
{
throw new AggregateException("Encountered exceptions while executing circuit handlers.", exceptions);
}
}
public async Task OnConnectionDownAsync(CancellationToken cancellationToken)
{
Log.ConnectionDown(_logger, Circuit.Id, Client.ConnectionId);
Renderer.Dispatcher.AssertAccess();
List<Exception> exceptions = null;
for (var i = 0; i < _circuitHandlers.Length; i++)
{
var circuitHandler = _circuitHandlers[i];
try
{
await circuitHandler.OnConnectionDownAsync(Circuit, cancellationToken);
}
catch (Exception ex)
{
Log.CircuitHandlerFailed(_logger, circuitHandler, nameof(CircuitHandler.OnConnectionDownAsync), ex);
exceptions ??= new List<Exception>();
exceptions.Add(ex);
}
}
if (exceptions != null)
{
throw new AggregateException("Encountered exceptions while executing circuit handlers.", exceptions);
}
}
private async Task OnCircuitDownAsync(CancellationToken cancellationToken)
{
Log.CircuitClosed(_logger, Circuit.Id);
List<Exception> exceptions = null;
for (var i = 0; i < _circuitHandlers.Length; i++)
{
var circuitHandler = _circuitHandlers[i];
try
{
await circuitHandler.OnCircuitClosedAsync(Circuit, cancellationToken);
}
catch (Exception ex)
{
Log.CircuitHandlerFailed(_logger, circuitHandler, nameof(CircuitHandler.OnCircuitClosedAsync), ex);
exceptions ??= new List<Exception>();
exceptions.Add(ex);
}
}
if (exceptions != null)
{
throw new AggregateException("Encountered exceptions while executing circuit handlers.", exceptions);
}
}
// Called by the client when it completes rendering a batch.
// OnRenderCompletedAsync is used in a fire-and-forget context, so it's responsible for its own
// error handling.
public async Task OnRenderCompletedAsync(long renderId, string errorMessageOrNull)
{
AssertInitialized();
AssertNotDisposed();
try
{
_ = Renderer.OnRenderCompletedAsync(renderId, errorMessageOrNull);
}
catch (Exception e)
{
// Captures sync exceptions when invoking OnRenderCompletedAsync.
// An exception might be throw synchronously when we receive an ack for a batch we never produced.
Log.OnRenderCompletedFailed(_logger, renderId, CircuitId, e);
await TryNotifyClientErrorAsync(Client, GetClientErrorMessage(e, $"Failed to complete render batch '{renderId}'."));
UnhandledException(this, new UnhandledExceptionEventArgs(e, isTerminating: false));
}
}
// BeginInvokeDotNetFromJS is used in a fire-and-forget context, so it's responsible for its own
// error handling.
public async Task BeginInvokeDotNetFromJS(string callId, string assemblyName, string methodIdentifier, long dotNetObjectId, string argsJson)
{
AssertInitialized();
AssertNotDisposed();
try
{
await Renderer.Dispatcher.InvokeAsync(() =>
{
SetCurrentJSRuntime();
Log.BeginInvokeDotNet(_logger, callId, assemblyName, methodIdentifier, dotNetObjectId);
DotNetDispatcher.BeginInvoke(callId, assemblyName, methodIdentifier, dotNetObjectId, argsJson);
});
}
catch (Exception ex)
{
// We don't expect any of this code to actually throw, because DotNetDispatcher.BeginInvoke doesn't throw
// however, we still want this to get logged if we do.
Log.BeginInvokeDotNetFailed(_logger, callId, assemblyName, methodIdentifier, dotNetObjectId, ex);
await TryNotifyClientErrorAsync(Client, GetClientErrorMessage(ex, "Interop call failed."));
UnhandledException?.Invoke(this, new UnhandledExceptionEventArgs(ex, isTerminating: false));
}
}
// EndInvokeJSFromDotNet is used in a fire-and-forget context, so it's responsible for its own
// error handling.
public async Task EndInvokeJSFromDotNet(long asyncCall, bool succeded, string arguments)
{
AssertInitialized();
AssertNotDisposed();
try
{
await Renderer.Dispatcher.InvokeAsync(() =>
{
SetCurrentJSRuntime();
if (!succeded)
{
// We can log the arguments here because it is simply the JS error with the call stack.
Log.EndInvokeJSFailed(_logger, asyncCall, arguments);
}
else
{
Log.EndInvokeJSSucceeded(_logger, asyncCall);
}
DotNetDispatcher.EndInvoke(arguments);
});
}
catch (Exception ex)
{
// An error completing JS interop means that the user sent invalid data, a well-behaved
// client won't do this.
Log.EndInvokeDispatchException(_logger, ex);
await TryNotifyClientErrorAsync(Client, GetClientErrorMessage(ex, "Invalid interop arguments."));
UnhandledException?.Invoke(this, new UnhandledExceptionEventArgs(ex, isTerminating: false));
}
}
// DispatchEvent is used in a fire-and-forget context, so it's responsible for its own
// error handling.
public async Task DispatchEvent(string eventDescriptorJson, string eventArgsJson)
{
AssertInitialized();
AssertNotDisposed();
WebEventData webEventData;
try
{
webEventData = WebEventData.Parse(eventDescriptorJson, eventArgsJson);
}
catch (Exception ex)
{
// Invalid event data is fatal. We expect a well-behaved client to send valid JSON.
Log.DispatchEventFailedToParseEventData(_logger, ex);
await TryNotifyClientErrorAsync(Client, GetClientErrorMessage(ex, "Bad input data."));
UnhandledException?.Invoke(this, new UnhandledExceptionEventArgs(ex, isTerminating: false));
return;
}
try
{
await Renderer.Dispatcher.InvokeAsync(() =>
{
SetCurrentJSRuntime();
return Renderer.DispatchEventAsync(
webEventData.EventHandlerId,
webEventData.EventFieldInfo,
webEventData.EventArgs);
});
}
catch (Exception ex)
{
// A failure in dispatching an event means that it was an attempt to use an invalid event id.
// A well-behaved client won't do this.
Log.DispatchEventFailedToDispatchEvent(_logger, webEventData.EventHandlerId.ToString(), ex);
await TryNotifyClientErrorAsync(Client, GetClientErrorMessage(ex, "Failed to dispatch event."));
UnhandledException?.Invoke(this, new UnhandledExceptionEventArgs(ex, isTerminating: false));
}
}
// OnLocationChangedAsync is used in a fire-and-forget context, so it's responsible for its own
// error handling.
public async Task OnLocationChangedAsync(string uri, bool intercepted)
{
AssertInitialized();
AssertNotDisposed();
try
{
await Renderer.Dispatcher.InvokeAsync(() =>
{
SetCurrentJSRuntime();
Log.LocationChange(_logger, uri, CircuitId);
var navigationManager = (RemoteNavigationManager)Services.GetRequiredService<NavigationManager>();
navigationManager.NotifyLocationChanged(uri, intercepted);
Log.LocationChangeSucceeded(_logger, uri, CircuitId);
});
}
// It's up to the NavigationManager implementation to validate the URI.
//
// Note that it's also possible that setting the URI could cause a failure in code that listens
// to NavigationManager.LocationChanged.
//
// In either case, a well-behaved client will not send invalid URIs, and we don't really
// want to continue processing with the circuit if setting the URI failed inside application
// code. The safest thing to do is consider it a critical failure since URI is global state,
// and a failure means that an update to global state was partially applied.
catch (LocationChangeException nex)
{
// LocationChangeException means that it failed in user-code. Treat this like an unhandled
// exception in user-code.
Log.LocationChangeFailedInCircuit(_logger, uri, CircuitId, nex);
await TryNotifyClientErrorAsync(Client, GetClientErrorMessage(nex, "Location change failed."));
UnhandledException?.Invoke(this, new UnhandledExceptionEventArgs(nex, isTerminating: false));
}
catch (Exception ex)
{
// Any other exception means that it failed validation, or inside the NavigationManager. Treat
// this like bad data.
Log.LocationChangeFailed(_logger, uri, CircuitId, ex);
await TryNotifyClientErrorAsync(Client, GetClientErrorMessage(ex, $"Location change to '{uri}' failed."));
UnhandledException?.Invoke(this, new UnhandledExceptionEventArgs(ex, isTerminating: false));
}
}
public void SetCircuitUser(ClaimsPrincipal user)
{
// This can be called before the circuit is initialized.
AssertNotDisposed();
var authenticationStateProvider = Services.GetService<AuthenticationStateProvider>() as IHostEnvironmentAuthenticationStateProvider;
if (authenticationStateProvider != null)
{
var authenticationState = new AuthenticationState(user);
authenticationStateProvider.SetAuthenticationState(Task.FromResult(authenticationState));
}
}
public void SendPendingBatches()
{
AssertInitialized();
AssertNotDisposed();
// Dispatch any buffered renders we accumulated during a disconnect.
// Note that while the rendering is async, we cannot await it here. The Task returned by ProcessBufferedRenderBatches relies on
// OnRenderCompletedAsync to be invoked to complete, and SignalR does not allow concurrent hub method invocations.
_ = Renderer.Dispatcher.InvokeAsync(() => Renderer.ProcessBufferedRenderBatches());
}
private void AssertInitialized()
{
if (!_initialized)
{
throw new InvalidOperationException("Circuit is being invoked prior to initialization.");
}
}
private void AssertNotDisposed()
{
if (_disposed)
{
throw new ObjectDisposedException(objectName: null);
}
}
// An unhandled exception from the renderer is always fatal because it came from user code.
// We want to notify the client if it's still connected, and then tear-down the circuit.
private async void Renderer_UnhandledException(object sender, Exception e)
{
await ReportUnhandledException(e);
UnhandledException?.Invoke(this, new UnhandledExceptionEventArgs(e, isTerminating: false));
}
// An unhandled exception from the renderer is always fatal because it came from user code.
// We want to notify the client if it's still connected, and then tear-down the circuit.
private async void SynchronizationContext_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
await ReportUnhandledException((Exception)e.ExceptionObject);
UnhandledException?.Invoke(this, e);
}
private async Task ReportUnhandledException(Exception exception)
{
Log.CircuitUnhandledException(_logger, CircuitId, exception);
await TryNotifyClientErrorAsync(Client, GetClientErrorMessage(exception), exception);
}
private string GetClientErrorMessage(Exception exception, string additionalInformation = null)
{
if (_options.DetailedErrors)
{
return exception.ToString();
}
else
{
return
$"There was an unhandled exception on the current circuit, so this circuit will be terminated. For more details turn on " +
$"detailed exceptions in '{typeof(CircuitOptions).Name}.{nameof(CircuitOptions.DetailedErrors)}'. {additionalInformation}";
}
}
// exception is only populated when either the renderer or the synchronization context signal exceptions.
// In other cases it is null and should never be sent to the client.
// error contains the information to send to the client.
private async Task TryNotifyClientErrorAsync(IClientProxy client, string error, Exception exception = null)
{
if (!Client.Connected)
{
Log.UnhandledExceptionClientDisconnected(
_logger,
CircuitId,
exception);
return;
}
try
{
Log.CircuitTransmittingClientError(_logger, CircuitId);
await client.SendAsync("JS.Error", error);
Log.CircuitTransmittedClientErrorSuccess(_logger, CircuitId);
}
catch (Exception ex)
{
Log.CircuitTransmitErrorFailed(_logger, CircuitId, ex);
}
}
private static class Log
{
private static readonly Action<ILogger, Exception> _intializationStarted;
private static readonly Action<ILogger, Exception> _intializationSucceded;
private static readonly Action<ILogger, Exception> _intializationFailed;
private static readonly Action<ILogger, string, Exception> _disposeStarted;
private static readonly Action<ILogger, string, Exception> _disposeSucceded;
private static readonly Action<ILogger, string, Exception> _disposeFailed;
private static readonly Action<ILogger, string, Exception> _onCircuitOpened;
private static readonly Action<ILogger, string, string, Exception> _onConnectionUp;
private static readonly Action<ILogger, string, string, Exception> _onConnectionDown;
private static readonly Action<ILogger, string, Exception> _onCircuitClosed;
private static readonly Action<ILogger, Type, string, string, Exception> _circuitHandlerFailed;
private static readonly Action<ILogger, string, Exception> _circuitUnhandledException;
private static readonly Action<ILogger, string, Exception> _circuitTransmittingClientError;
private static readonly Action<ILogger, string, Exception> _circuitTransmittedClientErrorSuccess;
private static readonly Action<ILogger, string, Exception> _circuitTransmitErrorFailed;
private static readonly Action<ILogger, string, Exception> _unhandledExceptionClientDisconnected;
private static readonly Action<ILogger, string, string, string, Exception> _beginInvokeDotNetStatic;
private static readonly Action<ILogger, string, long, string, Exception> _beginInvokeDotNetInstance;
private static readonly Action<ILogger, string, string, string, Exception> _beginInvokeDotNetStaticFailed;
private static readonly Action<ILogger, string, long, string, Exception> _beginInvokeDotNetInstanceFailed;
private static readonly Action<ILogger, Exception> _endInvokeDispatchException;
private static readonly Action<ILogger, long, string, Exception> _endInvokeJSFailed;
private static readonly Action<ILogger, long, Exception> _endInvokeJSSucceeded;
private static readonly Action<ILogger, Exception> _dispatchEventFailedToParseEventData;
private static readonly Action<ILogger, string, Exception> _dispatchEventFailedToDispatchEvent;
private static readonly Action<ILogger, string, string, Exception> _locationChange;
private static readonly Action<ILogger, string, string, Exception> _locationChangeSucceeded;
private static readonly Action<ILogger, string, string, Exception> _locationChangeFailed;
private static readonly Action<ILogger, string, string, Exception> _locationChangeFailedInCircuit;
private static readonly Action<ILogger, long, string, Exception> _onRenderCompletedFailed;
private static class EventIds
{
// 100s used for lifecycle stuff
public static readonly EventId InitializationStarted = new EventId(100, "InitializationStarted");
public static readonly EventId InitializationSucceeded = new EventId(101, "InitializationSucceeded");
public static readonly EventId InitializationFailed = new EventId(102, "InitializationFailed");
public static readonly EventId DisposeStarted = new EventId(103, "DisposeStarted");
public static readonly EventId DisposeSucceeded = new EventId(104, "DisposeSucceeded");
public static readonly EventId DisposeFailed = new EventId(105, "DisposeFailed");
public static readonly EventId OnCircuitOpened = new EventId(106, "OnCircuitOpened");
public static readonly EventId OnConnectionUp = new EventId(107, "OnConnectionUp");
public static readonly EventId OnConnectionDown = new EventId(108, "OnConnectionDown");
public static readonly EventId OnCircuitClosed = new EventId(109, "OnCircuitClosed");
public static readonly EventId CircuitHandlerFailed = new EventId(110, "CircuitHandlerFailed");
public static readonly EventId CircuitUnhandledException = new EventId(111, "CircuitUnhandledException");
public static readonly EventId CircuitTransmittingClientError = new EventId(112, "CircuitTransmittingClientError");
public static readonly EventId CircuitTransmittedClientErrorSuccess = new EventId(113, "CircuitTransmittedClientErrorSuccess");
public static readonly EventId CircuitTransmitErrorFailed = new EventId(114, "CircuitTransmitErrorFailed");
public static readonly EventId UnhandledExceptionClientDisconnected = new EventId(115, "UnhandledExceptionClientDisconnected");
// 200s used for interactive stuff
public static readonly EventId DispatchEventFailedToParseEventData = new EventId(200, "DispatchEventFailedToParseEventData");
public static readonly EventId DispatchEventFailedToDispatchEvent = new EventId(201, "DispatchEventFailedToDispatchEvent");
public static readonly EventId BeginInvokeDotNet = new EventId(202, "BeginInvokeDotNet");
public static readonly EventId BeginInvokeDotNetFailed = new EventId(203, "BeginInvokeDotNetFailed");
public static readonly EventId EndInvokeDispatchException = new EventId(204, "EndInvokeDispatchException");
public static readonly EventId EndInvokeJSFailed = new EventId(205, "EndInvokeJSFailed");
public static readonly EventId EndInvokeJSSucceeded = new EventId(206, "EndInvokeJSSucceeded");
public static readonly EventId DispatchEventThroughJSInterop = new EventId(207, "DispatchEventThroughJSInterop");
public static readonly EventId LocationChange = new EventId(208, "LocationChange");
public static readonly EventId LocationChangeSucceded = new EventId(209, "LocationChangeSucceeded");
public static readonly EventId LocationChangeFailed = new EventId(210, "LocationChangeFailed");
public static readonly EventId LocationChangeFailedInCircuit = new EventId(211, "LocationChangeFailedInCircuit");
public static readonly EventId OnRenderCompletedFailed = new EventId(212, " OnRenderCompletedFailed");
}
static Log()
{
_intializationStarted = LoggerMessage.Define(
LogLevel.Debug,
EventIds.InitializationFailed,
"Circuit initialization started.");
_intializationSucceded = LoggerMessage.Define(
LogLevel.Debug,
EventIds.InitializationFailed,
"Circuit initialization succeeded.");
_intializationFailed = LoggerMessage.Define(
LogLevel.Debug,
EventIds.InitializationFailed,
"Circuit initialization failed.");
_disposeStarted = LoggerMessage.Define<string>(
LogLevel.Debug,
EventIds.DisposeStarted,
"Disposing circuit '{CircuitId}' started.");
_disposeSucceded = LoggerMessage.Define<string>(
LogLevel.Debug,
EventIds.DisposeSucceeded,
"Disposing circuit '{CircuitId}' succeded.");
_disposeFailed = LoggerMessage.Define<string>(
LogLevel.Debug,
EventIds.DisposeFailed,
"Disposing circuit '{CircuitId}' failed.");
_onCircuitOpened = LoggerMessage.Define<string>(
LogLevel.Debug,
EventIds.OnCircuitOpened,
"Opening circuit with id '{CircuitId}'.");
_onConnectionUp = LoggerMessage.Define<string, string>(
LogLevel.Debug,
EventIds.OnConnectionUp,
"Circuit id '{CircuitId}' connected using connection '{ConnectionId}'.");
_onConnectionDown = LoggerMessage.Define<string, string>(
LogLevel.Debug,
EventIds.OnConnectionDown,
"Circuit id '{CircuitId}' disconnected from connection '{ConnectionId}'.");
_onCircuitClosed = LoggerMessage.Define<string>(
LogLevel.Debug,
EventIds.OnCircuitClosed,
"Closing circuit with id '{CircuitId}'.");
_circuitHandlerFailed = LoggerMessage.Define<Type, string, string>(
LogLevel.Error,
EventIds.CircuitHandlerFailed,
"Unhandled error invoking circuit handler type {handlerType}.{handlerMethod}: {Message}");
_circuitUnhandledException = LoggerMessage.Define<string>(
LogLevel.Error,
EventIds.CircuitUnhandledException,
"Unhandled exception in circuit '{CircuitId}'.");
_circuitTransmittingClientError = LoggerMessage.Define<string>(
LogLevel.Debug,
EventIds.CircuitTransmittingClientError,
"About to notify client of an error in circuit '{CircuitId}'.");
_circuitTransmittedClientErrorSuccess = LoggerMessage.Define<string>(
LogLevel.Debug,
EventIds.CircuitTransmittedClientErrorSuccess,
"Successfully transmitted error to client in circuit '{CircuitId}'.");
_circuitTransmitErrorFailed = LoggerMessage.Define<string>(
LogLevel.Debug,
EventIds.CircuitTransmitErrorFailed,
"Failed to transmit exception to client in circuit '{CircuitId}'.");
_unhandledExceptionClientDisconnected = LoggerMessage.Define<string>(
LogLevel.Debug,
EventIds.UnhandledExceptionClientDisconnected,
"An exception ocurred on the circuit host '{CircuitId}' while the client is disconnected.");
_beginInvokeDotNetStatic = LoggerMessage.Define<string, string, string>(
LogLevel.Debug,
EventIds.BeginInvokeDotNet,
"Invoking static method with identifier '{MethodIdentifier}' on assembly '{Assembly}' with callback id '{CallId}'.");
_beginInvokeDotNetInstance = LoggerMessage.Define<string, long, string>(
LogLevel.Debug,
EventIds.BeginInvokeDotNet,
"Invoking instance method '{MethodIdentifier}' on instance '{DotNetObjectId}' with callback id '{CallId}'.");
_beginInvokeDotNetStaticFailed = LoggerMessage.Define<string, string, string>(
LogLevel.Debug,
EventIds.BeginInvokeDotNetFailed,
"Failed to invoke static method with identifier '{MethodIdentifier}' on assembly '{Assembly}' with callback id '{CallId}'.");
_beginInvokeDotNetInstanceFailed = LoggerMessage.Define<string, long, string>(
LogLevel.Debug,
EventIds.BeginInvokeDotNetFailed,
"Failed to invoke instance method '{MethodIdentifier}' on instance '{DotNetObjectId}' with callback id '{CallId}'.");
_endInvokeDispatchException = LoggerMessage.Define(
LogLevel.Debug,
EventIds.EndInvokeDispatchException,
"There was an error invoking 'Microsoft.JSInterop.DotNetDispatcher.EndInvoke'.");
_endInvokeJSFailed = LoggerMessage.Define<long, string>(
LogLevel.Debug,
EventIds.EndInvokeJSFailed,
"The JS interop call with callback id '{AsyncCall}' failed with error '{Error}'.");
_endInvokeJSSucceeded = LoggerMessage.Define<long>(
LogLevel.Debug,
EventIds.EndInvokeJSSucceeded,
"The JS interop call with callback id '{AsyncCall}' succeeded.");
_dispatchEventFailedToParseEventData = LoggerMessage.Define(
LogLevel.Debug,
EventIds.DispatchEventFailedToParseEventData,
"Failed to parse the event data when trying to dispatch an event.");
_dispatchEventFailedToDispatchEvent = LoggerMessage.Define<string>(
LogLevel.Debug,
EventIds.DispatchEventFailedToDispatchEvent,
"There was an error dispatching the event '{EventHandlerId}' to the application.");
_locationChange = LoggerMessage.Define<string, string>(
LogLevel.Debug,
EventIds.LocationChange,
"Location changing to {URI} in circuit '{CircuitId}'.");
_locationChangeSucceeded = LoggerMessage.Define<string, string>(
LogLevel.Debug,
EventIds.LocationChangeSucceded,
"Location change to '{URI}' in circuit '{CircuitId}' succeded.");
_locationChangeFailed = LoggerMessage.Define<string, string>(
LogLevel.Debug,
EventIds.LocationChangeFailed,
"Location change to '{URI}' in circuit '{CircuitId}' failed.");
_locationChangeFailedInCircuit = LoggerMessage.Define<string, string>(
LogLevel.Error,
EventIds.LocationChangeFailed,
"Location change to '{URI}' in circuit '{CircuitId}' failed.");
_onRenderCompletedFailed = LoggerMessage.Define<long, string>(
LogLevel.Debug,
EventIds.OnRenderCompletedFailed,
"Failed to complete render batch '{RenderId}' in circuit host '{CircuitId}'.");
}
public static void InitializationStarted(ILogger logger) => _intializationStarted(logger, null);
public static void InitializationSucceeded(ILogger logger) => _intializationSucceded(logger, null);
public static void InitializationFailed(ILogger logger, Exception exception) => _intializationFailed(logger, exception);
public static void DisposeStarted(ILogger logger, string circuitId) => _disposeStarted(logger, circuitId, null);
public static void DisposeSucceeded(ILogger logger, string circuitId) => _disposeSucceded(logger, circuitId, null);
public static void DisposeFailed(ILogger logger, string circuitId, Exception exception) => _disposeFailed(logger, circuitId, exception);
public static void CircuitOpened(ILogger logger, string circuitId) => _onCircuitOpened(logger, circuitId, null);
public static void ConnectionUp(ILogger logger, string circuitId, string connectionId) => _onConnectionUp(logger, circuitId, connectionId, null);
public static void ConnectionDown(ILogger logger, string circuitId, string connectionId) => _onConnectionDown(logger, circuitId, connectionId, null);
public static void CircuitClosed(ILogger logger, string circuitId) => _onCircuitClosed(logger, circuitId, null);
public static void CircuitHandlerFailed(ILogger logger, CircuitHandler handler, string handlerMethod, Exception exception)
{
_circuitHandlerFailed(
logger,
handler.GetType(),
handlerMethod,
exception.Message,
exception);
}
public static void CircuitUnhandledException(ILogger logger, string circuitId, Exception exception) => _circuitUnhandledException(logger, circuitId, exception);
public static void CircuitTransmitErrorFailed(ILogger logger, string circuitId, Exception exception) => _circuitTransmitErrorFailed(logger, circuitId, exception);
public static void EndInvokeDispatchException(ILogger logger, Exception ex) => _endInvokeDispatchException(logger, ex);
public static void EndInvokeJSFailed(ILogger logger, long asyncHandle, string arguments) => _endInvokeJSFailed(logger, asyncHandle, arguments, null);
public static void EndInvokeJSSucceeded(ILogger logger, long asyncCall) => _endInvokeJSSucceeded(logger, asyncCall, null);
public static void DispatchEventFailedToParseEventData(ILogger logger, Exception ex) => _dispatchEventFailedToParseEventData(logger, ex);
public static void DispatchEventFailedToDispatchEvent(ILogger logger, string eventHandlerId, Exception ex) => _dispatchEventFailedToDispatchEvent(logger, eventHandlerId ?? "", ex);
public static void BeginInvokeDotNet(ILogger logger, string callId, string assemblyName, string methodIdentifier, long dotNetObjectId)
{
if (assemblyName != null)
{
_beginInvokeDotNetStatic(logger, methodIdentifier, assemblyName, callId, null);
}
else
{
_beginInvokeDotNetInstance(logger, methodIdentifier, dotNetObjectId, callId, null);
}
}
public static void BeginInvokeDotNetFailed(ILogger logger, string callId, string assemblyName, string methodIdentifier, long dotNetObjectId, Exception exception)
{
if (assemblyName != null)
{
_beginInvokeDotNetStaticFailed(logger, methodIdentifier, assemblyName, callId, null);
}
else
{
_beginInvokeDotNetInstanceFailed(logger, methodIdentifier, dotNetObjectId, callId, null);
}
}
public static void LocationChange(ILogger logger, string uri, string circuitId) => _locationChange(logger, uri, circuitId, null);
public static void LocationChangeSucceeded(ILogger logger, string uri, string circuitId) => _locationChangeSucceeded(logger, uri, circuitId, null);
public static void LocationChangeFailed(ILogger logger, string uri, string circuitId, Exception exception) => _locationChangeFailed(logger, uri, circuitId, exception);
public static void LocationChangeFailedInCircuit(ILogger logger, string uri, string circuitId, Exception exception) => _locationChangeFailedInCircuit(logger, uri, circuitId, exception);
public static void UnhandledExceptionClientDisconnected(ILogger logger, string circuitId, Exception exception) => _unhandledExceptionClientDisconnected(logger, circuitId, exception);
public static void CircuitTransmittingClientError(ILogger logger, string circuitId) => _circuitTransmittingClientError(logger, circuitId, null);
public static void CircuitTransmittedClientErrorSuccess(ILogger logger, string circuitId) => _circuitTransmittedClientErrorSuccess(logger, circuitId, null);
public static void OnRenderCompletedFailed(ILogger logger, long renderId, string circuitId, Exception e) => _onRenderCompletedFailed(logger, renderId, circuitId, e);
}
}
}