使用SignalR和简单的js客户端实现Abp通知

3

我正在尝试使 Abp 通知(notification)正常工作。后端使用 Asp.net boilerplate,使用 asp.net core 2.2 和 signalR 1.1.0。

这里有几个问题需要解决:

1. simple js client without angular(does not work, code below)
2. It is assumed that the signalR sends messages in real time, but how can the Abp handle situations if the user is offline, or has been disconnected at the time of the sending notification? If there is no such functionality in ABP, what can I do about it?
3. Does the ABP have a mechanism to confirm receipt of a notification? Can I be sure that my message has been delivered?

客户端:安装 abp-web-resources 并获取 abp.signalr.js + abp.signalr-client.js Index.html 如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">    
    <title>Document</title>
</head>
<body>    
    <div id="inputForm">
        <p>Customer ABP client</p>
        <p>Message:</p>
        <input type="text" id="message" />
        <p>User:</p>
        <input type="text" id="user" />
        <input type="button" id="sendBtn" value="send" />       

    </div>
    <div id="chatroom"></div>
    <script   src="https://code.jquery.com/jquery-3.4.1.min.js"
              integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo="
              crossorigin="anonymous"></script>
    <script src="node_modules/abp-web-resources/Abp/Framework/scripts/libs/abp.signalr.js"></script>
    <script src="node_modules/abp-web-resources/Abp/Framework/scripts/libs/abp.signalr-client.js"></script>
    <script>
        let myUrl = "http://localhost:21021";               
        let hubUrl = "/chat";        
        let token = "Bearer here my token";         

        var chatHub = null;

        abp.signalr.startConnection(myUrl + hubUrl, function (connection) {
            chatHub = connection; 
            connection.on('Send', function (message, userName, connectionId, time) {            
                let userNameElem = document.createElement("b");
                userNameElem.appendChild(document.createTextNode(time +" "+userName+" ("+ connectionId +")"+ ' : '));

                let elem = document.createElement("p");
                elem.appendChild(userNameElem);
                elem.appendChild(document.createTextNode(message));

                let firstElem = document.getElementById("chatroom").firstChild;
                document.getElementById("chatroom").insertBefore(elem, firstElem);     
            }); 
        }).then(function (connection) {
            abp.log.debug('Connected to myChatHub server!');
            abp.event.trigger('myChatHub.connected');
        });

        abp.event.on('myChatHub.connected', function() { 
            chatHub.invoke('sendMessage', "Hi everybody, I'm connected to the chat!"); 
        });

        document.getElementById("sendBtn").addEventListener("click", function (e) {
            let message = document.getElementById("message").value;
            let userName = document.getElementById("user").value;           

            chatHub.invoke("Send", message, userName).catch(function (err) {
                return console.error(err.toString());
            });

            event.preventDefault();
        });
    </script>
</body>
</html>

在Startup.cs中的ConfigureServices方法中:

 services.AddSignalR();            
 services.AddCors(
    options => options.AddPolicy(
                    DefaultCorsPolicyName,
                    builder => builder                         
                        .AllowAnyHeader()
                        .AllowAnyMethod()
                        .AllowAnyOrigin() 
                        .AllowCredentials()
                ));

在配置中:

...
 app.UseAbp(options => { options.UseAbpRequestLocalization = false; });
 app.UseWebSockets();
 app.UseCors(DefaultCorsPolicyName); 
 app.UseStaticFiles();
 app.UseAuthentication();
 app.UseAbpRequestLocalization();

 app.UseSignalR(routes => { routes.MapHub<Test2Hub>("/chat"); });

app.UseMvc();
...

在AuthConfigurer中也会处理令牌并添加授权标头(我不写太多细节)。
我的建议:
namespace MyProjectName.Web.Host.MyHubs
{
    [Authorize]
    public class Test2Hub : AbpHubBase, ISingletonDependency //with trancient  
                                        //not working at all: Clients == null
    {
        private IAbpSession AbpSession { get; set; }        

        public Test2Hub( )            
        {
            AbpSession = NullAbpSession.Instance;            
        }

        public async Task Send(string msg, string userName)
        {
            await this.Clients.All.SendAsync("Send", msg, userName, Context.ConnectionId, "[" + Clock.Now + "]");
        }

        public async Task SendToUser(string msg, long userId)
        {
            if (this.Clients != null)
            {
                await Clients.User(userId.ToString()).SendAsync("Send", msg, "From Server by userID ",   Context.ConnectionId, Clock.Now);
            }
            else
            {
                throw new UserFriendlyException("smthng wrong");                
            }           
        }

        public async Task<HttpContext> GetContext()
        {
            return Context.GetHttpContext();
        }

        public override async Task OnConnectedAsync()
        {            
            await Clients.All.SendAsync("Send", $"{Context.UserIdentifier} enter into chat");
            await base.OnConnectedAsync();
        }

        public override async Task OnDisconnectedAsync(Exception exception)
        {            
            await Clients.All.SendAsync("Send", $"{Context.UserIdentifier} gone...");
            await base.OnDisconnectedAsync(exception);
        }        
    }
}

控制器:

 [Route("api/[controller]/[action]")]
    public class NotificationWebController : MyProjectControllerBase, IRealTimeNotifier
    {        
        private readonly Test2Hub _testHub;       
        private readonly INotificationPublisher _notificationPublisher;
        private readonly INotificationSubscriptionManager _notificationSubscriptionManager;
        private readonly IUserNotificationManager _notificationManager;

        public NotificationWebController
        (
            IUserNotificationManager notificationManager,
            INotificationPublisher notificationPublisher,
            INotificationSubscriptionManager notificationSubscriptionManager,
            Test2Hub testHub            
        )
        {
            _testHub = testHub;
            _notificationPublisher = notificationPublisher;
            _notificationSubscriptionManager = notificationSubscriptionManager;
            _notificationManager = notificationManager;
        }

        [HttpPost]
        public async Task SendToUserBySignalR(string msg, long userId)
        {                           
            await _testHub.SendToUser(msg, userId);            
        }

        [HttpGet]
        public async Task<HttpContext> GetContext()
        {            
            return await _testHub.GetContext();            
        }

         /*
            I also tried to use the Abp notification system,
 records in the database were created, but I could not transfer it to the client
        */        

        [HttpPost]
        public async Task Subscribe(int? tenantId, long userId)
        {
            await _notificationSubscriptionManager.SubscribeAsync(new UserIdentifier(tenantId, userId), "App.SimpleMessage");
        }

        [HttpPost]
        public async Task<ActionResult> TestNotificationAbp(string message, long userId)
        {    
            var identifier = new UserIdentifier(1, userId); //tenantId = 1
            await _notificationPublisher.PublishAsync(
                "App.SimpleMessage",
                new MessageNotificationData(message),
                severity: NotificationSeverity.Info,
                userIds: new[] { identifier }
            );

            return Content("Sent notification: " + message);
        }  

        [HttpPost]
        public async Task SendNotificationsAsync(UserNotification[] userNotifications)
        {
            //realization IRealTimeNotifier, but it is not clear how to use it...
           throw new NotImplementedException();
        }                
    }

客户端无法工作。错误信息:

abp.signalr-client.js:5 Uncaught ReferenceError: signalR is not defined
    at abp.signalr-client.js:5
    at abp.signalr-client.js:109
(anonymous) @ abp.signalr-client.js:5
(anonymous) @ abp.signalr-client.js:109
(index):38 Uncaught TypeError: Cannot read property 'startConnection' of undefined 

我做错了什么?我也希望能得到上述问题的答案。对于我的英语表示抱歉。

可能是 https://dev59.com/R2Eh5IYBdhLWcg3wpEtF 的重复问题。 - ryan.c
1个回答

1
<script src="node_modules/abp-web-resources/Abp/Framework/scripts/libs/abp.signalr.js"></script>
<script src="node_modules/abp-web-resources/Abp/Framework/scripts/libs/abp.signalr-client.js"></script>

ASP.NET Core

使用abp.signalr-client.js,其依赖于signalr.js。

<script src="node_modules/signalr/dist/browser/signalr.js"></script>
<script src="node_modules/abp-web-resources/Abp/Framework/scripts/libs/abp.signalr-client.js"></script>

参考资料:

ASP.NET MVC 5

使用abp.signalr.js,该库依赖于signalr/hubs。

<script src="signalr/hubs"></script>
<script src="node_modules/abp-web-resources/Abp/Framework/scripts/libs/abp.signalr-client.js"></script>

参考资料:


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接