locked
Signal R with multiple Websites RRS feed

  • Question

  • User-1078128378 posted

    Hi All,

    I have 2 websites and both websites points to same database.

    For example , App1 and App2

    now I have 2 users( user A,user B).

    Now User A(From App1) has send Notification message to user B.(But User B has logged in Both App1 and App2)

    I can able to send message either App1 or App2 only.i cant able to send message to 2 website at a same time.

    My Code:

    <!DOCTYPE html>
    
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
    
    
    <script src="Scripts/jquery-1.10.2.min.js"></script>
    <script src="Scripts/jquery.signalR-2.2.0.min.js"></script>
    <script src="/signalr/hubs"></script>
    <script>
    $(function () {
        Domain2();
        Domain1();
    
    });
    
    
    function Domain1() {
    
        $.connection.hub.url = "http://localhost/App1/signalr";
        $.hubConnection("http://localhost/App1/signalr", { useDefaultPath: false });
        var chat = $.connection.chatHub;
           
        chat.client.notify = function (message) {
            // updateSessionData(message);
            var encodedName = $('<div />').text(message.sender).html();
            var encodedMsg = $('<div />').text(message.message).html();
            // Add the message to the page.
            $('#discussion').append('<li><strong>' + encodedName
                + '</strong>:&nbsp;&nbsp;' + encodedMsg + '</li>');
        };
        $.connection.hub.start();
       
    }
    function Domain2() {
        $.connection.hub.url = "http://localhost/App2/signalr";
        $.hubConnection("http://localhost/App2/signalr", { useDefaultPath: false });
        var chat = $.connection.chatHub;
           
        chat.client.notify = function (message) {
            // updateSessionData(message);
            var encodedName = $('<div />').text(message.sender).html();
            var encodedMsg = $('<div />').text(message.message).html();
            // Add the message to the page.
            $('#discussion').append('<li><strong>' + encodedName
                + '</strong>:&nbsp;&nbsp;' + encodedMsg + '</li>');
        };
        $.connection.hub.start();
    }
    
    function sendNotifyMessage(message, toAddress) {
        sendNotifyMessage1(message, toAddress);
        sendNotifyMessage2(message, toAddress);
    }
    
    function sendNotifyMessage1(message, toAddress) {
        $.connection.hub.url = "http://localhost/App1/signalr";
        $.hubConnection("http://localhost/App1/signalr", {
            useDefaultPath: false
        });
        var chat = $.connection.chatHub;
        
        $.connection.hub.start().done(function () {
            chat.server.notificationSend(message, toAddress);
        });
    }
    
    function sendNotifyMessage2(message, toAddress) {
        $.connection.hub.url = "http://localhost/App2/signalr";
        $.hubConnection("http://localhost/App2/signalr", {
            useDefaultPath: false
        });
        var chat = $.connection.chatHub;
        $.connection.hub.start().done(function () {
            chat.server.notificationSend(message, toAddress);
        });
    }
    function sendData() {
                var toAddr = $("#<%= txtUser.ClientID %>").val();
                var msg = $("#<%= txtMessage.ClientID %>").val();
                sendNotifyMessage(msg, toAddr);
                return false;
            }
    
    </script>
    </head>
    <body>
        <form id="form1" runat="server">
    <asp:TextBox ID="txtUser" runat="server" PlaceHolder="Other User Name"></asp:TextBox>
        <br />
        <asp:TextBox ID="txtMessage" runat="server" PlaceHolder="Message"></asp:TextBox>
    
        <br />
        <asp:Button ID="Button3" runat="server" Text="Send Message" OnClientClick="sendData()" />
      
        <br />
    </form>
    </body>
    </html>

    Chathub.cs

    using Microsoft.AspNet.SignalR;
    using System;
    using System.Collections.Concurrent;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Web;
    
    /// <summary>
    /// Summary description for ChatHub
    /// </summary>
    public class ChatHub : Hub
    {
        private static readonly ConcurrentDictionary<string, ChatHubUser> Users =
           new ConcurrentDictionary<string, ChatHubUser>(StringComparer.InvariantCultureIgnoreCase);
    
        public void NotificationSend(string message, string to)
        {
            ChatHubUser receiver;
            if (Users.TryGetValue(to, out receiver))
            {
                ChatHubUser sender = GetUser(Context.User.Identity.Name);
                IEnumerable<string> allReceivers;
                lock (receiver.ConnectionIds)
                {
                    lock (sender.ConnectionIds)
                    {
                        //allReceivers = receiver.ConnectionIds.Concat(sender.ConnectionIds);
                        allReceivers = receiver.ConnectionIds;
                    }
                }
    
                foreach (var cid in allReceivers)
                {
                    Clients.Client(cid).notify(new { sender = sender.Name, message = message, isPrivate = true });
                }
            }
        }
    
        
    
        #region Connect and Disconnect
        public override Task OnConnected()
        {
            string userName = Context.User.Identity.Name;
            string connectionId = Context.ConnectionId;
            string groupName = "g1";
    
            var user = Users.GetOrAdd(userName, _ => new ChatHubUser
            {
                Name = userName,
                ConnectionIds = new HashSet<string>(),
                Group = groupName
            });
    
            lock (user.ConnectionIds)
            {
                user.ConnectionIds.Add(connectionId);
            }
    
            if (!string.IsNullOrEmpty(groupName))
            {
                foreach (var conId in user.ConnectionIds)
                {
                    this.Groups.Add(conId, groupName);
                }
            }
    
            return base.OnConnected();
        }
    
        public override Task OnDisconnected(bool stopCalled = false)
        {
    
            string userName = Context.User.Identity.Name;
            string connectionId = Context.ConnectionId;
    
            ChatHubUser user;
            Users.TryGetValue(userName, out user);
    
            if (user != null)
            {
                lock (user.ConnectionIds)
                {
                    user.ConnectionIds.RemoveWhere(cid => cid.Equals(connectionId));
                    if (!user.ConnectionIds.Any())
                    {
                        ChatHubUser removedUser;
                        Users.TryRemove(userName, out removedUser);
    
                        // You might want to only broadcast this info if this 
                        // is the last connection of the user and the user actual is 
                        // now disconnected from all connections.
                        Clients.Others.userDisconnected(userName);
                    }
                }
            }
    
            return base.OnDisconnected(stopCalled);
        }
        #endregion
    
        #region Helper Methods
        private ChatHubUser GetUser(string username)
        {
            ChatHubUser user;
            Users.TryGetValue(username, out user);
            return user;
        }
        #endregion
    }
    
    public class ChatHubUser
    {
        public string Name { get; set; }
        public HashSet<string> ConnectionIds { get; set; }
        public string Group { get; set; }
    }

    Owin.Startup

    using Microsoft.AspNet.SignalR;
    using Microsoft.Owin;
    using Microsoft.Owin.Cors;
    using Owin;
    
    [assembly: OwinStartup(typeof(Startup))]
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
    
            app.Map("/signalr", map =>
            {
                
                map.UseCors(CorsOptions.AllowAll);
                var hubConfiguration = new HubConfiguration
                {
                    
                };
               map.RunSignalR(hubConfiguration);
            });
        }
    }

    In document.load i am calling like below

    Domain2(); // for app2

    Domain1(); //for app1

    which connection i called at last always notification going to that connection in my current example always notification going to app1 because my last connection is connected to app1.

    if i change javascript like Domain1();  after that Domain2(); now when i send message always it is going to App2 Login User only.

    but i need to send both App1 user B and App2 User B.

    any one please help to reslove this issue.

    Monday, June 17, 2019 11:32 AM

Answers

  • User61956409 posted

    Hi Murali Krishna,

    If you want that your Hub can be connected from two JavaScript Client Apps (App1 and App2) and make these two Apps can exchange message via your Hub, you can refer to the following approach and example.

    Create Hub Class and JavaScript Client App (in App1 project)

    ChatHub Class

    public class ChatHub : Hub
    {
        public void Send(string name, string message)
        {
            Clients.All.broadcastMessage(name, $"{message}");
        }
    }

    JavaScript Client App

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8" />
        <title>SignalR Simple Chat</title>
        <style type="text/css">
            .container {
                background-color: #99CCFF;
                border: thick solid #808080;
                padding: 20px;
                margin: 20px;
            }
        </style>
        <script src="Scripts/jquery-1.6.4.min.js"></script>
        <script src="Scripts/jquery.signalR-2.4.0.min.js"></script>
        <!--Reference the autogenerated SignalR hub script. -->
        <script src="signalr/hubs"></script>
    
        <script type="text/javascript">
            $(function () {
                // Declare a proxy to reference the hub.
                var chat = $.connection.chatHub;
                // Create a function that the hub can call to broadcast messages.
                chat.client.broadcastMessage = function (name, message) {
                    // Html encode display name and message.
                    var encodedName = $('<div />').text(name).html();
                    var encodedMsg = $('<div />').text(message).html();
                    // Add the message to the page.
                    $('#discussion').append('<li><strong>' + encodedName
                        + '</strong>:&nbsp;&nbsp;' + encodedMsg + '</li>');
                };
                // Get the user name and store it to prepend to messages.
                $('#displayname').val(prompt('Enter your name:', ''));
                // Set initial focus to message input box.
                $('#message').focus();
                // Start the connection.
                $.connection.hub.start().done(function () {
                    $('#sendmessage').click(function () {
                        // Call the Send method on the hub.
                        chat.server.send($('#displayname').val(), $('#message').val() +" (sent from App1)");
                        // Clear text box and reset focus for next comment.
                        $('#message').val('').focus();
                    });
                });
            });
        </script>

    Enable CORS as you did (in App1 project)

    app.Map("/signalr", map =>
    {
        map.UseCors(CorsOptions.AllowAll);
    
        var hubConfiguration = new HubConfiguration
        {
            //EnableJSONP = true
        };
    
        map.RunSignalR(hubConfiguration);
    });

    Create Web App (as App2), and connect to a different hub server

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8" />
        <title></title>
        <style type="text/css">
            .container {
                background-color: #99CCFF;
                border: thick solid #808080;
                padding: 20px;
                margin: 20px;
            }
        </style>
        <script src="Scripts/jquery-1.6.4.min.js"></script>
        <script src="Scripts/jquery.signalR-2.4.0.min.js"></script>

    <!-- replace following reference based on your hub hosting server --> <script src="http://localhost:53227/signalr/hubs"></script> </head> <body> <div class="container"> <input type="text" id="message" /> <input type="button" id="sendmessage" value="Send" /> <input type="hidden" id="displayname" /> <ul id="discussion"></ul> </div> </body> </html> <script> $(function () {
    //specify the URL based on your hub hosting server $.connection.hub.url = 'http://localhost:53227/signalr'; var chat = $.connection.chatHub; chat.client.broadcastMessage = function (name, message) { console.log(name + ' ' + message); // Html encode display name and message. var encodedName = $('<div />').text(name).html(); var encodedMsg = $('<div />').text(message).html(); // Add the message to the page. $('#discussion').append('<li><strong>' + encodedName + '</strong>:&nbsp;&nbsp;' + encodedMsg + '</li>'); }; $('#displayname').val(prompt('Enter your name:', '')); // Set initial focus to message input box. $('#message').focus(); $.connection.hub.start().done(function () { $('#sendmessage').click(function () { // Call the Send method on the hub. chat.server.send($('#displayname').val(), $('#message').val() + " (sent from App2)"); // Clear text box and reset focus for next comment. $('#message').val('').focus(); }); }); }) </script>

    Test Result:

    With Regards,

    Fei Han

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Tuesday, June 18, 2019 7:53 AM
  • User61956409 posted

    Hi Murali Krishna,

    Hi Fei Han,

    Thanks for the answer.

    this is what i am looking . it is resolved my issue  thanks again.

    Glad to hear that the reply with example I shared did help resolved the problem.

    i have another question if i have another websites like app3, app4 along with app1 and app2 then what is the approach to send message to all websites.

    You can implement same in app3, app4 etc like we did in app2, these client Apps (websites) connect to same hub, so connected users from different client Apps (websites) should be able to exchange message between each other. 

    Besides, you can [create a physical file for the SignalR generated proxy](https://docs.microsoft.com/en-us/aspnet/signalr/overview/guide-to-the-api/hubs-api-guide-javascript-client#manualproxy), then add a reference to it in place of the "signalr/hubs" reference in your web page of your websites.

    For example:

    In JavaScript Client of App2, App3 or App4 etc

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8" />
        <title></title>
        <style type="text/css">
            .container {
                background-color: #99CCFF;
                border: thick solid #808080;
                padding: 20px;
                margin: 20px;
            }
        </style>
        <script src="Scripts/jquery-1.6.4.min.js"></script>
        <script src="Scripts/jquery.signalR-2.4.0.min.js"></script>
    
        <script src="Scripts/server.js"></script>
    </head>
    <body>
        <div class="container">
            <input type="text" id="message" />
            <input type="button" id="sendmessage" value="Send" />
            <input type="hidden" id="displayname" />
            <ul id="discussion"></ul>
        </div>
    </body>
    </html>
    <script>
        $(function () {
            //specify the URL based on your hub hosting server
            $.connection.hub.url = 'http://localhost:53227/signalr';
    
            var chat = $.connection.chatHub;
            chat.client.broadcastMessage = function (name, message) {
                console.log(name + ' ' + message);
                // Html encode display name and message.
                var encodedName = $('<div />').text(name).html();
                var encodedMsg = $('<div />').text(message).html();
                // Add the message to the page.
                $('#discussion').append('<li><strong>' + encodedName
                    + '</strong>:&nbsp;&nbsp;' + encodedMsg + '</li>');
            };
            $('#displayname').val(prompt('Enter your name:', ''));
            // Set initial focus to message input box.
            $('#message').focus();
    
            $.connection.hub.start().done(function () {
                $('#sendmessage').click(function () {
                    // Call the Send method on the hub.
                    chat.server.send($('#displayname').val(), $('#message').val() + " (sent from App2)");
                    // Clear text box and reset focus for next comment.
                    $('#message').val('').focus();
                });
            });
        })
    </script>

    Test Result:

    With Regards,

    Fei Han

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Wednesday, June 19, 2019 7:49 AM

All replies

  • User61956409 posted

    Hi Murali Krishna,

    If you want that your Hub can be connected from two JavaScript Client Apps (App1 and App2) and make these two Apps can exchange message via your Hub, you can refer to the following approach and example.

    Create Hub Class and JavaScript Client App (in App1 project)

    ChatHub Class

    public class ChatHub : Hub
    {
        public void Send(string name, string message)
        {
            Clients.All.broadcastMessage(name, $"{message}");
        }
    }

    JavaScript Client App

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8" />
        <title>SignalR Simple Chat</title>
        <style type="text/css">
            .container {
                background-color: #99CCFF;
                border: thick solid #808080;
                padding: 20px;
                margin: 20px;
            }
        </style>
        <script src="Scripts/jquery-1.6.4.min.js"></script>
        <script src="Scripts/jquery.signalR-2.4.0.min.js"></script>
        <!--Reference the autogenerated SignalR hub script. -->
        <script src="signalr/hubs"></script>
    
        <script type="text/javascript">
            $(function () {
                // Declare a proxy to reference the hub.
                var chat = $.connection.chatHub;
                // Create a function that the hub can call to broadcast messages.
                chat.client.broadcastMessage = function (name, message) {
                    // Html encode display name and message.
                    var encodedName = $('<div />').text(name).html();
                    var encodedMsg = $('<div />').text(message).html();
                    // Add the message to the page.
                    $('#discussion').append('<li><strong>' + encodedName
                        + '</strong>:&nbsp;&nbsp;' + encodedMsg + '</li>');
                };
                // Get the user name and store it to prepend to messages.
                $('#displayname').val(prompt('Enter your name:', ''));
                // Set initial focus to message input box.
                $('#message').focus();
                // Start the connection.
                $.connection.hub.start().done(function () {
                    $('#sendmessage').click(function () {
                        // Call the Send method on the hub.
                        chat.server.send($('#displayname').val(), $('#message').val() +" (sent from App1)");
                        // Clear text box and reset focus for next comment.
                        $('#message').val('').focus();
                    });
                });
            });
        </script>

    Enable CORS as you did (in App1 project)

    app.Map("/signalr", map =>
    {
        map.UseCors(CorsOptions.AllowAll);
    
        var hubConfiguration = new HubConfiguration
        {
            //EnableJSONP = true
        };
    
        map.RunSignalR(hubConfiguration);
    });

    Create Web App (as App2), and connect to a different hub server

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8" />
        <title></title>
        <style type="text/css">
            .container {
                background-color: #99CCFF;
                border: thick solid #808080;
                padding: 20px;
                margin: 20px;
            }
        </style>
        <script src="Scripts/jquery-1.6.4.min.js"></script>
        <script src="Scripts/jquery.signalR-2.4.0.min.js"></script>

    <!-- replace following reference based on your hub hosting server --> <script src="http://localhost:53227/signalr/hubs"></script> </head> <body> <div class="container"> <input type="text" id="message" /> <input type="button" id="sendmessage" value="Send" /> <input type="hidden" id="displayname" /> <ul id="discussion"></ul> </div> </body> </html> <script> $(function () {
    //specify the URL based on your hub hosting server $.connection.hub.url = 'http://localhost:53227/signalr'; var chat = $.connection.chatHub; chat.client.broadcastMessage = function (name, message) { console.log(name + ' ' + message); // Html encode display name and message. var encodedName = $('<div />').text(name).html(); var encodedMsg = $('<div />').text(message).html(); // Add the message to the page. $('#discussion').append('<li><strong>' + encodedName + '</strong>:&nbsp;&nbsp;' + encodedMsg + '</li>'); }; $('#displayname').val(prompt('Enter your name:', '')); // Set initial focus to message input box. $('#message').focus(); $.connection.hub.start().done(function () { $('#sendmessage').click(function () { // Call the Send method on the hub. chat.server.send($('#displayname').val(), $('#message').val() + " (sent from App2)"); // Clear text box and reset focus for next comment. $('#message').val('').focus(); }); }); }) </script>

    Test Result:

    With Regards,

    Fei Han

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Tuesday, June 18, 2019 7:53 AM
  • User-1204637165 posted

    Hello Fei Han,

    I love your approach to solving this question. But If I may ask. This means that the HUB would be hosted independently has a seperate server and both website would connect to it via the client javascript of signalr.

    Hope I am correct ?

    Tuesday, June 18, 2019 8:59 AM
  • User61956409 posted

    Hi InspiredJide,

    This means that the HUB would be hosted independently has a seperate server and both website would connect to it via the client javascript of signalr.

    Hope I am correct ?

    Yes, we can host Hub independently, and let different Client Applictaions (websites) to connect it.

    With Regards,

    Fei Han

    Tuesday, June 18, 2019 9:28 AM
  • User-1078128378 posted

    Hi Fei Han,

    Thanks for the answer.

    this is what i am looking . it is resolved my issue  thanks again.

    and i have another question if i have another websites like app3, app4 along with app1 and app2 then what is the approach to send message to all websites.

    because in my production we have multiple domains like mydomain.com, staff.mydomain.com, orders.mydomain.com, support.mydomain.com,

    user can send message from any website i need to send notification to all websites.

    Wednesday, June 19, 2019 6:54 AM
  • User61956409 posted

    Hi Murali Krishna,

    Hi Fei Han,

    Thanks for the answer.

    this is what i am looking . it is resolved my issue  thanks again.

    Glad to hear that the reply with example I shared did help resolved the problem.

    i have another question if i have another websites like app3, app4 along with app1 and app2 then what is the approach to send message to all websites.

    You can implement same in app3, app4 etc like we did in app2, these client Apps (websites) connect to same hub, so connected users from different client Apps (websites) should be able to exchange message between each other. 

    Besides, you can [create a physical file for the SignalR generated proxy](https://docs.microsoft.com/en-us/aspnet/signalr/overview/guide-to-the-api/hubs-api-guide-javascript-client#manualproxy), then add a reference to it in place of the "signalr/hubs" reference in your web page of your websites.

    For example:

    In JavaScript Client of App2, App3 or App4 etc

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8" />
        <title></title>
        <style type="text/css">
            .container {
                background-color: #99CCFF;
                border: thick solid #808080;
                padding: 20px;
                margin: 20px;
            }
        </style>
        <script src="Scripts/jquery-1.6.4.min.js"></script>
        <script src="Scripts/jquery.signalR-2.4.0.min.js"></script>
    
        <script src="Scripts/server.js"></script>
    </head>
    <body>
        <div class="container">
            <input type="text" id="message" />
            <input type="button" id="sendmessage" value="Send" />
            <input type="hidden" id="displayname" />
            <ul id="discussion"></ul>
        </div>
    </body>
    </html>
    <script>
        $(function () {
            //specify the URL based on your hub hosting server
            $.connection.hub.url = 'http://localhost:53227/signalr';
    
            var chat = $.connection.chatHub;
            chat.client.broadcastMessage = function (name, message) {
                console.log(name + ' ' + message);
                // Html encode display name and message.
                var encodedName = $('<div />').text(name).html();
                var encodedMsg = $('<div />').text(message).html();
                // Add the message to the page.
                $('#discussion').append('<li><strong>' + encodedName
                    + '</strong>:&nbsp;&nbsp;' + encodedMsg + '</li>');
            };
            $('#displayname').val(prompt('Enter your name:', ''));
            // Set initial focus to message input box.
            $('#message').focus();
    
            $.connection.hub.start().done(function () {
                $('#sendmessage').click(function () {
                    // Call the Send method on the hub.
                    chat.server.send($('#displayname').val(), $('#message').val() + " (sent from App2)");
                    // Clear text box and reset focus for next comment.
                    $('#message').val('').focus();
                });
            });
        })
    </script>

    Test Result:

    With Regards,

    Fei Han

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Wednesday, June 19, 2019 7:49 AM
  • User-1078128378 posted

    Hi Fei Han,


    Thank you so much.

    and i have 2 more last doubts.

    1.if i want to pass any data to singal r hub like userid,user roleId etc then i am passing with the help of query string only.

    For example

     var hv = $('#ctl00_hdnUser').val();
     var chat = $.connection.chatHub;
    $.connection.hub.qs = 'user=' + hv;

    is there any other way (without using query string) to pass data to hub. because by using query string data is showing in Network calls.

    2.how can i call server hub method from c# code behind?

    for example in my above example i have method called NotificationSend in the Hub class?

    is it possible to call hub method from any server side event like button click?

    if it is possible then message will send to all apps(app1,app2,app3) from single button click

    Wednesday, June 19, 2019 9:49 AM
  • User-1204637165 posted

    Same approach @murali.

    Make signalr standalone as an independent application.

    Then allow all your independent website to call the client library.

    Send a public message and all the website would see the message.

    Look at the code that the Fei Han wrote.

    It would help.

    Wednesday, June 19, 2019 4:05 PM