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.