-
Hi, When using Safari with ASP.NET Core 3.1 Core Blazor Server the What is the process for disposing the signalR .NET client connection when using Safari with ASP.NET Core 3.1 Core and Blazor Server? Current Source Code using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.SignalR.Client;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using WebApp.Data;
using WebApp.Data.Serializers.Converters;
using WebApp.Data.Serializers.Converters.Visitors;
using WebApp.Repository.Contracts;
namespace WebApp.Pages
{
public partial class Index : IAsyncDisposable, IDisposable
{
private HubConnection hubConnection;
public bool IsConnected => hubConnection.State == HubConnectionState.Connected;
private bool disposed = false;
[Inject]
public NavigationManager NavigationManager { get; set; }
[Inject]
public IMotionDetectionRepository Repository { get; set; }
[Inject]
public ILogger<MotionDetectionConverter> LoggerMotionDetection { get; set; }
[Inject]
public ILogger<MotionInfoConverter> LoggerMotionInfo { get; set; }
[Inject]
public ILogger<JsonVisitor> LoggerJsonVisitor { get; set; }
[Inject]
public ILogger<Index> Logger { get; set; }
#region Dispose
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Clear secondary signalR Closed event handler and stop the
/// secondary signalR connection
/// </summary>
/// <remarks>
/// ASP.NET Core Release Candidate 5 calls DisposeAsync when
/// navigating away from a Blazor Server page. Until the
/// release is stable DisposeAsync will have to be triggered from
/// Dispose. Sadly, this means having to use GetAwaiter().GetResult()
/// in Dispose().
/// However, providing DisposeAsync() now makes the migration easier
/// https://github.com/dotnet/aspnetcore/issues/26737
/// https://github.com/dotnet/aspnetcore/issues/9960
/// https://github.com/dotnet/aspnetcore/milestone/57?closed=1
/// </remarks>
protected virtual void Dispose(bool disposing)
{
if (disposed)
return;
if (disposing)
{
Logger.LogInformation("Index.razor page is disposing...");
try
{
if (hubConnection != null)
{
Logger.LogInformation("Removing signalR client event handlers...");
hubConnection.Closed -= CloseHandler;
}
// Until ASP.NET Core 5 is released in November
// trigger DisposeAsync(). See docstring and DiposeAsync() below.
// not ideal, but having to use GetAwaiter().GetResult() until
// forthcoming release of ASP.NET Core 5 for the introduction
// of triggering DisposeAsync on pages that implement IAsyncDisposable
DisposeAsync().GetAwaiter().GetResult();
}
catch (Exception exception)
{
Logger.LogError($"Exception encountered while disposing Index.razor page :: {exception.Message}");
}
}
disposed = true;
}
/// <summary>
/// Dispose the secondary backend signalR connection
/// </summary>
/// <remarks>
/// ASP.NET Core Release Candidate 5 adds DisposeAsync when
/// navigating away from a Blazor Server page. Until the
/// release is stable DisposeAsync will have to be triggered from
/// Dispose. Sadly, this means having to use GetAwaiter().GetResult()
/// in Dispose().
/// However, providing DisposeAsync() now makes the migration easier
/// https://github.com/dotnet/aspnetcore/issues/26737
/// https://github.com/dotnet/aspnetcore/issues/9960
/// https://github.com/dotnet/aspnetcore/milestone/57?closed=1
/// </remarks>
public async virtual ValueTask DisposeAsync()
{
try
{
if (hubConnection != null)
{
Logger.LogInformation("Closing secondary signalR connection...");
await hubConnection.StopAsync();
Logger.LogInformation("Closed secondary signalR connection");
}
// Dispose(); When migrated to ASP.NET Core 5 let DisposeAsync trigger Dispose
}
catch (Exception exception)
{
Logger.LogInformation($"Exception encountered wwhile stopping secondary signalR connection :: {exception.Message}");
}
}
#endregion
#region ComponentBase
/// <summary>
/// Connect to the secondary signalR hub after rendering.
/// Perform on the first render.
/// </summary>
/// <remarks>
/// This could have been performed in OnInitializedAsync but
/// that method gets executed twice when server prerendering is used.
/// </remarks>
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
var hubUrl = NavigationManager.BaseUri.TrimEnd('/') + "/motionhub";
try
{
Logger.LogInformation("Index.razor page is performing initial render, connecting to secondary signalR hub");
hubConnection = new HubConnectionBuilder()
.WithUrl(hubUrl)
.ConfigureLogging(logging =>
{
logging.AddConsole();
logging.AddFilter("Microsoft.AspNetCore.SignalR", LogLevel.Information);
})
.AddJsonProtocol(options =>
{
options.PayloadSerializerOptions = JsonConvertersFactory.CreateDefaultJsonConverters(LoggerMotionDetection, LoggerMotionInfo, LoggerJsonVisitor);
})
.Build();
hubConnection.On<MotionDetection>("ReceiveMotionDetection", ReceiveMessage);
hubConnection.Closed += CloseHandler;
Logger.LogInformation("Starting HubConnection");
await hubConnection.StartAsync();
Logger.LogInformation("Index Razor Page initialised, listening on signalR hub url => " + hubUrl.ToString());
}
catch (Exception e)
{
Logger.LogError(e, "Encountered exception => " + e);
}
}
}
protected override async Task OnInitializedAsync()
{
await Task.CompletedTask;
}
#endregion
#region signalR
/// <summary>Log signalR connection closing</summary>
/// <param name="exception">
/// If an exception occurred while closing then this argument describes the exception
/// If the signaR connection was closed intentionally by client or server, then this
/// argument is null
/// </param>
private Task CloseHandler(Exception exception)
{
if (exception == null)
{
Logger.LogInformation("signalR client connection closed");
}
else
{
Logger.LogInformation($"signalR client closed due to error => {exception.Message}");
}
return Task.CompletedTask;
}
/// <summary>
/// Add motion detection notification to repository
/// </summary>
/// <param name="message">Motion detection received via signalR</param>
private void ReceiveMessage(MotionDetection message)
{
try
{
Logger.LogInformation("Motion detection message received");
Repository.AddItem(message);
StateHasChanged();
}
catch (Exception ex)
{
Logger.LogError(ex, "An exception was encountered => " + ex.ToString());
}
}
#endregion
}
} signalR Server Hub using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.Logging;
namespace WebApp.Realtime.SignalR
{
/// <summary>
/// This represents endpoints available on the server, available for the
/// clients to call
/// </summary>
public class MotionHub : Hub<IMotion>
{
private bool _disposed = false;
public ILogger<MotionHub> Logger { get; set; }
public MotionHub(ILogger<MotionHub> logger) : base()
{
Logger = logger;
}
public override async Task OnConnectedAsync()
{
Logger.LogInformation($"OnConnectedAsync => Connection ID={Context.ConnectionId} : User={Context.User.Identity.Name}");
await base.OnConnectedAsync();
}
public override async Task OnDisconnectedAsync(Exception exception)
{
if (exception != null)
{
Logger.LogInformation($"OnDisconnectedAsync => Connection ID={Context.ConnectionId} : User={Context.User.Identity.Name} : Exception={exception.Message}");
}
else
{
Logger.LogInformation($"OnDisconnectedAsync => Connection ID={Context.ConnectionId} : User={Context.User.Identity.Name}");
}
await base.OnDisconnectedAsync(exception);
}
// Protected implementation of Dispose pattern.
protected override void Dispose(bool disposing)
{
if (_disposed)
{
return;
}
_disposed = true;
// Call base class implementation.
base.Dispose(disposing);
}
}
} |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment
-
Solved by updating Safari to Version 14.0 (15610.1.28.9, 15610) via macOS Catalina v10.15.7 |
Beta Was this translation helpful? Give feedback.
Solved by updating Safari to Version 14.0 (15610.1.28.9, 15610) via macOS Catalina v10.15.7