SignalR Self Host+MVC and other multi-terminal message push services (1)

Keywords: ASP.NET IIS REST

I. Overview

Because of the need of the project, there is a module function in the company's project recently, which requires immediate approval notification. The original design scheme is to use ajax to poll the server regularly. At the beginning, when the amount of data and usage is not large, it's good. Later, with the increase of usage and the complexity of various business in the system, the pressure of the server is also increasing, so I decided to use ajax to poll the server regularly. To replace Ajax polling queries with message push, when there is approval submission, the push method is called to push the message to the next approver, which reduces the pressure on the server.

Signal is an html websocket framework supported by Microsoft running on. NET platform. The main purpose of this system is to realize that the server pushes the message to the client page actively, so that the client does not have to re-send the request or use polling technology to get the message. And SignalR's compatibility is also very strong, here is not much to say. Now that SignalR has been chosen, let's get started.

My idea is to make SignalR a self-hosted service and separate it from our b/s project. The benefits are as follows: 1. Push service does not depend on iis, even if IIS hangs up, our push service can run normally; 2. We can call this push service on multiple platforms, and multiple projects can use it at the same time;

2. Creating Service Side

No more nonsense, I'm also the first time to write a blog. After introducing business scenarios and ideas, let's start coding.

1. Create a solution named "Signal RProject" with VS.

2. Create a new console named Server under the ignal RProject solution

3. On the package manager console, enter the following commands

1 Install-Package Microsoft.AspNet.SignalR.SelfHost 

4. Enter the following commands:

1 Install-Package Microsoft.Owin.Cors

 

5. Add the UserInfo class to the Server console with the following code

 1 using System;  
 2   
 3 namespace Server  
 4 {  
 5     public class UserInfo  
 6     {  
 7         public string ConnectionId { get; set; }  
 8         public string UserName { get; set; }  
 9         public DateTime LastLoginTime { get; set; }  
10     }  
11 }  

6. Add the ChatHub class to the Server console with the following code

  1 using Microsoft.AspNet.SignalR;
  2 using Microsoft.AspNet.SignalR.Hubs;
  3 using System;
  4 using System.Collections.Generic;
  5 using System.Linq;
  6 using System.Threading.Tasks;
  7 
  8 namespace Server
  9 {
 10     [HubName("IMHub")]
 11     public class ChatHub : Hub
 12     {
 13         // Static attributes
 14         public static List<UserInfo> OnlineUsers = new List<UserInfo>(); // Online User List
 15 
 16         /// <summary>
 17         /// Login Connection
 18         /// </summary>
 19         /// <param name="userId">user Id</param>
 20         /// <param name="userName">User name</param>
 21         public void Register(string userName)
 22         {
 23             var connnectId = Context.ConnectionId;
 24 
 25             if (OnlineUsers.Count(x => x.ConnectionId == connnectId) == 0)
 26             {
 27                 if (OnlineUsers.Any(x => x.UserName == userName))
 28                 {
 29                     var items = OnlineUsers.Where(x => x.UserName == userName).ToList();
 30                     foreach (var item in items)
 31                     {
 32                         Clients.AllExcept(connnectId).onUserDisconnected(item.ConnectionId, item.UserName);
 33                     }
 34                     OnlineUsers.RemoveAll(x => x.UserName == userName);
 35                 }
 36 
 37                 //Adding Online Personnel
 38                 OnlineUsers.Add(new UserInfo
 39                 {
 40                     ConnectionId = connnectId,
 41                     UserName = userName,
 42                     LastLoginTime = DateTime.Now
 43                 });
 44             }
 45 
 46             // All clients synchronize online users
 47             Clients.All.onConnected(connnectId, userName, OnlineUsers);
 48         }
 49 
 50         /// <summary>
 51         /// Send a private chat
 52         /// </summary>
 53         /// <param name="toUserId">Receiver User Connection ID</param>
 54         /// <param name="message">content</param>
 55         public void SendPrivateMessage(string toUserName, string message)
 56         {
 57             var fromConnectionId = Context.ConnectionId;
 58 
 59             var toUser = OnlineUsers.FirstOrDefault(x => x.UserName == toUserName);
 60             var fromUser = OnlineUsers.FirstOrDefault(x => x.ConnectionId == fromConnectionId);
 61 
 62             if (toUser != null )
 63             {
 64                 Clients.Client(toUser.ConnectionId).receivePrivateMessage(fromUser.UserName, message);
 65                 Clients.Client(toUser.ConnectionId).receivePrivateMessage(message);
 66             }
 67             else
 68             {
 69                 //Indicate that the other party is not online
 70                 Clients.Caller.absentSubscriber();
 71             }
 72         }
 73 
 74         public void Send(string name, string message)
 75         {
 76             //Clients.All { get; } // Represents all clients
 77             //Clients.AllExcept(params string[] excludeConnectionIds); // Except for all clients in the parameters
 78             //Clients.Client(string connectionId); // Specific client, this method is also the key to achieve end-to-end chat.
 79             //Clients.Clients(IList<string> connectionIds); // Client in parameter
 80             //Clients.Group(string groupName, params string[] excludeConnectionIds); // Specifying client groups is also the key to group chat
 81             //Clients.Groups(IList<string> groupNames, params string[] excludeConnectionIds);Client groups in parameters
 82             //Clients.User(string userId);  // Specific users
 83             //Clients.Users(IList<string> userIds); // Users in parameters
 84 
 85             Console.WriteLine("ConnectionId:{0}, InvokeMethod:{1}", Context.ConnectionId, "Send");
 86             Clients.All.addMessage(name, message);
 87         }
 88 
 89         /// <summary>
 90         /// Call when connecting
 91         /// </summary>
 92         /// <returns></returns>
 93         public override Task OnConnected()
 94         {
 95             Console.WriteLine("Client Connection ID yes:{0},The current number of people online is{1}", Context.ConnectionId, OnlineUsers.Count+1);
 96             return base.OnConnected();
 97         }
 98 
 99 
100         /// <summary>
101         /// Call when disconnected
102         /// </summary>
103         /// <param name="stopCalled"></param>
104         /// <returns></returns>
105         public override Task OnDisconnected(bool stopCalled)
106         {
107             var user = OnlineUsers.FirstOrDefault(u => u.ConnectionId == Context.ConnectionId);
108 
109             // Determine whether the user exists or not,Existence deletes
110             if (user == null)
111             {
112                 return base.OnDisconnected(stopCalled);
113             }
114 
115             Clients.All.onUserDisconnected(user.ConnectionId, user.UserName);   //Call client user offline notification
116             // delete user
117             OnlineUsers.Remove(user);
118             Console.WriteLine("Client disconnection, connection ID yes:{0},The current number of people online is{1}", Context.ConnectionId, OnlineUsers.Count);
119             return base.OnDisconnected(stopCalled);
120         }
121 
122         public override Task OnReconnected()
123         {
124             return base.OnReconnected();
125         }
126     }
127 }

 

7. Add the Startup class to the Server console with the following code

 1 using Microsoft.Owin.Cors;
 2 using Owin;
 3 
 4 namespace Server
 5 {
 6     public class Startup
 7     {
 8         public void Configuration(IAppBuilder app)
 9         {
10             //allow CORS Cross domain
11             app.UseCors(CorsOptions.AllowAll);
12             app.MapSignalR();
13         }
14     }
15 }

 

8. Modify the Server console to add the Program class, the code is as follows

 1 using Microsoft.Owin.Hosting;
 2 using System;
 3 
 4 namespace Server
 5 {
 6     class Program
 7     {
 8         static void Main(string[] args)
 9         {
10             string url = "http://localhost:10086";//Set up SignalR Hub Server External interface
11             using (WebApp.Start(url))//start-up SignalR Hub Server
12             {
13                 Console.WriteLine("Server running on {0}", url);
14                 Console.ReadLine();
15             }
16         }
17     }
18 }

 

9. F5 is running

Then access http://localhost:10086/signalr/hubs in the browser

The results are as follows:

See the picture above, it's almost finished. Today I'll talk about it first. It's not too early. I'll take a rest first. Then I'll have time to fill in the following articles.

Posted by hometoast on Tue, 18 Jun 2019 13:39:21 -0700