Use SignalR in Asp. net mvc to implement the push function, mvcsignalr
I. Introduction
Signal is an html websocket framework supported by Microsoft running on the Dot NET platform. The main purpose of this function is to enable the server to actively Push messages to the client page, so that the client does not have to resend requests or use polling technology to obtain messages.
II. Implementation Mechanism
The implementation mechanism of SignalR is similar to that of. net wcf or Remoting. It is implemented using remote proxy. In specific use, there are two interfaces for different purposes: PersistentConnection and Hubs. PersistentConnection implements long Javascript round robin (similar to Comet ), hub is used to solve the problem of real-time information exchange. It is implemented by using Javascript dynamic loading and execution methods. SignalR encapsulates the entire connection and the information exchange process is very beautiful. the client and the server use JSON to exchange data.
The following describes the entire process of using the Hubs interface:
1. Define the corresponding hub class on the server side;
2. Define the proxy class corresponding to the hub class on the client;
3. establish a connection between the client and the server );
4. Then the client can call the proxy object method to call the server method, that is, send the request to the server;
5. After receiving the request, the server can send messages to A/group client or all clients (broadcast.
3. Hub example tutorial
1. Prepare the tool
SignalR runs on the. NET 4.5 platform, so you need to install. NET 4.5. For ease of demonstration, ASP. net mvc is used in this example in Win 7 system. Install ASP. net mvc 3 or ASP. net mvc 4.
2. Build a project
Open the ASP. net mvc 3 Web Application project named SignalRTutorial created in VS2010/VS2012, select the Internet Application template, Razor view engine, and select the Use HTMl 5 tab.
3. Install SignalR
Open the NuGet package manager console (Tools-> Library package manager), enter install-package SignalR. Sample, and press enter to install the package. :
4. Implement the Hub server code
Create a new SignalR directory in the project and add the ChatHub. cs file as follows:
Namespace SignalTutorial. SignalR
{
[HubName ("chat")]
Public class Chat: Hub
{
Public void Send (string clientName, string message)
{
// Var toSelfinfo = "You had sent message" + message;
// Caller. addSomeMessage (clientName, toSelfinfo );
// Call the addMessage method on all clients
Clients. addSomeMessage (clientName, message );
// Clients [Context. ConnectionId]. addSomeMessage (clientName, data );
}
}
}
In the above Code:
1) HubName is used to let the client know how to create a proxy object for the service corresponding to the server. If this attribute is not set, the service class name on the server is used as the default value of HubName;
2) Chat is inherited from the Hub. The following Hub interface diagram shows that the Hub supports the request initiator (Caller), all Clients (Clients), and specific groups) push messages.
3), public void Send (string clientName, string message) is called by the client through the proxy object;
4) Clients is the property of Hub, indicating the client pages of all links. It is dynamic like Caller, because it must correspond directly to Javascript objects;
5), Clients. addSomeMessage (clientName, message); indicates that the server calls the addSomeMessage method of the client. This is a Javascript method to push messages to the client.
6). Conclusion: The service implemented here is very simple. After a client calls the Send method to Send a message to the server, the server is responsible for broadcasting the message to all clients (you can also broadcast the message to a specific group or client, see the blocked Code) to implement the functions of the chat room.
5. Implement the Hub client code
1) Reference SignalR Javascript
To simplify the operation of referencing the SignalR script, I directly introduced SignalR and other scripts in View/Shared/_ Layout. cshtml:
<Head>
<Meta charset = "UTF-8"/>
<Title> @ ViewBag. Title </title>
<Link href = "@ Url. Content ("~ /Content/Site.css ")" rel = "stylesheet" type = "text/css"/>
<Script src = "@ Url. Content ("~ /Scripts/jquery-1.5.1.min.js ")" type = "text/javascript"> </script>
<Script src = "@ Url. Content ("~ /Scripts/jquery-1.6.4.js ")" type = "text/javascript"> </script>
<Script src = "@ Url. Content ("~ /Scripts/jquery-ui-1.8.24.js ")" type = "text/javascript"> </script>
<Script src = "@ Url. Content ("~ /Scripts/jquery. signalR-0.5.3.js ")" type = "text/javascript"> </script>
<Script src = "@ Url. Content ("~ /Scripts/modernizr-1.7.min.js ")" type = "text/javascript"> </script>
<Script src = "@ Url. Content ("~ /Signalr/hubs ")" type = "text/javascript"> </script>
</Head>
Note: signalR depends on jquery, so signalR must be placed after jquery, while hubs must be placed after signalR.
Then add the HubChat Tab to the body:
<Li> @ Html. ActionLink ("HubChat", "HubChat", "Home") </li>
2) generate an access page
Add the following method to HomeController:
Public ActionResult HubChat ()
{
ViewBag. ClientName = "user-" + Rnd. Next (10000,999 99 );
Return View ();
}
Here, the server sets the client name based on the random number, which is not rigorous enough, because the name generated by the random number is not unique. Here, it is only a simplified demonstration, and the GUID should be used in practical applications.
Then generate the corresponding View: HubChat. cshtml
@ Model dynamic
@{
ViewBag. Title = "title ";
}
<Script src = "@ Url. Content ("~ /Scripts/hubDemo. js ")" type = "text/javascript"> </script>
<Script type = "text/javascript">
$ (Document). ready (function (){
});
</Script>
<H2> Hub Chat
<Div>
<Input type = "text" id = "Placeholder" value = "@ ViewBag. ClientName" hidden = "true"/>
<Input type = "text" id = "msg"/>
<Input type = "button" id = "broadcast" value = "broadcast"/>
<Br/>
<Br/>
<H3>
Message record: (You are: <span id = "MyClientName"> @ ViewBag. ClientName </span> ):
</H3>
<Ul id = "messages">
</Ul>
</Div>
In the code on the above page, I added the hubDemo name. js script, which will be introduced below; there is also a hidden input control with id Placeholder to pass the client name to Javascript.
3) Compile Javascript
Add a new Javescript to the Scripts directory: hubDemo. js. The content is as follows:
$ (Function (){
Var myClientName = $ ('# Placeholder'). val ();
// Proxy created on the fly
Var chat = $. connection. chat;
// Declare a function on the chat hub so the server can invoke it
Chat. addSomeMessage = function (clientName, message ){
WriteEvent ('<B>' + clientName + '</B>:' + message, 'event-message ');
};
$ ("# Broadcast"). click (function (){
// Call the chat method on the server
Chat. send (myClientName, $ ('# msg'). val ())
. Done (function (){
Console. log ('sent message success! ');
})
. Fail (function (e ){
Console. warn (e );
});
});
// Start the connection
$. Connection. hub. start ();
// A function to write events to the page
Function writeEvent (eventLog, logClass ){
Var now = new Date ();
Var nowStr = now. getHours () + ':' + now. getMinutes () + ':' + now. getSeconds ();
$ ('# Messages '). prepend ('<li class = "+ logClass +"> <B>' + nowStr + '</B>' + eventLog + '. </li> ');
}
});
The code above has a detailed comment, and the key points are described below:
1. first obtain the name of the client page;
2. Then, use $. connection. chat to create a proxy chat for the Hub class on the server;
3. Define the client's Javascript method addSomeMessage. The server calls the client's method through dynamic to implement the push function. Every time you receive a message pushed by the server, you can insert the message in the messages list header on the client page.
4. When you click the broadcast button, the client uses the proxy object to call the send method of the server to send messages to the server.
5. Open the link through the $. connection. hub. start (); statement.
6) Compile and run the Hub example
Open the page in multiple browser windows. The effect is as follows:
Iv. Example of Persistent Connection
1. Implement server-side code
1) write the server PersistentConnection code
Add the PersistentConnection. cs file to the SignalR directory of the project. The content is as follows:
Using System;
Using System. Collections. Generic;
Using System. Threading. Tasks;
Using SignalR;
Namespace SignalTutorial. SignalR
{
Public class MyConnection: PersistentConnection
{
Protected override Task OnConnectedAsync (IRequest request, string connectionId)
{
Return Connection. Broadcast ("Connection" + connectionId + "connected ");
}
Protected override Task OnReconnectedAsync (IRequest request, IEnumerable <string> groups, string clientId)
{
Return Connection. Broadcast ("Client" + clientId + "re-connected ");
}
Protected override Task OnReceivedAsync (IRequest request, string connectionId, string data)
{
Var info = data + ". ConnectionId is [" + connectionId + "]";
// Return Connection. Send (connectionId, info );
// Broadcast data to all clients
Return Connection. Broadcast (info );
}
Protected override Task OnDisconnectAsync (string connectionId)
{
Return Connection. Broadcast ("Connection" + connectionId + "disconncted ");
}
Protected override Task OnErrorAsync (Exception error)
{
Return Connection. Broadcast ("Error ocurred" + error );
}
}
}
In the above Code:
1. MyConnection is inherited from PersistentConnection, so that we can process the connection in case of client connection, reconnection, disconnection, message sending, and connection error. The following PersistentConnection interface shows that PersistentConnection also supports group push.
2. Push messages are provided by the PersistentConnection attribute Connection, which inherits from the IConnection interface. This interface provides two functions to push and broadcast messages to specific clients.
System. Threading. Tasks. Task Send (string signal, object value)
System. Threading. Tasks. Task Broadcast (object value)
2) configure the access route
To support client access, you must configure it in the routing table. Open Global. asax. cs and modify the Application_Start () function as follows:
Protected void Application_Start ()
{
AreaRegistration. RegisterAllAreas ();
RouteTable. Routes. MapConnection <MyConnection> ("echo", "echo/{* operation }");
RegisterGlobalFilters (GlobalFilters. Filters );
RegisterRoutes (RouteTable. Routes );
// Make connections wait 50 s maximum for any response. After
// 50 s are up, trigger a timeout command and make the client reconnect.
GlobalHost. Configuration. ConnectionTimeout = TimeSpan. FromSeconds (50 );
// DisconnectTimeout
// HeartBeatInterval
// KeepAlive
}
In the above code, I map echo and its sub-path access to MyConnection, and set the connection timeout to 50 s. You can also set other parameters, such as the disconnection timeout time and heartbeat interval.
2. implement client code
1) generate an access page
Based on the previous three Hub sample tutorials, we will add the Persistent Connection demonstration to this project. Add the PersistentChat Tab to _ Layout. cshtml as before:
<Li> @ Html. ActionLink ("PersistentChat", "PersistentChat", "Home") </li>
Then add the following method to HomeController:
Public ActionResult PersistentChat ()
{
ViewBag. ClientName = "user-" + Rnd. Next (10000,999 99 );
Return View ();
}
Here, the server sets the client name based on the random number, which is not rigorous enough, because the name generated by the random number is not unique. Here, it is only a simplified demonstration, and the GUID should be used in practical applications.
Then generate the corresponding page: PersistentChat. cshtml:
@ Model dynamic
@{
ViewBag. Title = "title ";
}
<Script src = "@ Url. Content ("~ /Scripts/persistent. js ")" type = "text/javascript"> </script>
<H2> Persistent Chat
<Div>
<Input type = "text" id = "Placeholder" value = "@ ViewBag. ClientName" hidden = "true"/>
<Input type = "text" id = "msg"/>
<Input type = "button" id = "broadcast" value = "broadcast"/>
<Br/>
<Br/>
<H3>
Message record: (You are: <span id = "MyClientName"> @ ViewBag. ClientName </span> ):
</H3>
<Ul id = "messages">
</Ul>
</Div>
In the code on the above page, I added persistent. js script, which will be introduced below; there is also a hidden input control with id Placeholder to pass the client name to Javascript.
2) Compile Javascript
Add a new Javescript: persistent. js to the Scripts directory. The content is as follows:
$ (Function (){
Var myClientName = $ ('# Placeholder'). val ();
Var connection = $. connection ('/echo ');
Connection. received (function (data ){
Var msg = new String (data );
Var index = msg. indexOf ("#");
Var clientName = msg. substring (0, index );
Var content = msg. substring (index + 1 );
If (clientName = null | clientName = ""){
WriteEvent ('<B>' + "system message" + '</B>:' + content, 'event-message ');
}
Else {
WriteEvent ('<B>' + clientName + '</B>:' + content, 'event-message ');
}
});
Connection. start ();
$ ("# Broadcast"). click (function (){
Var msg = myClientName + "#" + $ ('# msg'). val ();
Connection. send (msg );
});
// A function to write events to the page
Function writeEvent (eventLog, logClass ){
Var now = new Date ();
Var nowStr = now. getHours () + ':' + now. getMinutes () + ':' + now. getSeconds ();
$ ('# Messages '). prepend ('<li class = "+ logClass +"> <B>' + nowStr + '</B>' + eventLog + '. </li> ');
}
});
The above code is basically the same as the previous Hub implementation and will not be described here. There are two points worth noting:
1. When creating a connection, specify the path "/echo". The route ing table on the server side is mapped to MyConnection. Therefore, the connection is directed to the MyConnection provided earlier.
2. Put the clientName information in the message, and use # To connect the clientName and message content into a msg.
3. Compile and run the Persistent example