Background
OA management system, the employee submits the application form, the news real-time notification to the relevant personnel timely approval, after approval will push the result to the user.
Technology options
The first discovery was firebase, so excited to start Daoteng up. Firebase is simple to use: quoting a JS can be, the official web-based tutorials quickly applied to the project. Open the project the next day discover the push function is not so, why? Finally found Firebase official website can't open ... Firebase by Google will also be the celestial to the wall off? Perhaps Firebase himself hung up, in short, it is not used. There are a couple of things to worry about when pushing data to the Firebase server for push-to-drive:
1. Data not secure
2. Dependence on Firebase is too strong
3.firebase charge (free version too weak)
So decisively give up firebase, friend recommended there is a call signalr East can try, this is a special for the ASP. NET developers to prepare a message push class library, and do not rely on other servers, free.
How to use
1. Search for and add the latest version of SIGNALR in NuGet
2. Refer to the Jquery.signalr-2.2.0.min.js file in the page (dependent on jquery) and add <script src= "/signalr/hubs" ></script> Scripts for automatic generation of SIGNALR
3. Add the MsgHub.cs class for handling the corresponding user information and message push implementations
usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingsystem.web;usingMicrosoft.AspNet.SignalR;usingMicrosoft.AspNet.SignalR.Hubs;namespacezmeioa.services{
[Authorize] [Hubname ("Zmhub")] Public classMsghub:hub {/// <summary> ///Connection/// </summary> /// <returns></returns> Public OverrideSystem.Threading.Tasks.Task onconnected () {Groups.add (Context.connectionid, Context.User.Identity. Name); return Base. Onconnected (); } /// <summary> ///re-connect/// </summary> /// <returns></returns> Public OverrideSystem.Threading.Tasks.Task onreconnected () {Groups.add (Context.connectionid, Context.User.Identit Y.name); return Base. Onreconnected (); } /// <summary> ///Disconnect Connection/// </summary> /// <param name= "stopcalled" ></param> /// <returns></returns> Public OverrideSystem.Threading.Tasks.Task ondisconnected (BOOLstopcalled) {Groups.remove (Context.connectionid, Context.User.Identity.Name); return Base. Ondisconnected (stopcalled); } }}
Note: SIGNALR push messages are based on user connection (ConnectionID), SIGNALR automatically generates a ConnectionID for each session. But our push is based on the user (permission system), that is, only after login to register to this hub. Here I use is signalr in the groups, the login user's ConnectionID and corresponding UserID added to the groups, push the time just specify groups name, SIGNALR will automatically find its corresponding ConnectionID and send a message (this may not be the best way, because each user's userid will be added as a groups key, when the user is very large, groups will be very large, But I haven't found a better alternative.
4. There are two forms of message push: A. server direct push; b. Client Push.
The difference is that the server pushes the message to the relevant person directly after persisting the data, and after the client pushes the persisted data, the client uses the Signalr JS method to invoke the push function of the server based on the return value. I use the server-side push data directly, because after persisting the data can be completely according to the business notify the relevant person, if return to the foreground and then call the service side of the push method is only superfluous.
For example, notify the approver immediately after saving the application form.
Get the hub context in the service
/// <summary> /// Message Push Context /// </summary> protected Static Ihubcontext Zmhubcontext = globalhost.connectionmanager.gethubcontext<msghub> ();
Push messages to relevant people after saving the request (note: The dynamic method Broadcasttodo is the method that the client needs to receive the message)
Public Static applyform Save (FormView view) {
Omit business operations ...
//...
// notification to-dos ZmHubContext.Clients.Groups (app. Auditorids.split (','new' new ', data = App}); return app;}
5. Connect the hub when registering the angular module and pass it as value into the module so that each controller can use the connection:
var zmhub = $.connection. Zmhub; var zmApp = angular.module (' zmApp ', [' Ngroute ', ' ngresource ', ' ngsanitize ', ' ngmessages ', ' Ngsvgattributes ']). Value (' Zmhub ', zmhub);
6. Receive push messages in the controller on the home page and provide two push experiences: a. Desktop notifications; b. In-page messages. Desktop notifications are cool, even when the browser is minimized, you can get a hint in the lower right corner of the desktop (Chrome and Firefox support, ie not supported)
ZmHub.client.broadcastTodo =function(UserIDs, obj) {//notify subordinate controller pending$scope. $broadcast (' todoschanged ', obj); //Show Desktop Notifications if(Obj.type = = ' new ') {
Desktop Notification Headervartitle = ' Application form from [' + Obj.data.ApplicantName + ']; //application Form type name varFormtypename = Defaultservice.getenumtext (17, Obj.data.Type); varmsg = ' [' + Formtypename + '] ' +Obj.data.Name;
Desktop Notification method Notifyservice.notify (' Todos ', title, MSG); }}
Subordinate controller receiving method (about Angularjs broadcast not much explanation, do not understand the website can be consulted):
//receive push to- dos$scope. $on (' todoschanged ',function(d, obj) {$scope. $apply (function () {
If this is a new data, add one in the current listif(Obj.type = = ' new ') {$scope. Todoapps.unshift (Obj.data); } Else if(Obj.type = = ' Delete '{//If it is a revocation request, the data in the current list is deleted for(varj = 0; J < $scope. Todoapps.length; J + +) { if($scope. Todoapps[j]. Id = =obj.data.Id) {$scope. Todoapps.splice (J,1); Break; } } } });});
Desktop Notification Service:
//Desktop Notification ServiceZmapp.factory (' Notifyservice ',function () { return{Notify:function(icon, title, msg) {//at first, let's check if we have permission for notification //If not, let's ask for it if(Window. Notification && notification.permission!== "granted") {notification.requestpermission (function(status) {if(Notification.permission!==status) {notification.permission=status; } }); } varIconPath = '/content/images/icons/' + (icon | | ' info ') + '. png '; varOptions ={lang:' ZH-CN ', body:msg, Icon:iconpath}; varnotify; //If The user agreed to get notified if(Window. Notification && notification.permission = = = "Granted") {Notify=NewNotification (title, options); } Else if(Window. Notification && notification.permission!== "denied") {notification.requestpermission (function(status) {if(Notification.permission!==status) {notification.permission=status; } if(Status = = = "Granted") {Notify=NewNotification (title, options); } Else{Console.log (' You have banned desktop notifications and cannot be pushed to your desktop! ‘); } }); } Else{Console.log (' You have banned desktop notifications and cannot be pushed to your desktop! ‘); } if(notify) {Notify.onclose=function(evt) {}; //Click Switch to BrowserNotify.onclick =function() {window.focus (); }; } } };});
Desktop Notification Effect:
Summarize:
With SIGNALR push message generally relatively simple, just a few steps can be achieved, and is selfhost, do not have to worry about other server dependencies and data security issues, interested friends can try
Angularjs+asp.net MVC+SIGNALR for message push