从不同的 AppDomain 调用 SignalR 方法
Call a SignalR method from a different AppDomain
我有一个使用 SignalR 用 C# 编写的工作 Web 服务器。这是一个自托管的 Owin 应用程序。一切正常。
现在我必须在不同的 AppDomain 中重新定位我的控制器。这打破了 SignalR 部分,因为 GlobalHost
仅在一个 AppDomain 中保持不变,并且不可序列化(因此我无法将它按原样传递给其他 AppDomain)。
我发现了很多 examples/questions/tutorials 关于从 Controller/an 其他 class/whatever 调用 SignalR 集线器方法的内容,但在默认 AppDomain(Owin 应用程序所在的那个)之外没有任何内容已初始化)。
如何从设置在与 Hub 不同的 AppDomain 中的控制器向客户端发送消息?
从外面:
var context = GlobalHost.ConnectionManager.GetHubContext<YOURHUBCLASS>();
context.Clients.All.yourHubTask();
我找到的解决方案非常简单:对于任何 AppDomain 间通信,我们需要可以跨越 AppDomain 边界的东西,因此数据或 class.[=22= 的代理]
因此,以下工作:
创建一个 class 扩展 MarshalByRefObject:当我们将它传递给另一个 class 在不同的 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
成员,等等...
创建这个class的一个实例并传递给不同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
实例中,随意使用;) :
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);
}
}
就是这样=)
我有一个使用 SignalR 用 C# 编写的工作 Web 服务器。这是一个自托管的 Owin 应用程序。一切正常。
现在我必须在不同的 AppDomain 中重新定位我的控制器。这打破了 SignalR 部分,因为 GlobalHost
仅在一个 AppDomain 中保持不变,并且不可序列化(因此我无法将它按原样传递给其他 AppDomain)。
我发现了很多 examples/questions/tutorials 关于从 Controller/an 其他 class/whatever 调用 SignalR 集线器方法的内容,但在默认 AppDomain(Owin 应用程序所在的那个)之外没有任何内容已初始化)。
如何从设置在与 Hub 不同的 AppDomain 中的控制器向客户端发送消息?
从外面:
var context = GlobalHost.ConnectionManager.GetHubContext<YOURHUBCLASS>();
context.Clients.All.yourHubTask();
我找到的解决方案非常简单:对于任何 AppDomain 间通信,我们需要可以跨越 AppDomain 边界的东西,因此数据或 class.[=22= 的代理]
因此,以下工作:
创建一个 class 扩展 MarshalByRefObject:当我们将它传递给另一个 class 在不同的 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
成员,等等...
创建这个class的一个实例并传递给不同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
实例中,随意使用;) :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); } }
就是这样=)