【问题标题】:Can SignalR group be shared between different hubs?SignalR 组可以在不同的集线器之间共享吗?
【发布时间】:2014-02-14 07:06:36
【问题描述】:

在与群组通信时找到this update 后,似乎有一个群组与集线器名称无关。如果这是正确的(如果我弄错了请告诉我)集线器有什么方法可以访问另一个集线器的组,或者更好的是拥有某种全局组?

我的问题是我有一个将客户端添加到组的集线器:

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);
        }
    }
}

这些 sn-ps 来自一个单例类,该类建立连接并在 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 时传入的。

【问题讨论】:

    标签: signalr


    【解决方案1】:

    您可以在 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);
    }
    

    如果您不想在每次调用 AddMessage 时重新创建 gameContext,可以将其存储在字段中。

    【讨论】:

    • 这也不起作用,我使用自主机配置有什么关系吗?服务器是一个控制台应用程序,我现在唯一的客户端是一个 WPF 应用程序。
    • 好的,所以在 GameService 中,我尝试拉出 MessageService 上下文并添加到那里的组中,这很好,但这只是意味着我需要对其他服务做同样的事情好吧,这将比我只使用 GameService 上下文更多的代码。关于为什么它以一种方式起作用而不是另一种的任何想法?
    • 我必须查看您的客户端代码。显然,我的建议应该有效。当您启动 SignalR 连接时,您的客户端可能未正确订阅 GameService 中心。
    • 我已经添加了处理连接到集线器的连接的客户端代码,希望它清楚。
    • 您还没有添加调用 HubConnection.Start 的代码。 在调用 HubConnection.Start 之前,您需要从同一个 HubConnection 创建两个 HubProxy 对象(一个用于 GameService 和 MessagingService),否则您将不会收到来自这些集线器的消息。 asp.net/signalr/overview/signalr-20/hubs-api/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-19
    • 2022-12-19
    • 2021-03-03
    • 2015-02-10
    相关资源
    最近更新 更多