"Cannot access a disposed object" SignalR 崩溃
"Cannot access a disposed object" crash in SignalR
我有一个带有计时器的测试中心,可以将日期发送给所有客户端。
客户端连接后崩溃并出现以下错误:无法访问已释放的对象。
这是错误:
System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'MyHub'.
at Microsoft.AspNetCore.SignalR.Hub.CheckDisposed()
at Microsoft.AspNetCore.SignalR.Hub.get_Clients()
这是中心代码:
public class MyHub : Hub
{
public MyHub()
{
Program.T = new Timer(TickTimer, null, 1000, 1000);
}
private void TickTimer(object State)
{
try
{
var Time = DateTime.UtcNow.ToString(CultureInfo.InvariantCulture);
Console.WriteLine(Time);
Clients.All.SendCoreAsync("update", new object[] { Time });
}
catch (Exception E)
{
Console.WriteLine(E);
throw;
}
}
}
看起来 Clients 对象已被处理掉,但我不明白为什么。
编辑,这里有更多信息:
集线器可以来自不同的程序集,因此它们在 asp 启动的配置部分动态注册。
每个集线器都装饰有一个属性以识别它并提供路径:
[AttributeUsage(AttributeTargets.Class)]
public class SignalRHub : Attribute
{
public readonly string Route;
public SignalRHubPath(string Route)
{
this.Route = Route;
}
}
然后以这种方式找到并注册:
private static void RegisterHubs(IApplicationBuilder Application)
{
// find all SignalR hubs
var HubsList = ReflectionHelper.FindType<SignalRHubPath>();
Logging.Info($"Found {HubsList.Count} hubs");
// get a link to the mapper method of the hubroutebuilder.
var MapperMethodInfo = typeof(HubRouteBuilder).GetMethod("MapHub", new[] { typeof(PathString) }, null);
// register them
foreach (var H in HubsList)
{
// get the route attribute
var Route = string.Empty;
var Attributes = Attribute.GetCustomAttributes(H);
foreach (var Attribute in Attributes)
{
if (Attribute is SignalRHubPath A) { Route = A.Route; break; }
}
// register the hub
if (string.IsNullOrEmpty(Route))
{
Logging.Warn($"[Hub] {H.Name} does not have a path, skipping");
}
else
{
Logging.Info($"[Hub] Registering {H.Name} with path {Route}");
// Application.UseSignalR(_ => _.MapHub<Hub>("/" + Route));
// use the mapper method call instead so we can pass the hub type
var Path = new PathString("/" + Route);
Application.UseSignalR(R => MapperMethodInfo.MakeGenericMethod(H).Invoke(R, new object [] { Path }));
}
}
}
集线器生命周期是每个请求的(请参阅 https://docs.microsoft.com/en-us/aspnet/core/signalr/hubs?view=aspnetcore-3.1 处的注释),因此您会遇到处置异常,因为您正在访问已处置对象的 属性(客户端)。
当您想向集线器外部的客户端发送消息时(并且您在外部,因为对计时器做出反应,因此在 .netcore 集线器生命周期之后),您应该使用 IHubContext(您可以通过 DI 获得), 看看 https://docs.microsoft.com/en-us/aspnet/core/signalr/hubcontext?view=aspnetcore-3.1
集线器是暂时的:
不要将状态存储在集线器 class 上的 属性 中。每个集线器方法调用都在新的集线器实例上执行。
在调用依赖于集线器保持活动状态的异步方法时使用等待。例如,如果在没有等待的情况下调用 Clients.All.SendAsync(...) 之类的方法,并且集线器方法在 SendAsync 完成之前完成。enter link description here
我有一个带有计时器的测试中心,可以将日期发送给所有客户端。
客户端连接后崩溃并出现以下错误:无法访问已释放的对象。
这是错误:
System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'MyHub'.
at Microsoft.AspNetCore.SignalR.Hub.CheckDisposed()
at Microsoft.AspNetCore.SignalR.Hub.get_Clients()
这是中心代码:
public class MyHub : Hub
{
public MyHub()
{
Program.T = new Timer(TickTimer, null, 1000, 1000);
}
private void TickTimer(object State)
{
try
{
var Time = DateTime.UtcNow.ToString(CultureInfo.InvariantCulture);
Console.WriteLine(Time);
Clients.All.SendCoreAsync("update", new object[] { Time });
}
catch (Exception E)
{
Console.WriteLine(E);
throw;
}
}
}
看起来 Clients 对象已被处理掉,但我不明白为什么。
编辑,这里有更多信息:
集线器可以来自不同的程序集,因此它们在 asp 启动的配置部分动态注册。
每个集线器都装饰有一个属性以识别它并提供路径:
[AttributeUsage(AttributeTargets.Class)]
public class SignalRHub : Attribute
{
public readonly string Route;
public SignalRHubPath(string Route)
{
this.Route = Route;
}
}
然后以这种方式找到并注册:
private static void RegisterHubs(IApplicationBuilder Application)
{
// find all SignalR hubs
var HubsList = ReflectionHelper.FindType<SignalRHubPath>();
Logging.Info($"Found {HubsList.Count} hubs");
// get a link to the mapper method of the hubroutebuilder.
var MapperMethodInfo = typeof(HubRouteBuilder).GetMethod("MapHub", new[] { typeof(PathString) }, null);
// register them
foreach (var H in HubsList)
{
// get the route attribute
var Route = string.Empty;
var Attributes = Attribute.GetCustomAttributes(H);
foreach (var Attribute in Attributes)
{
if (Attribute is SignalRHubPath A) { Route = A.Route; break; }
}
// register the hub
if (string.IsNullOrEmpty(Route))
{
Logging.Warn($"[Hub] {H.Name} does not have a path, skipping");
}
else
{
Logging.Info($"[Hub] Registering {H.Name} with path {Route}");
// Application.UseSignalR(_ => _.MapHub<Hub>("/" + Route));
// use the mapper method call instead so we can pass the hub type
var Path = new PathString("/" + Route);
Application.UseSignalR(R => MapperMethodInfo.MakeGenericMethod(H).Invoke(R, new object [] { Path }));
}
}
}
集线器生命周期是每个请求的(请参阅 https://docs.microsoft.com/en-us/aspnet/core/signalr/hubs?view=aspnetcore-3.1 处的注释),因此您会遇到处置异常,因为您正在访问已处置对象的 属性(客户端)。
当您想向集线器外部的客户端发送消息时(并且您在外部,因为对计时器做出反应,因此在 .netcore 集线器生命周期之后),您应该使用 IHubContext(您可以通过 DI 获得), 看看 https://docs.microsoft.com/en-us/aspnet/core/signalr/hubcontext?view=aspnetcore-3.1
集线器是暂时的:
不要将状态存储在集线器 class 上的 属性 中。每个集线器方法调用都在新的集线器实例上执行。 在调用依赖于集线器保持活动状态的异步方法时使用等待。例如,如果在没有等待的情况下调用 Clients.All.SendAsync(...) 之类的方法,并且集线器方法在 SendAsync 完成之前完成。enter link description here