SignalR将数据传递给包含类
本文关键字:包含类 数据 SignalR | 更新日期: 2023-09-27 18:16:36
我有一个服务,并希望通过SignalR(在OWIN上)添加与之交互的能力。有很多关于如何向客户机发送消息的示例,但是如何从客户机接收消息并将其转发到父服务呢?
。
public class MyService
{
...
public void LaunchSR()
{
_srWebApp = WebApplication.Start<SrStartup>("http://localhost:" + _signalRPortNumber.ToString());
_srContext = GlobalHost.ConnectionManager.GetHubContext<MyHub>();
}
public class SrStartup
{
public void Configuration(Owin.IAppBuilder app)
{
app.MapConnection("/raw", typeof(PersistentConnection), new ConnectionConfiguration { EnableCrossDomain = true });
app.MapHubs();
}
}
public class MyHub : Hub
{
public void SendToServer(string data)
{
//!! Don't have a reference to MyService instance,
//!! so LocalCommand is out of scope
LocalCommand(data, null);
}
}
public void LocalCommand(data)
{
// Do Stuff in the main service context, accessing private objects etc.
}
}
SendToServer()
中的代码有编译时错误:
"不能通过嵌套类型MyHub访问外部类型MyService的非静态成员"。
我知道为什么会这样,但不知道如何正确地做到这一点。
Hub实例是暂时的,因此您需要创建某种类型的反转。一种方法是在单例类中创建类似通信代理的东西,两者通过该代理进行通信。
public class HubToServiceProxy {
public static readonly HubToServiceProxy Instance = new HubToServiceProxy();
private HubToServiceProxy() {}
private MyService m_svc;
// call this when the service starts up, from the service
public void RegisterService (MyService svc) {
// Be very careful of multithreading here,
// the Proxy should probably lock m_svc on
// every read/write to ensure you don't have problems.
m_svc = svc;
}
// call this from the hub instance to send a message to the service
public void SendCommandToService(string data) {
m_svc.LocalCommand(data, null);
}
}
,然后做:
public class MyService
{
...
public MyService() {
HubToServiceProxy.Instance.RegisterService(this);
}
...
}
public class MyHub : Hub
{
public void SendToServer(string data)
{
HubToServiceProxy.Instance.SendCommandToService(data);
}
}
注意事项:
-
RegisterService (MyService svc)
可以完全删除,用一个监听事件来代替:也就是说,你可以通过事件来实现观察者模式(或者像。net那样):而不是在通信代理中记录服务引用。- 服务将监听通信代理上的事件(在实例化时,它将订阅通信代理上的事件),
- 和
SendCommandToService
方法将引发CommandFromClient
事件,而不是调用服务。
- 如果你想坚持将代理和服务耦合:
-
RegisterService (MyService svc)
应该是RegisterService (ILocalCommand svc)
,其中ILocalCommand
是定义LocalCommand
方法签名的接口,由MyService
实现 - 你可以使用静态类,而不是单例(你的调用)
- 如果你有多个服务实例,你可以保留它们的列表,并将数据发送给所有它们,或者某种关键字字典,它允许你过滤发送数据的位置。
-
- 您可以实现工厂,以便在Hub实例化时调用工厂来获取通信代理。这将有助于执行基于DI的测试。 您可能不会通过代理将服务直接公开给Hub,因为这会破坏OO设计的规则,比如封装、内聚和松耦合。
有很多种方法来切割它,你需要根据你的具体情况选择最好的一个。要记住的主要事情是集线器是瞬时的,因此它们必须调用某种非瞬时的服务器端端点,该端点将:将消息传递给服务;或者返回一个对象实例,集线器可以将消息传递给该对象实例以进行分发。显然,这个初始调用不能是另一个类的实例,因此静态或单例类是您唯一的选择。
反过来,这就是GlobalHost.ConnectionManager.GetHubContext<MyHub>()
方法允许服务器类的实例与客户端通信的方法。它为您自己的实例提供了一个非瞬态端点,以便在它们想要与客户端通信时调用。