从另一个AppDomain

时间:2018-02-03 01:19:38

标签: c# signalr owin appdomain

我有一个使用SignalR用C#编写的工作Web服务器。它是一个自我托管的Owin应用程序。一切正常。

现在我必须在不同的AppDomain中重新定位我的控制器。这打破了SignalR部分,因为GlobalHost仅在一个AppDomain中保持不变,并且不可序列化(因此我无法将其原样传递给其他AppDomain)。

我发现了许多关于从Controller /其他类/其他类调用SignalR hubs方法的示例/问题/教程,但没有从Default AppDomain(Owin应用程序初始化的那个)之外的任何内容中找到。

如何从与集线器不同的AppDomain中设置的控制器向客户端发送消息?

2 个答案:

答案 0 :(得分:0)

从外面看:

var context = GlobalHost.ConnectionManager.GetHubContext<YOURHUBCLASS>();
context.Clients.All.yourHubTask();

答案 1 :(得分:0)

我发现的解决方案非常简单:对于任何app -main间通信,我们需要能够跨越AppDomain边界的东西,即数据或类的代理。

因此,以下工作:

  1. 创建一个扩展MarshalByRefObject的类:当我们将它传递给另一个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; }
    }
    
  2. 确保您的参数为Serializable:此处,PublishParameter显然是正确的,但ChannelEvent也必须是可序列化的,并且只包含Serializable个成员等。

    1. 创建此类的实例并将其传递给不同AppDomains中的对象(communicationChannelInterAppDomainForSignalR的实例):

      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);
      
    2. 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);
          }
      }
      
    3. 就是这样=)

      可以找到有关如何实施app -main间通信的更多文档herehere