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

时间:2015-03-23 15:35:54

标签: c# asp.net signalr signalr-hub

我使用SignalR& amp;的WebAPI。我有一个基于令牌的自定义授权上下文,我使用QueryString为每个SignalR请求提供。

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

最后,我想从服务器调用客户端方法,对于特定用户(具有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 imlementation

[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...

我现在没有解决问题,我不明白会发生什么,有没有人已经实现了这个目标?

1 个答案:

答案 0 :(得分:1)

我终于想出了这个问题,但我不知道如何修复它......

实际问题很简单,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");
    }
}

我的客户收到&#34;来自Hub本身的消息&#34;,但从未收到来自ConnectionManager&#34;我的消息。

总之,我的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>();