C# 到多台服务器上映射的用户的信令连接

C# 到多台服务器上映射的用户的信令连接,c#,asp.net-mvc-4,redis,signalr,C#,Asp.net Mvc 4,Redis,Signalr,我有以下信号集线器、一个Redis背板和一台服务器。 在一台服务器上这样工作非常好。 现在,我需要在多台服务器上运行我的应用程序,但我不知道如何映射 将用户连接到连接,以便在两台服务器上共享signalR ConnectionId。 也许一个解决方案是将ConnectionMapping存储在Redis上,但我不知道如何实现。 这就是我的解决方案目前的工作方式 MyHub.cs public class MyHub : Hub { #region Init

我有以下信号集线器、一个Redis背板和一台服务器。 在一台服务器上这样工作非常好。 现在,我需要在多台服务器上运行我的应用程序,但我不知道如何映射 将用户连接到连接,以便在两台服务器上共享signalR ConnectionId。 也许一个解决方案是将ConnectionMapping存储在Redis上,但我不知道如何实现。 这就是我的解决方案目前的工作方式

MyHub.cs

public class MyHub : Hub
    {
        #region Init
        private static IHubContext GetHubContext => GlobalHost.ConnectionManager.GetHubContext<MyHub>();
  
        public MyHub()
        {
        }
        #endregion Init

        #region Connection Management events
        public Task JoinGroup(string groupName)
        {
            return Groups.Add(Context.ConnectionId, groupName);
        }

        public Task LeaveGroup(string groupName)
        {
            return Groups.Remove(Context.ConnectionId, groupName);
        }
        [Authorize]
        public override Task OnConnected()
        {
            if (Context.User != null)
            {
                if (Context.User.Identity.IsAuthenticated)
                {
                    var userId = Context.User.Identity.GetUserId<int>();
                    if (userId == 0)
                    {
                        var userManager = HttpContext.Current.GetOwinContext().GetUserManager<MyUserManager>();
                        var user = userManager.FindByName(Context.User.Identity.Name);
                        if (user != null)
                            userId = user.Id;
                    }
                    var userRoles = UserRoles.GetAll().Where(x => Context.User.IsInRole(x)).ToArray();

                    ConnectionMappingsService.AddConnectionAsync(Context.ConnectionId, userId, userRoles);

                    if (Context.User.IsInRole(UserRoles.Admin))
                        UserStatusChanged(userId, true);
                }
            }
            return base.OnConnected();
        }
        [Authorize]
        public override Task OnDisconnected(bool stopCalled)

        {
           
            UserDisconnectedAsync(Context.ConnectionId);
            return base.OnDisconnected(stopCalled);
        }

public static async Task MessageCreatedMobile(int userId)
        {
            var SignalRMessage = new
            {
                ClientEvent = "Message",
                Flag = "Update",
                Target “Test”
            };
            var recipientConnectionIds = await ConnectionMappingsService.GetUserConnectionsAsync(userId);
            var hubContext = GlobalHost.ConnectionManager.GetHubContext<MyHub>();// GetHubContext;
            try
            {
                foreach (var connection in recipientConnectionIds)
                {
                    hubContext.Clients.Client(connection).send(SignalRMessage);
                }
            }
            catch (Exception ex)
            {
            }
        }
公共类MyHub:Hub
{
#区域初始化
私有静态IHubContext GetHubContext=>GlobalHost.ConnectionManager.GetHubContext();
公共MyHub()
{
}
#端域初始化
#区域连接管理事件
公共任务组(字符串组名)
{
返回Groups.Add(Context.ConnectionId,groupName);
}
公共任务组(字符串组名)
{
返回Groups.Remove(Context.ConnectionId,groupName);
}
[授权]
已连接的公用覆盖任务()
{
if(Context.User!=null)
{
if(Context.User.Identity.IsAuthenticated)
{
var userId=Context.User.Identity.GetUserId();
if(userId==0)
{
var userManager=HttpContext.Current.GetOwinContext().GetUserManager();
var user=userManager.FindByName(Context.user.Identity.Name);
如果(用户!=null)
userId=user.Id;
}
var userRoles=userRoles.GetAll().Where(x=>Context.User.IsInRole(x)).ToArray();
ConnectionMappingService.AddConnectionAsync(Context.ConnectionId、userId、userRoles);
if(Context.User.IsInRole(UserRoles.Admin))
UserStatusChanged(userId,true);
}
}
返回base.OnConnected();
}
[授权]
公共覆盖任务OnDisconnected(bool stopCalled)
{
UserDisconnectedAsync(Context.ConnectionId);
返回基.OnDisconnected(stopCalled);
}
公共静态异步任务MessageCreatedMobile(int userId)
{
var信号消息=新建
{
ClientEvent=“Message”,
Flag=“更新”,
目标“测试”
};
var RecipientConnectionId=await ConnectionMappingService.GetUserConnectionAsync(用户ID);
var hubContext=GlobalHost.ConnectionManager.GetHubContext();//GetHubContext;
尝试
{
foreach(RecipientConnectionId中的var连接)
{
hubContext.Clients.Client(connection).send(SignalRMessage);
}
}
捕获(例外情况除外)
{
}
}
ConnectionMappingService.cs

public static class ConnectionMappingsService
    {
        private static readonly ConnectionMapping<int> UsersConnections = new ConnectionMapping<int>();
        private static readonly ConnectionMapping<string> RoleConnections = new ConnectionMapping<string>();

        public static async Task AddConnectionAsync(string connectionId, int userId, string[] roles)
        {
            var userConnectionTask = UsersConnections.AddAsync(new int[] { userId }, connectionId);
            var roleConnectionTask = RoleConnections.AddAsync(roles, connectionId);
            await Task.WhenAll(userConnectionTask, roleConnectionTask);
        }
        public static async Task AddConnectionIfAbsentAsync(string connectionId, int userId, string[] roles)
        {
            var userConnectionTask = UsersConnections.AddIfAbsentAsync(new int[] { userId }, connectionId);
            var roleConnectionTask=  RoleConnections.AddIfAbsentAsync(roles, connectionId);
            await Task.WhenAll(userConnectionTask, roleConnectionTask);
        }

        public static async Task<ConnectionDataDto> RemoveConnectionAsync(string connectionId)
        {
            var result = new ConnectionDataDto();
            result.UserIds = await UsersConnections.RemoveAsync(connectionId);
            result.Roles = await RoleConnections.RemoveAsync(connectionId);
            return result;
        }

        public static async Task<IEnumerable<string>> GetUserConnectionsAsync(int userId)
        {
            return await UsersConnections.GetConnectionsAsync(new int[] { userId });
        }
        public static async Task<IEnumerable<string>> GetUserConnectionsAsync(int[] userIds)
        {
            return await UsersConnections.GetConnectionsAsync(userIds);
        }
        public static async Task<IEnumerable<string>> GetRoleConnectionsAsync(string[] roles)
        {
            return await RoleConnections.GetConnectionsAsync(roles);
        }

        public static async Task<bool> UserHasConnectionsAsync(int userId)
        {
            return await UsersConnections.AnyConnectionsAsync(userId);
        }
    }
}
公共静态类ConnectionMappingService
{
私有静态只读ConnectionMapping UsersConnections=new ConnectionMapping();
私有静态只读ConnectionMapping RoleConnections=新ConnectionMapping();
公共静态异步任务AddConnectionAsync(字符串connectionId、int userId、字符串[]角色)
{
var userConnectionTask=UsersConnections.AddAsync(新的int[]{userId},connectionId);
var roleConnectionTask=RoleConnections.AddAsync(角色,连接ID);
wait Task.WhenAll(userConnectionTask、roleConnectionTask);
}
公共静态异步任务addConnectionFabSentAsync(字符串connectionId,int userId,字符串[]角色)
{
var userConnectionTask=UsersConnections.AddIfAbsentAsync(新的int[]{userId},connectionId);
var roleConnectionTask=RoleConnections.AddIfAbsentAsync(角色,连接ID);
wait Task.WhenAll(userConnectionTask、roleConnectionTask);
}
公共静态异步任务RemoveConnectionAsync(字符串connectionId)
{
var result=new connectiondatato();
result.UserIds=await UsersConnections.RemoveAsync(connectionId);
result.Roles=wait RoleConnections.RemoveAsync(connectionId);
返回结果;
}
公共静态异步任务GetUserConnectionAsync(int userId)
{
返回wait UsersConnections.getConnectionAsync(新的int[]{userId});
}
公共静态异步任务GetUserConnectionAsync(int[]userIds)
{
返回wait UsersConnections.getConnectionAsync(userid);
}
公共静态异步任务GetRoleConnectionsAsync(字符串[]角色)
{
返回wait-RoleConnections.getConnectionAsync(角色);
}
公共静态异步任务UserHasConnectionAsync(int userId)
{
返回wait UsersConnections.anyconnectionasync(userId);
}
}
}
ConnectionMapping.cs

 public class ConnectionMapping<T>
    {
        private readonly Dictionary<T, HashSet<string>> _connections = new Dictionary<T, HashSet<string>>();


        public async Task<int> CountAsync()
        {
            return await Task.Run(()=> Count());
        }
        public async Task AddAsync(T[] keys, string connectionId)
        {
            await Task.Run(() => Add(keys, connectionId));
        }
        public async Task AddIfAbsentAsync(T[] keys, string connectionId)
        {
            await Task.Run(() => AddIfAbsent(keys,connectionId));
        }
        
        public async Task<IEnumerable<string>> GetConnectionsAsync(T[] keys)
        {
            return await Task.Run(() => GetConnections(keys));
        }
        
        public async Task<T[]> RemoveAsync(string connectionId)
        {
          return await Task.Run(()=>Remove(connectionId) ) ;
        }
        public async Task<T[]> GetConnectionKeysAsync(string connectionId)
        {
            return await Task.Run(() => GetConnectionKeys(connectionId));
        }
        public async Task<bool> AnyConnectionsAsync(T key)
        {
            return await Task.Run(() => AnyConnections(key));
        }


        #region NonAsync
        public int Count()
        {
            lock (_connections)
            {
                return _connections.Count;
            }
        }
        public void Add(T[] keys, string connectionId)
        {
            
            if (keys == null || !keys.Any())
                return;

            lock (_connections)
            {
                foreach (T key in keys)
                {
                    HashSet<string> connections;
                    if (!_connections.TryGetValue(key, out connections))
                    {
                        connections = new HashSet<string>();
                        _connections.Add(key, connections);
                    }

                    lock (connections)
                    {
                        connections.Add(connectionId);
                    }
                }
            }
        }
        public void AddIfAbsent(T[] keys, string connectionId)
        {
            if (keys == null || !keys.Any())
                return;

            lock (_connections)
            {
                foreach (T key in keys)
                {
                    HashSet<string> connections;
                    if (!_connections.TryGetValue(key, out connections))
                    {
                        connections = new HashSet<string>();
                        _connections.Add(key, connections);
                    }

                    lock (connections)
                    {
                        if (!connections.Contains(connectionId))
                            connections.Add(connectionId);
                    }
                }
            }
        }
        public IEnumerable<string> GetConnections(T[] keys)
        {
            var result = new HashSet<string>();
            lock (_connections)
            {                
                foreach (var key in keys)
                {
                    HashSet<string> connections;
                    if (_connections.TryGetValue(key, out connections))
                    {
                       result.UnionWith(connections);
                    }
                }
                
            }

            return result as IEnumerable<string>;
        }
        public T[] Remove(string connectionId)
        {
            T[] keys;
            lock (_connections)
            {
                keys = _connections.Where(x => x.Value.Contains(connectionId)).Select(x => x.Key).ToArray();
                foreach (var key in keys)
                {
                    HashSet<string> connections;
                    if (!_connections.TryGetValue(key, out connections))
                    {
                        continue;
                    }
                    lock (connections)
                    {
                        connections.Remove(connectionId);

                        if (connections.Count == 0)
                        {
                            _connections.Remove(key);
                        }
                    }
                }
            }
            return keys;
        }
        public T[] GetConnectionKeys(string connectionId)
        {
            lock (_connections)
            {
                var keys = _connections.Where(x => x.Value.Contains(connectionId)).Select(x => x.Key).ToArray();
                return keys;
            }
        }
        public bool AnyConnections(T key)
        {
            lock (_connections)
            {
                HashSet<string> connections;
                if (!_connections.TryGetValue(key, out connections))
                {
                    return false;
                }
                else
                {
                    return connections.Any();
                }
            }
        }
        #endregion NonAsync
    }
}
公共类连接映射
{
专用只读词典_connections=new Dictionary();
公共异步任务CountAsync()
{
返回等待任务。运行(()=>Count());
}
公共异步任务AddAsync(T[]键,字符串连接ID)
{
等待任务。运行(()=>Add(key,connectionId));
}
公共异步任务AddIfAbsentAsync(T[]键,字符串连接ID)
{
等待任务。运行(()=>AddFabSent(键,连接ID));
}
公共异步任务GetConnectionAsync(T[]键)
{
返回等待任务。运行(()=>GetConnections(键));
}
公共异步任务RemoveAsync(字符串连接ID)
{
返回等待任务。运行(()=>Remove(connectionId));
}
公共异步任务GetConnectionKeysA