从不同的 AppDomain 调用 SignalR 方法 [英] Call a SignalR method from a different AppDomain
问题描述
我有一个使用 SignalR 用 C# 编写的工作 Web 服务器.这是一个自托管的 Owin 应用程序.一切正常.
I have a working web server written in C# using SignalR. It's a self-hosted Owin Application. Everything works fine.
现在我必须在不同的 AppDomains 中重新定位我的控制器.这打破了 SignalR 部分,因为 GlobalHost
仅在一个 AppDomain 中保持不变,并且不可序列化(因此我无法将其按原样传递给其他 AppDomain).
Now I have to relocate my controllers in different AppDomains. This breaks the SignalR part, because GlobalHost
remains the same only within one AppDomain, and is not serializable (thus I can't pass it along to other AppDomains as it is).
我发现了很多关于从控制器/其他类/任何东西调用 SignalR 集线器方法的示例/问题/教程,但没有来自默认应用程序域(Owin 应用程序被初始化的那个)之外的任何内容.
I've found a lot of examples/questions/tutorials about calling SignalR hubs methods from a Controller/an other class/whatever, but nothing from outside the Default AppDomain (the one where the Owin application is initialized).
如何从与集线器不同的 AppDomain 中设置的控制器向客户端发送消息?
How can I send a message to a client from a controller set in a different AppDomain than the Hub ?
推荐答案
我找到的解决方案非常简单:对于任何跨 AppDomain 通信,我们需要一些可以跨越 AppDomain 边界的东西,因此数据或代理去上课.
The solution I found is pretty simple: as for any inter-AppDomain communication, we need something that can cross the boundaries of an AppDomain, thus data or a proxy to a class.
因此,以下工作:
创建一个扩展 MarshalByRefObject 的类:当我们将它传递给不同 AppDomain 中的另一个类时,这将自动创建该类的代理
Create a class extending MarshalByRefObject: this will automatically create a proxy to this class when we pass it to a other class in a different AppDomain
public class InterAppDomainForSignalR : MarshalByRefObject
{
public void Publish(PublishParameter param) {
var clients = GlobalHost.ConnectionManager.GetHubContext<TradeHub>().Clients;
dynamic chan;
if (param.group != null && param.group.Length > 0)
{
chan = clients.Group(param.group, param.ids);
}
else
{
if(param.ids == null || param.ids.length = 0) {
return; //not supposed to happen
}
chan = clients.Client(param.ids[0]);
}
chan.OnEvent(param.channelEvent.ChannelName, param.channelEvent);
}
}
[Serializable]
public class PublishParameter
{
public string group { get; set; }
public string[] ids { get; set; }
public ChannelEvent channelEvent { get; set; }
}
确保您的参数是 Serializable
:这里,PublishParameter
显然是正确的,但是 ChannelEvent
也必须是可序列化的,并且只包含 Serializable
成员等...
Make sure your parameters are Serializable
: here, PublishParameter
is obviously correct, BUT ChannelEvent
has to be serializable too, and contain only Serializable
members, etc...
创建这个类的一个实例并将其传递给不同AppDomains中的对象(
communicationChannel
是InterAppDomainForSignalR
的一个实例):
AppDomain domain = AppDomain.CreateDomain(myDomainName);
Type type = typeof(ClassInOtherAppDomain);
ClassInOtherAppDomain startpoint = (ClassInOtherAppDomain)domain.CreateInstanceAndUnwrap(
type.Assembly.FullName,
type.FullName) as ClassInOtherAppDomain;
var session = startpoint.initialize(communicationChannel);
将 communicationChannel
存储在 ClassInOtherAppDomain
实例中,并随意使用它;) :
Store the communicationChannel
in the ClassInOtherAppDomain
instance, and use it at will ;) :
public class ClassInOtherAppDomain {
private InterAppDomainForSignalR communicationChannel { get; set; }
public void initialize(InterAppDomainForSignalR communicationChannel) {
this.communicationChannel = communicationChannel;
}
public void Publish(PublishParameter param) {
this.communicationChannel.Publish(param);
}
}
就是这样 =)
关于如何实现跨 AppDomain 通信的更多文档可以在 这里和这里.
More documentation on how to implement inter-AppDomain communication can be found here and here.
这篇关于从不同的 AppDomain 调用 SignalR 方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!