处理 WinForm UI 中已在 SignalR 持久连接端点 class 实例中引发的事件
Handling events in WinForm UI that have been raised in instance of a SignalR persistent connections endpoint class
所以,我整理了一个简单的 class 来创建一个 SignalR 服务器并启动 Owin.HttpListener 并允许客户端连接,到目前为止工作正常:创建服务器对象,服务器对象启动听众,客户端连接到听众,等等,等等,它有效。
但是,我遇到的问题是试图从 EndPoint class 引发事件并在 UI 处理它(Form1).到目前为止,我在让这些活动发挥作用方面运气为零。
我的假设是它可能与 主线程 上的 UI 运行 和 [=28= 中引发的事件有关]EndPoint class 运行 在 工作线程 上?但是,我不知道此时是否还缺少其他东西或该做什么。
下面的代码是我自己设置的。任何建议将不胜感激
Windows 表单调用代码:
Public Class Form1
Const ServerURI As String = "http://localhost:8081"
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'' create object and start server
Dim MyServer As New Server(ServerURI)
AddHandler MyServer.OnClientConnected, AddressOf ConnectionHandled
End Sub
Public Sub ConnectionHandled(connectionID As String)
MsgBox("It worked!")
End Sub
End Class
引用自 Windows Form1 的代码
Public Class Server
Private SignalR As IDisposable
Private Property uri As String
Private endPoint As EndPoint
Public Event OnClientConnected(connectionID As String)
Public Sub New(HostURI As String)
_uri = HostURI
StartServer()
endPoint = New EndPoint
AddHandler endPoint.OnClientConnected, AddressOf ClientConnected
End Sub
Private Sub StartServer()
Try
SignalR = WebApp.Start(uri)
Catch ex As Exception
'' Blah
End Try
End Sub
Private Sub ClientConnected(connectionID As String)
'' raise event for calling code
RaiseEvent OnClientConnected(connectionID)
End Sub
End Class
Public NotInheritable Class EndPoint
Inherits PersistentConnection
Public Event OnClientConnected(connectionID As String)
Protected Overrides Function OnConnected(request As IRequest, connectionId As String) As Task
RaiseEvent OnClientConnected(connectionID)
Return Me.Connection.Broadcast(String.Format("New Connectionn: {0}", connectionId))
End Function
End Class
Public Class Startup
Public Sub Configuration(app As IAppBuilder)
app.UseCors(CorsOptions.AllowAll).MapSignalR(Of MyEndPoint)("/signalr").MapSignalR()
End Sub
End Class
你的代码在结构上看起来是错误的,从中我无法理解所有部分属于哪里。
Server
class正在尝试连接到服务器,因此属于客户端,但是在其构造函数中实例化Endpoint
,它又继承自 PersistentConnection
,因此必须存在于服务器上,至于 Startup
class,但你说代码是 referenced 来自 Form1
,因此它似乎在客户端上运行,这是错误的。
即使您只是在错误的位置列出了服务器部分,尝试在客户端实例化 Endpoint
Server
也是完全错误的。其他事情看起来也不对,比如让服务器端 OnConnected
事件直接引发客户端事件。
因此,我认为您可能会错过一些有关 SignalR 的部分位置的基础知识。 IMO you should go back to basics 并了解这一点,以便修复您的代码。
编辑 1
好吧,我刚刚意识到我在 Server
class 之前读错了一行,这让事情变得更好,因为它使它成为一个合适的服务器端 class,但是在客户端实例化你的 Server
class 仍然是错误的,所以总的来说我认为我的建议仍然有效。
编辑 2
免责声明:我从未写过一行生产VB.NET代码,因此将其视为伪代码。
一种可能的方法是让您的服务器也成为客户端。添加 .NET client Nuget 包,并在启动服务器后在您的代码中添加:
Dim connection = New Connection(_uri)
AddHandler connection.Received, AddressOf ClientConnected
connection.Start().Wait()
您还将删除 Server
中对 Endpoint
的任何显式使用。有了这个,Server
也应该充当客户端,并且应该像任何其他客户端一样收到有关连接的通知,因此您的事件应该按计划触发。
这只是一个起点,但它应该能让您步入正轨。我从来没有真正尝试过这样的组合,但它应该有效。
还有其他方法(即绕过依赖注入),但这应该很简单。
我还看到您代码中的 Server
实例存在潜在的资源管理问题,您可能需要检查一下。
编辑 3
扩展依赖项注入的想法,如果您阅读 here,您可以了解如何控制 SignalR artifacts 的创建,包括集线器和持久连接。在您的情况下,您可以控制 Server
的生命周期,并且可以在启动时将其注册到 SignalR 的 DependencyResolver
中,然后调整 Endpoint
以在其构造函数中接收 Server
实例.通过这种方式,您可以轻松地看到如何从 SignalR 在进行广播时创建的任何 Endpoint
直接调用 Server
,从而解决您的问题。
在我看来,此解决方案比前一个解决方案更好,前一个解决方案完全合法,但感觉更像是一种 hack 和矫枉过正,因为迫使您在同一进程中的各个部分之间使用 HTTP 通信。
所以,我整理了一个简单的 class 来创建一个 SignalR 服务器并启动 Owin.HttpListener 并允许客户端连接,到目前为止工作正常:创建服务器对象,服务器对象启动听众,客户端连接到听众,等等,等等,它有效。
但是,我遇到的问题是试图从 EndPoint class 引发事件并在 UI 处理它(Form1).到目前为止,我在让这些活动发挥作用方面运气为零。
我的假设是它可能与 主线程 上的 UI 运行 和 [=28= 中引发的事件有关]EndPoint class 运行 在 工作线程 上?但是,我不知道此时是否还缺少其他东西或该做什么。
下面的代码是我自己设置的。任何建议将不胜感激
Windows 表单调用代码:
Public Class Form1
Const ServerURI As String = "http://localhost:8081"
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'' create object and start server
Dim MyServer As New Server(ServerURI)
AddHandler MyServer.OnClientConnected, AddressOf ConnectionHandled
End Sub
Public Sub ConnectionHandled(connectionID As String)
MsgBox("It worked!")
End Sub
End Class
引用自 Windows Form1 的代码
Public Class Server
Private SignalR As IDisposable
Private Property uri As String
Private endPoint As EndPoint
Public Event OnClientConnected(connectionID As String)
Public Sub New(HostURI As String)
_uri = HostURI
StartServer()
endPoint = New EndPoint
AddHandler endPoint.OnClientConnected, AddressOf ClientConnected
End Sub
Private Sub StartServer()
Try
SignalR = WebApp.Start(uri)
Catch ex As Exception
'' Blah
End Try
End Sub
Private Sub ClientConnected(connectionID As String)
'' raise event for calling code
RaiseEvent OnClientConnected(connectionID)
End Sub
End Class
Public NotInheritable Class EndPoint
Inherits PersistentConnection
Public Event OnClientConnected(connectionID As String)
Protected Overrides Function OnConnected(request As IRequest, connectionId As String) As Task
RaiseEvent OnClientConnected(connectionID)
Return Me.Connection.Broadcast(String.Format("New Connectionn: {0}", connectionId))
End Function
End Class
Public Class Startup
Public Sub Configuration(app As IAppBuilder)
app.UseCors(CorsOptions.AllowAll).MapSignalR(Of MyEndPoint)("/signalr").MapSignalR()
End Sub
End Class
你的代码在结构上看起来是错误的,从中我无法理解所有部分属于哪里。
Server
class正在尝试连接到服务器,因此属于客户端,但是在其构造函数中实例化Endpoint
,它又继承自 PersistentConnection
,因此必须存在于服务器上,至于 Startup
class,但你说代码是 referenced 来自 Form1
,因此它似乎在客户端上运行,这是错误的。
即使您只是在错误的位置列出了服务器部分,尝试在客户端实例化 Endpoint
Server
也是完全错误的。其他事情看起来也不对,比如让服务器端 OnConnected
事件直接引发客户端事件。
因此,我认为您可能会错过一些有关 SignalR 的部分位置的基础知识。 IMO you should go back to basics 并了解这一点,以便修复您的代码。
编辑 1
好吧,我刚刚意识到我在 Server
class 之前读错了一行,这让事情变得更好,因为它使它成为一个合适的服务器端 class,但是在客户端实例化你的 Server
class 仍然是错误的,所以总的来说我认为我的建议仍然有效。
编辑 2
免责声明:我从未写过一行生产VB.NET代码,因此将其视为伪代码。
一种可能的方法是让您的服务器也成为客户端。添加 .NET client Nuget 包,并在启动服务器后在您的代码中添加:
Dim connection = New Connection(_uri)
AddHandler connection.Received, AddressOf ClientConnected
connection.Start().Wait()
您还将删除 Server
中对 Endpoint
的任何显式使用。有了这个,Server
也应该充当客户端,并且应该像任何其他客户端一样收到有关连接的通知,因此您的事件应该按计划触发。
这只是一个起点,但它应该能让您步入正轨。我从来没有真正尝试过这样的组合,但它应该有效。
还有其他方法(即绕过依赖注入),但这应该很简单。
我还看到您代码中的 Server
实例存在潜在的资源管理问题,您可能需要检查一下。
编辑 3
扩展依赖项注入的想法,如果您阅读 here,您可以了解如何控制 SignalR artifacts 的创建,包括集线器和持久连接。在您的情况下,您可以控制 Server
的生命周期,并且可以在启动时将其注册到 SignalR 的 DependencyResolver
中,然后调整 Endpoint
以在其构造函数中接收 Server
实例.通过这种方式,您可以轻松地看到如何从 SignalR 在进行广播时创建的任何 Endpoint
直接调用 Server
,从而解决您的问题。
在我看来,此解决方案比前一个解决方案更好,前一个解决方案完全合法,但感觉更像是一种 hack 和矫枉过正,因为迫使您在同一进程中的各个部分之间使用 HTTP 通信。