问题描述
我有一个使用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.
现在,我必须将控制器重新放置在不同的AppDomain中.这破坏了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).
我已经找到了许多关于从Controller/其他类/类调用SignalR集线器方法的示例/问题/教程,但没有从Default AppDomain(用于初始化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方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!