2014-02-12 64 views
4

在發現this update圍繞與組進行通信後,看起來組中的某個組被鍵入了樞紐名稱。如果這是正確的(請讓我知道如果我錯了)是否有任何方式讓樞紐訪問另一個樞紐的小組或更好地擁有某種全球組?SignalR組可以在不同的集線器之間共享嗎?

我的問題是,我有一個集線器,增加了客戶端的一組:

public class GameService : Hub, IGameService 
... 
public void CreateNewGame(CreateGameDto game) 
    { 
     game.Creator = UserRepo.GetUser(Context.ConnectionId); 
     var newGame = GameRepo.CreateNewGame(game); 
     Groups.Add(Context.ConnectionId, newGame.GameId.ToString(CultureInfo.InvariantCulture)); 
     Clients.Caller.JoinedGame(newGame); 
    } 

和另一個集線器完全需要廣播到該組:現在

public class MessagingService : Hub , IMessageService 
    ... 
     public void AddMessage(MessageDto message) 
    { 
     message.User = UserRepo.GetUser(Context.ConnectionId); 
     MessageRepo.AddMessage(message); 
     Clients.Group(message.User.GameId.ToString(CultureInfo.InvariantCulture)) 
      .ReceivedMessage(message); 
    } 

截至,客戶永遠不會收到這個廣播。

編輯添加客戶端代碼。 這裏是客戶端信號設置,我創建了一個框架,允許我使用Castle Dynamic Proxy的服務接口,這樣我就不會通過字符串名稱調用服務和方法。

public abstract class BaseClientProxy<TServer,TClient> 
{ 
    public TServer ServiceProxy; 

    protected BaseClientProxy(HubConnection conn) 
    { 
     ServiceProxy = CreateProxy(conn); 
    } 

    private ProxyGenerator _generator; 
    protected IHubProxy Proxy; 
    protected TClient Receiver; 

    protected TServer CreateProxy(HubConnection conn) 
    { 
     Proxy = conn.CreateHubProxy<TServer>(); 

     _generator = new ProxyGenerator(); 

     return (TServer)_generator.CreateInterfaceProxyWithoutTarget(typeof(TServer), new HubProxyInterceptor(Proxy)); 
    } 

    public void SetReceiver(TClient receiver) 
    { 
     Receiver = (TClient)_generator.CreateInterfaceProxyWithTarget(typeof(TClient), receiver); 
     RegisterEvents(); 
    } 

    protected void RegisterEvents() 
    { 
     Action<MethodInfo> regAction = RegisterEvent<object>; 
     var methods = 
      typeof (TClient).GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public); 
     foreach (var methodInfo in methods) 
     { 
      var locInfo = methodInfo; 
      if (locInfo.GetParameters().Length > 0) 
      { 
       var regMethod = typeof(BaseClientProxy<TServer, TClient>).GetMethodExt(regAction.Method.Name, typeof(MethodInfo)); 
       var genAction = regMethod.MakeGenericMethod(locInfo.GetParameters()[0].ParameterType); 
       genAction.Invoke(null, new object[] { locInfo }); 
      } 
      else 
      { 
       Proxy.On(locInfo.Name,() =>locInfo.Invoke(Receiver, null)); 
      } 
     } 
    } 

    protected void RegisterEvent<TDto>(MethodInfo method) 
    { 
     Proxy.On<TDto>(method.Name, x => method.Invoke(Receiver, new object[] {x})); 
    } 
} 

public class HubProxyInterceptor : IInterceptor 
{ 
    protected IHubProxy Proxy; 

    public HubProxyInterceptor(IHubProxy proxy) 
    { 
     Proxy = proxy; 
    } 

    protected async void Invoke<TDto>(string methodName, TDto dto) 
    { 
     await Proxy.Invoke(methodName, dto); 
    } 

    protected async void Invoke(string methodName) 
    { 
     await Proxy.Invoke(methodName); 
    } 

    public void Intercept(IInvocation invocation) 
    { 
     if (invocation.Arguments.Length > 0) 
     { 
      Invoke(invocation.Method.Name, invocation.Arguments[0]); 
     } 
     else 
     { 
      Invoke(invocation.Method.Name); 
     } 
    } 
} 

這些片段來自singleton類,它建立連接並將服務註冊到windsor容器中。

private SignalRManager() 
    { 
     var settings = Settings.GetSettings<IClientSettings>(ConfigurationManager.AppSettings); 

     Connection = new HubConnection(settings.SignalRServerUri); 

     ioc = new WindsorContainer(); 
     ioc.Register(
      Component.For<BaseClientProxy<IUserService, IUserClient>>().Instance(new UserServiceProxy(Connection)), 
      Component.For<BaseClientProxy<IDrawingService, IDrawingClient>>().Instance(new DrawingServiceProxy(Connection)), 
      Component.For<BaseClientProxy<IMessageService, IMessageClient>>().Instance(new MessageServiceProxy(Connection)), 
      Component.For<BaseClientProxy<IScoreBoardService, IScoreBoardClient>>().Instance(new ScoreBoardServiceProxy(Connection)), 
      Component.For< BaseClientProxy<IGameService,IGameClient>>().Instance(new GameServiceProxy(Connection))); 
     Connection.Start().Wait(); 
    } 
    public TClient GetService<TClient,TReceiver>(TReceiver receiver) where TClient : IService 
    { 
     var proxy = ioc.Resolve<BaseClientProxy<TClient, TReceiver>>(); 
     proxy.SetReceiver(receiver); 
     return proxy.ServiceProxy; 
    } 

在此代碼中,HubProxyInterceptor負責完成對服務器的所有調用。

而BaseClientProxy中的RegisterEvents方法負責將來自服務器的調用連接到客戶端。 TServer和TClient類型參數是2個不同但類似的接口,TServer將由服務器端的Hub類實現,並且TClient由我的WPF視圖模型實現,這是在調用SetReceiver時傳入的內容。

回答

4

您可以在MessagingService.AddMessage中使用GetHubContext將消息發送到其他Hub組。

public void AddMessage(MessageDto message) 
{ 
    IHubContext gameContext = GlobalHost.ConnectionManager.GetHubContext<GameService>(); 

    message.User = UserRepo.GetUser(Context.ConnectionId); 
    MessageRepo.AddMessage(message); 

    gameContext.Clients.Group(message.User.GameId.ToString(CultureInfo.InvariantCulture)) 
     .ReceivedMessage(message); 
} 

你可以在一個領域gameContext存儲,如果你不想重新創建它在每次調用方法addMessage。

+0

這也不起作用,我使用自我主機配置是否有關係?服務器是一個控制檯應用程序,我現在唯一的客戶端是一個WPF應用程序。 – Phaeze

+0

好吧,在GameService中,我試着拔出MessageService上下文並添加到那裏的組中,這很好,但這意味着我需要爲其他服務做同樣的事情,如果我可以只使用GameService上下文。任何想法,爲什麼它以一種方式但不是另一種方式? – Phaeze

+0

我將不得不看你的客戶端代碼。顯然,我建議應該工作。也許你的客戶在啓動SignalR連接時沒有正確訂閱GameService中心。 – halter73

相關問題