Home  >  Article  >  Backend Development  >  angularJS+asp.net mvc+SignalR implements message push

angularJS+asp.net mvc+SignalR implements message push

伊谢尔伦
伊谢尔伦Original
2016-11-26 11:50:561226browse

Background

In the OA management system, employees submit application forms, and the message is notified in real time to relevant personnel for timely approval. After approval, the results are pushed to the user.

Technology Selection

The first thing I discovered was firebase, so I started to speculate very excitedly. Firebase is easy to use: just quote a js, and follow the tutorials on the official website to quickly apply it to the project. When I opened the project the next day, I found that the push function was not working. Why? Finally, I found that the firebase official website could not be opened. . . Could it be that if Firebase is taken over by Google, it will also be blocked by China? Maybe firebase itself hangs up, but it can't be used anymore. Because the push data must be completely stored on the firebase server to implement the push function, there will be the following issues to worry about:

1. Data is not safe

2. Too strong dependence on firebase

3. Firebase charges ( The free version is too weak)

So I gave up firebase decisively. A friend recommended something called SignalR to try. This is a message push library specially prepared for ASP.NET developers and does not rely on other servers. free.

How to use

1. Search and add the latest version of SignalR in nuget

angularJS+asp.net mvc+SignalR implements message push

2. Reference the jquery.signalR-2.2.0.min.js file (depends on jquery) in the page, and then add Script used to automatically generate signalr

3. Add the MsgHub.cs class for processing corresponding user information and message push implementation

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Hubs;
namespace ZmeiOA.Services
{
   [Authorize]
    [HubName("ZmHub")]
    public class MsgHub : Hub
    {/// <summary>
        /// 连接
        /// </summary>
        /// <returns></returns>
        public override System.Threading.Tasks.Task OnConnected()
        {
            Groups.Add(Context.ConnectionId, Context.User.Identity.Name);
            return base.OnConnected();
        }
        /// <summary>
        /// 重新连接
        /// </summary>
        /// <returns></returns>
        public override System.Threading.Tasks.Task OnReconnected()
        {
            Groups.Add(Context.ConnectionId, Context.User.Identity.Name);
            return base.OnReconnected();
        }
        /// <summary>
        /// 断开连接
        /// </summary>
        /// <param name="stopCalled"></param>
        /// <returns></returns>
        public override System.Threading.Tasks.Task OnDisconnected(bool stopCalled)
        {
            Groups.Remove(Context.ConnectionId, Context.User.Identity.Name);
            return base.OnDisconnected(stopCalled);
        }
    }
}

Description: SignalR push The message is based on the user connection (ConnectionId), and SignalR will automatically generate a ConnectionId for each session. But our push is based on users (permission system), that is, you can only register to this Hub after logging in. What I use here is Groups in SignalR. I add the logged-in user’s ConnectionId and the corresponding UserId to Groups. When pushing, I only need to specify the Name of the Groups, and SignalR will automatically find out its corresponding ConnectionId and send the message (this This method may not be the best, because each user's UserId will be added as the Key of Groups. When the number of users is large, Groups will also be very large, but I haven't found a better alternative yet).

4. There are two forms of message push: a. Direct push from the server; b. Push from the client.

The difference is that server-side push can directly push the message to the relevant person after persisting the data; while client-side push is after persisting the data, the client uses the JS method of SignalR to call the server based on the return value. Push function. I use the server to push data directly, because after persisting the data, I can notify the relevant people according to the business. If I return to the front desk and then call the server's push method, it is just unnecessary.

For example: Notify the approver immediately after saving the application form

Get the context of the Hub in Service

 

/// <summary>
  /// 消息推送上下文
  /// </summary>
  protected static IHubContext ZmHubContext = GlobalHost.ConnectionManager.GetHubContext<MsgHub>();

Push messages to relevant personnel after saving the application form (note: the dynamic method broadcastTodo is when the client needs to receive messages method)

public static ApplyForm Save(FormView view)
{  
   //省略业务操作...
   //...
    //通知待办事项
    ZmHubContext.Clients.Groups(app.AuditorIds.Split(&#39;,&#39;)).broadcastTodo(app.AuditorIds, new { type = "new", data = app });
    return app;
}

5. Connect the Hub when registering the Angular module and pass it into the module as a value, so that each controller can use this connection:

 var zmHub = $.connection.ZmHub;
  var zmApp = angular.module(&#39;zmApp&#39;, [&#39;ngRoute&#39;, &#39;ngResource&#39;, &#39;ngSanitize&#39;, &#39;ngMessages&#39;, &#39;ngSVGAttributes&#39;]).value(&#39;zmHub&#39;, zmHub);

6. Receive the pushed message in the controller on the homepage, and Provides two push experiences: a. Desktop notifications; b. In-page messages. Desktop notifications are cool. Even when the browser is minimized, you can receive prompts in the lower right corner of the desktop (supported by Chrome and Firefox, but not IE)

zmHub.client.broadcastTodo = function (userIds, obj) {
    //通知下级控制器有待办事项
    $scope.$broadcast(&#39;todoschanged&#39;, obj);
    //显示桌面通知
    if (obj.type == &#39;new&#39;) {
     //桌面通知标题
        var title = &#39;来自[&#39; + obj.data.ApplicantName + &#39;]的申请单&#39;;
        //申请单类型名称
        var formTypeName = DefaultService.getEnumText(17, obj.data.Type);
        var msg = &#39;[&#39; + formTypeName + &#39;]&#39; + obj.data.Name;
     //桌面通知方法
        NotifyService.Notify(&#39;todos&#39;, title, msg);
    }
}

The receiving method of the lower-level controller (not much explanation about the broadcast of angularjs , if you don’t understand, you can check it on the official website):

//接收推送的待办事项
$scope.$on(&#39;todoschanged&#39;, function (d, obj) {
    $scope.$apply(function () {
     //如果是新增数据,在当前列表中添加一条
        if (obj.type == &#39;new&#39;) {
            $scope.todoApps.unshift(obj.data);
        }
        else if (obj.type == &#39;delete&#39;) {//如果是撤销申请,则把当前列表中那条数据删除
            for (var j = 0; j < $scope.todoApps.length; j++) {
                if ($scope.todoApps[j].Id == obj.data.Id) {
                    $scope.todoApps.splice(j, 1);
                    break;
                }
            }
        }
    });
});

Desktop notification service:

//桌面通知服务
zmApp.factory(&#39;NotifyService&#39;, function () {
    return {
        Notify: function (icon, title, msg) {
            // At first, let&#39;s check if we have permission for notification
            // If not, let&#39;s ask for it
            if (window.Notification && Notification.permission !== "granted") {
                Notification.requestPermission(function (status) {
                    if (Notification.permission !== status) {
                        Notification.permission = status;
                    }
                });
            }
            var iconPath = &#39;/Content/images/icons/&#39; + (icon || &#39;info&#39;) + &#39;.png&#39;;
            var options = {
                lang: &#39;zh-CN&#39;,
                body: msg,
                icon: iconPath
            };
            var notify;
            // If the user agreed to get notified
            if (window.Notification && Notification.permission === "granted") {
                notify = new Notification(title, options);
            }
            else if (window.Notification && Notification.permission !== "denied") {
                Notification.requestPermission(function (status) {
                    if (Notification.permission !== status) {
                        Notification.permission = status;
                    }
                    if (status === "granted") {
                        notify = new Notification(title, options);
                    }
                    else {
                        console.log(&#39;您禁止了桌面通知,无法推送到您的桌面!&#39;);
                    }
                });
            }
            else {
                console.log(&#39;您禁止了桌面通知,无法推送到您的桌面!&#39;);
            }
            if (notify) {
                notify.onclose = function (evt) {
                };
                //点击切换到浏览器
                notify.onclick = function () {
                    window.focus();
                };
            }
        }
    };
});

Desktop notification effect:

angularJS+asp.net mvc+SignalR implements message push

Summary:

Using SignalR to push messages is generally relatively simple, and only requires a few simple steps It can be achieved in just one step, and it is selfhost, so you don’t have to worry about dependence on other servers and data security issues. Interested friends can try it


Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn