SignalR 使用自定义 IUserIdProvider 从服务器定位特定用户

SignalR target a specific user from server with custom IUserIdProvider

我有一个使用 SignalR 和 WebAPI 的应用程序。我有一个基于令牌的自定义授权上下文,我使用 QueryString 在每个 SignalR 请求上提供该令牌。

我已经实施 IUserIdProvider,以便从令牌中检索我的用户。

最后,我想从服务器调用客户端方法,对于特定用户(带有 is ID),我正在使用来自 GlobalHost.ConnectionManager.

的 HubContext

我的问题是我的用户永远无法从我的 HubContext 中找到,但它来自 Hub 本身...

这是我的 IUserIdProvider 实现

public class SignalRUserIdProvider : IUserIdProvider
{
    public string GetUserId(IRequest request)
    {
        var token = request.QueryString["token"];
        var scope = GetUnprotectedScope(token);

        if (scope == null)
            return null;

        return scope.Id_User.ToString();
    }
}

这是我的 Hub 实现

[HubName("notifier")]
public class NotifierHub : Hub
{
    public void Notify(string message)
    {
        Clients.User("1").Notify(message); //When call from a client, this works very well, only the User with the Id = 1 receive the notification
    }
}

最后,我使用它从我的服务器调用客户端方法:

GlobalHost
    .ConnectionManager
    .GetHubContext<NotifierHub>()
    .Clients
    .User("1")
    .Notify(notification.Message);
    // This does nothing...

我现在无法解决,我不明白会发生什么,有人已经实现了吗?

我终于解决了这个问题,但我不知道如何解决...

实际问题很简单,Hub本身与客户和一切都有很好的背景,但GlobalHost.ConnectionManager什么都没有。

如果我将 Hub 更改为如下所示:

[HubName("notifier")]
public class NotifierHub : Hub
{
    public void Notify(string message)
    {
        Clients.User("1").Notify(message + " from Hub itself");

        GlobalHost
            .ConnectionManager
            .GetHubContext<NotifierHub>()
            .Clients
            .User("1")
            .Notify(message + " from ConnectionManager");
    }
}

我的客户收到 "My message from Hub itself",但从未收到 "My message from ConnectionManager"。

总之,我的 DependencyInjection 有问题...我正在使用 Structuremap 和这个 DependencyResover :

public class StructureMapSignalRDependencyResolver : DefaultDependencyResolver
{
    private IContainer _container;

    public StructureMapSignalRDependencyResolver(IContainer container)
    {
        _container = container;
    }

    public override object GetService(Type serviceType)
    {
        if (serviceType == null)
            return null;

        var service = _container.TryGetInstance(serviceType) ?? base.GetService(serviceType);
        if (service != null) return service;

        return (!serviceType.IsAbstract && !serviceType.IsInterface && serviceType.IsClass)
            ? _container.GetInstance(serviceType)
            : _container.TryGetInstance(serviceType);
    }

    public override IEnumerable<object> GetServices(Type serviceType)
    {
        var objects = _container.GetAllInstances(serviceType).Cast<object>();
        return objects.Concat(base.GetServices(serviceType));
    }
}

我的启动文件:

public void Configuration(IAppBuilder app)
{
    app.Map("/signalr", RegisterSignalR);
}

public static void RegisterSignalR(IAppBuilder map)
{
   var resolver = new StructureMapSignalRDependencyResolver(IoC.Initialize());
   var config = new HubConfiguration { Resolver = resolver };

   map.UseCors(CorsOptions.AllowAll);
   map.RunSignalR(config);
}

最后是我的注册表...

For<Microsoft.AspNet.SignalR.IDependencyResolver>().Add<StructureMapSignalRDependencyResolver>();

For<INotifier>().Use<SignalRNotifier>();