我正在使用Microsoft.AspNetCore.SignalR 2.1 v1.0.4,并且使用v1.0.4的打字稿客户端正在使用ChannelReader流。
通道显示特定于单个实体的事件数据,因此,当客户端的用户导航到该单个实体的页面呈现数据时,预计客户端将订阅该通道。如果用户导航到同一页面但使用不同的实体,则客户端将进行另一个预订呼叫。
现在我要问的问题是,如何最好地退订该流,以及一般而言,在集线器连接停止/启动方案下,以及如果服务器显式中止连接(由于到access_token超时,从而触发客户端刷新其连接)?
似乎没有从api浮现出某些连接状态,因此我目前使用RxJs来向UI组件/服务浮现某些连接状态,即当集线器连接的开始调用成功时,我浮出“ true” ,并且在调用onclose回调时,我会显示“ false”。这使我可以尝试在先前断开的流上调用dispose来清理断开连接/停止连接期间的事情,然后在必要的情况下成功调用开始时再次对流进行预订。
我尝试在流上调用Dispose,如果集线器已连接,则可以,但是如果连接处于断开状态,则将出错。我想知道这是否是错误。即使在集线器断开连接的情况下,我也应该能够处理流吗?
可以先执行delete streamsubscription
然后根据需要重新创建吗?还是会以任何方式泄漏?
答案 0 :(得分:0)
在集线器连接停止/启动情况下,如果服务器显式中止连接(由于access_token超时并因此触发客户端刷新其连接),则流的生存期对客户端来说是什么。
当连接终止时(由于在客户端上调用stop
或服务器中止了连接),您的订户的error
方法将被调用,并显示一条错误消息,指示流已被删除。已终止,因为连接已终止。通常,您应该处理error
方法并将其视为终端事件(即,流永远不会产生其他对象)。在服务器上,如果连接(由任一端终止)将触发Context.ConnectionAborted
令牌,并且您可以停止写入流。
如果您已经在使用RxJS,我强烈建议您构建一个小型包装器,以将您从SignalR返回的对象转换为正确的RxJS Observable
。我们返回的对象实际上不是Observable
,而是具有所有相同的基本方法(subscribe
方法使用带有complete
,{{ 1}}和next
方法),因此包装起来应该很简单。
我尝试在流上调用Dispose,如果集线器已连接,则可以,但是如果连接处于断开状态,则将出错。我想知道这是否是错误。
是的,这可能是一个错误。如果在集线器断开连接后进行处理,我们不应该扔。您可以在https://github.com/aspnet/SignalR上提交吗?要解决此问题,您可以相当安全地error
错误并排除它(或者如果您偏执则将其记录下来)。
可以删除流订阅然后按要求重新创建吗?还是会以任何方式泄漏?
您应该始终 try...catch
订阅。如果您只是dispose
,那么我们将无法得知您已完成操作,因此我们永远不会告诉服务器停止。如果您呼叫delete
(并已连接),我们会向服务器发送一条消息,以“取消”该流。在ASP.NET Core 2.1中,我们不会向您公开此取消操作,但是我们会停止从dispose
中读取内容。在ASP.NET Core 2.2中,我们允许您在Hub方法中接受ChannelReader
,并且客户端上的CancellationToken
方法将在Hub方法中触发此令牌。我强烈建议您尝试使用ASP.NET Core 2.2的最新预览版,并在Hub方法中使用dispose
停止流:
CancellationToken
注意:如果执行此操作,则无需监视public ChannelReader<object> MyStreamingMethod(..., CancellationToken cancellationToken) {
// pass 'cancellationToken' over to whatever process is writing to the channel
// and stop writing when the token is triggered
}
,传递给您的Hub方法的令牌将涵盖所有取消情况。
在相关说明中,您应该始终使用Context.ConnectionAborted
创建您的频道。如果您使用无限制的通道,则泄漏内存将更加容易,因为写入器可以无限期地进行写入。如果您使用有界频道,则如果频道中有Channel.CreateBounded<T>(size)
个未读项目,则写入器将停止(WriteAsync
,WaitToWriteAsync
将被“阻止”)(例如,客户已断开连接,我们已停止阅读)。