我有两个有关 SignalR 集线器连接的相关问题,但在讨论它们之前,我将仅提供一些有关我正在做的事情的背景信息。
语境
我有一个使用 SignalR 将通知从服务器发送到前端(Javascript)客户端的应用程序。但是,还有一个后端 (.NET) 客户端可以创建中心的代理。后端客户端处理通知并将其发送到集线器,然后集线器将这些通知发送到前端客户端。
更具体地说,我有一个通知处理类,我们称之为NotificationProcessor.cs。每次创建新通知时,NotificationProcessor都会实例化一个实例。实例化后NotificationProcessor,将设置与集线器的代理连接。我有一个类,HubProxyService.cs它创建HubConnection对象并IHubProxy从中创建对象。其片段如下:
this.HubConnection = new HubConnection(serverUrl);
this.HubProxy = HubConnection.CreateHubProxy(hubName);
Task t = Task.Run(() => this.HubConnection.Start(new LongPollingTransport()));
t.WaitAndUnwrap();
Run Code Online (Sandbox Code Playgroud)
NotificationProcessor然后使用该IHubProxy对象调用集线器中的方法。
我发现HubConnection每次创建对象都会被实例化,并且在完成后NotificationProcessor不处理会导致内存泄漏。HubConnection
问题
(1)为了避免内存泄漏,我需要HubConnection以某种方式进行处置。我读到我可以做到
Task.Run(() => this.HubConnection.Stop())
Run Code Online (Sandbox Code Playgroud)
问题是我不知道什么时候可以调用它。由于使用代理调用 hub 方法是异步的,我可以在调用 hub 方法后立即调用它吗?或者,如果从集线器向前端客户端发送通知出现延迟,这是否会导致问题?
我想另一种选择是将 HubConnection 初始化包装在 using 语句中,如下所示
using (HubConnection connection = new HubConnection(serverUrl))
{
}
Run Code Online (Sandbox Code Playgroud)
我听说这也可能有问题,因为处理HubConnection可能需要一段时间。
有一个比另一个更好吗?后者似乎更惯用,而前者更明确并且可能效果更好。
(2) 为创建的HubConnection每个实例创建 …
我希望我的 SignalR 服务器每 n 秒更新一次仪表板。我现在正在使用这个:
public class MyHub : Hub
{
public override Task OnConnectedAsync()
{
Observable.Interval(TimeSpan.FromSeconds(0.5)).Subscribe(l =>
{
var alt = CalcAltitude(l);
SendMessage(alt);
});
return Task.CompletedTask;
}
private void SendMessage(double alt)
{
Clients.All.SendAsync("SendAction", new Status() {Altitude = alt});
}
private double CalcAltitude(long l)
{
return 100 * Math.Sin((double) l / 100) + 200;
}
}
public class Status
{
public double Altitude { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
当我的代码被执行时,它抛出一个异常说
无法访问已处置的对象
我怀疑我在这里做错了什么。
那么,及时向所有客户端发送消息的正确方法是什么?
我正在尝试从 (ASP.NET Core) MVC 控制器调用信号集线器类中的方法,但我无法在网上找到演示如何操作的示例。
注意:有很多示例在 .Net 框架中使用旧版本的信号器,但我看不到任何示例都显示了如何在 .Net Core 中执行此操作。
我需要将 MVC 操作结果中的 id 直接传递到我的集线器,而不是将 id 传递到页面,然后必须将客户端连接返回到集线器。
public class ChatHub : Hub
{
public async Task DoSomething(int id)
{
//// Something in here.
}
}
public class HomeController : Controller
{
private readonly IHubContext<ChatHub> _hubContext;
public HomeController(IHubContext<ChatHub> hubContext)
{
_hubContext = hubContext;
}
public async Task<ActionResult> Index(int id)
{
//// Call the DoSomething method from here, passing the id across.
await _hubContext.Clients.All.SendAsync("AddToGroup", groupId);
}
}
Run Code Online (Sandbox Code Playgroud)
请问有没有办法做到这一点?(或者我是否以错误的方式看待这个问题,是否有更好的方法来实现相同的结果?)
更新:如果我将 Id …
c# signalr signalr-hub asp.net-core-mvc asp.net-core-signalr
我正在使用 SignalR DotNetCore,我创建了组,我需要向组中的所有客户端发送消息,除了具有 Connection Id 的特定客户端。
我有一个 SignalR 集线器,我希望对其进行单元测试。该集线器非常简单,只是它在构造函数中包含一个 IHubContext 参数。我遇到的问题是,任何对 UpdateData 方法进行单元测试以便我可以验证 DataModel 数据属性是否已更新的尝试都会因空引用异常而失败。到目前为止,我只能验证该方法是否被调用。是不是我没有正确模拟 HubContext 依赖项?
任何人都可以提供如何解决此问题的详细信息吗?
using Microsoft.AspNetCore.SignalR;
using Moq;
using System.Threading;
using System.Threading.Tasks;
using Xunit;
namespace Tests
{
public class DataModel
{
public string Name { get; set; }
public string Job { get; set; }
}
public class DataHub : Hub
{
private readonly IHubContext<DataHub> _hubContext;
private DataModel data;
public DataHub(IHubContext<DataHub> context)
{
_hubContext = context;
}
public override async Task OnConnectedAsync()
{
await Groups.AddToGroupAsync(Context.ConnectionId, "DataGroup");
}
public void UpdateData(DataModel update)
{ …Run Code Online (Sandbox Code Playgroud) 通过 SignalR 向客户端发送不同对象列表的最佳方式是什么?
当我使用具有相同基类的对象列表时,客户端仅接收基类的属性:
class Update { }
class UpdateA { public string PropertyA {get; set;}}
class UpdateB { public string PropertyB {get; set;}}
...
IEnumerable<Update> updates = GetUpdates();
await Clients.Caller.SendAsync("update", updates);
Run Code Online (Sandbox Code Playgroud)
当我使用字符串形式的预序列化数据时,序列化器将 json 数据转义为字符串。
IEnumerable<string> updates = GetUpdates();
await Clients.Caller.SendAsync("update", updates);
// data looks like: [ "{...}", "{...}" ]
Run Code Online (Sandbox Code Playgroud)
我必须编写自己的序列化程序吗?SignalR 在 dotnet core 中如何工作?
我在 .Net 5 中有一个 Blazor 服务器应用程序,它工作正常。最近,我添加了一个用于通知消息的 SignalR HubConnection,但由于在生产服务器中建立了 SSL 连接,我遇到了异常,如下所示:
Workflow2.Common.DalException: The SSL connection could not be established, see inner exception.
---> System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure: RemoteCertificateNameMismatch
at System.Net.Security.SslStream.SendAuthResetSignal(ProtocolToken message, ExceptionDispatchInfo exception)
at System.Net.Security.SslStream.ForceAuthenticationAsync[TIOAdapter](TIOAdapter adapter, Boolean receiveFirst, Byte[] reAuthenticationData, Boolean isApm)
at System.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore(Boolean async, Stream stream, SslClientAuthenticationOptions sslOptions, CancellationToken cancellationToken)
--- End of inner exception stack trace ---
[2022-01-26 13:07:30.970][ERR]: InnerException Message
System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure: …Run Code Online (Sandbox Code Playgroud) 我正在使用带有集线器的SignalR 0.5.3,我明确地将传输设置为长轮询,如下所示:
$.connection.hub.start({ transport: 'longPolling' }, function () {
console.log('connected');
});
Run Code Online (Sandbox Code Playgroud)
使用这样的配置(在global.asax.cs Application_Start方法中):
GlobalHost.DependencyResolver.UseRedis(server, port, password, pubsubDB, "FooBar");
GlobalHost.Configuration.DisconnectTimeout = TimeSpan.FromSeconds(2);
GlobalHost.Configuration.KeepAlive = TimeSpan.FromSeconds(15);
Run Code Online (Sandbox Code Playgroud)
然而,长期轮询似乎既不适用于开发(IIS express)也不适用于生产(IIS 7.5)环境.连接似乎正常,但长轮询请求总是超时(约2分钟后),之后重新连接.IIS的日志在这里.第一次超时请求的回复:
{"MessageId":"3636","Messages":[],"Disconnect":false,"TimedOut":true,"TransportData":{"Groups":["NotificationHub.56DDB6692001Ex"],"LongPollDelay":0}}
Run Code Online (Sandbox Code Playgroud)
超时重新连接响应如下所示:
{"MessageId":"3641","Messages":[],"Disconnect":false,"TimedOut":true,"TransportData":{"Groups":["NotificationHub.56DDB6692001Ex"],"LongPollDelay":0}}
Run Code Online (Sandbox Code Playgroud)
对于这个问题,我将不胜感激.谢谢.
编辑
如果重新连接意味着新的长轮询周期的开始,为什么在global.asax.cs中的KeepAlive设置设置为15秒后~2分钟后启动?问题在于我在IIS前面有一个反向代理,它在25秒后超时保持活动请求,因此当达到此反向代理超时时,我得到504响应.
我在控制台应用程序中托管了一个集线器,并连接了一个WPF应用程序.它运作得很好.然后我将集线器移动到一个单独的项目中,并将主机的引用添加到新项目中.现在我收到500错误,没有其他细节.
为了从另一个汇编/命名空间托管集线器,是否需要做任何不同的事情?
编辑:打开问题后我尝试了一些事情.这是我到目前为止所尝试的:
这是传回的异常."System.Net.WebException:远程服务器返回错误:(500)内部服务器错误.位于Microsoft.AspNet.SignalR.Client.Http.HttpHelper的System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult).<> c_ DisplayClass2 System.Threading.Tasks.TaskFactory 1.FromAsyncCoreLogic(IAsyncResult iar, Func2中的.b _0(IAsyncResult ar)endFunction,Action 1 endAction, Task1 promise,Boolean requiresSynchronization)"
我有一个连接到的userDetails列表,hub我将这些用户存储到List<UserDetails>。我想将一些用户添加Group到,并向该组广播消息。但是我不知道如何创建一个小组,这是我到目前为止所做的:
foreach(var user in userDetails)
{
Groups.Add(user.connectionId, "Connected");
}
Clients.Group("Connected").broadcastMessage(message);
Run Code Online (Sandbox Code Playgroud) signalr-hub ×10
signalr ×7
c# ×4
.net-core ×2
.net ×1
asp.net ×1
asp.net-core ×1
long-polling ×1
memory-leaks ×1
moq ×1
xunit ×1