A day with .Net

My day to day experince in .net

Archive for the ‘SignalR’ Category

SignalR Communication In Multiple Projects (Multiple Server Hubs) – Micro-services Architecture

Posted by vivekcek on December 15, 2018

I have an MVC web application that communicate to a back-end web API. The API is not exposed directly to public and resides inside a virtual network.
But I want to implement a SignalR connection between my front-end MVC and back end web api.
In this setup I have two SignalR clients and two SignalR servers.
The first SignalR client is a JavaScript client that communicate to the SignalR server in the MVC application.
The second SignalR client is a .NET SignalR client inside the MVC app that can connect to SignalR server in the API.

The setup works this way.
1.JavaScript client establish a connection with MVC SignalR server hub.
2.The MVC SiganlR server hub establish a connection with API server hub through the SignalR .NET client inside the MVC app.

This is my JavaScript Client.

"use strict";

var connection = new signalR.HubConnectionBuilder().withUrl("/mvcHub").build();

connection.on("ReceiveMessage", function (user, message) {
    var msg = message.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
    var encodedMsg = user + " says " + msg;
    var li = document.createElement("li");
    li.textContent = encodedMsg;
    document.getElementById("messagesList").appendChild(li);
});

connection.start().catch(function (err) {
    return console.error(err.toString());
});

document.getElementById("sendButton").addEventListener("click", function (event) {
    var user = document.getElementById("userInput").value;
    var message = document.getElementById("messageInput").value;
    connection.invoke("SendMessage", user, message).catch(function (err) {
        return console.error(err.toString());
    });
    event.preventDefault();
});

This is my MVC Server hub

using System.Threading.Tasks;
using Microsoft.AspNetCore.SignalR;
using Microsoft.AspNetCore.SignalR.Client;

namespace WebApplication2
{
    public class MvcHub:Hub
    {
        private readonly IHubContext<MvcHub> _hubContext;
        public MvcHub(IHubContext<MvcHub> hubContext)
        {
            _hubContext = hubContext;
        }
        public async Task SendMessage(string user, string message)
        {

            var connection = new HubConnectionBuilder()
                .WithUrl("http://localhost:50735/apiHub")
                .Build();
            connection.StartAsync().Wait();

            await connection.InvokeAsync("SendMessage",
                    "sadsd", "sdf");
            
            connection.On<string, string>("ReceiveMessage", (user1, message1) =>
            {
                _hubContext.Clients.All.SendAsync("ReceiveMessage", user1, message1);
            });
        }
    }
}

This is my API Server hub

using System.Threading.Tasks;
using Microsoft.AspNetCore.SignalR;
namespace WebApplication1
{    public class ApiHub : Hub
    {
        public async Task SendMessage(string user, string message)
        {
            await Clients.Caller.SendAsync("ReceiveMessage", user, message);
        }
    }
}

From inside your API controller you can route message to MVC UI via this code.

public class ValuesController : ControllerBase
    {
        private readonly IHubContext<ApiHub> _hubContext;
        public ValuesController(IHubContext<ApiHub> hubContext)
        {
            _hubContext = hubContext;

        }

        // GET api/values/5
        [HttpGet("{id}")]
        public ActionResult<string> Get(int id)
        {
            _hubContext.Clients.All.SendAsync("ReceiveMessage", "vivek", "asdad");
            return "value";
        }
    }

Posted in SignalR | Tagged: , , , | Leave a Comment »

File upload and usability – Upload by a single click

Posted by vivekcek on June 26, 2016

Today i was just filing my tax via HRBlock India, and the experience was good.As you know for filing tax, you should upload your Form 16 docs to Hrblock.
They provide the below screen for uploading each document.Here you need to select each document and click the upload button, that is 2 click per upload.

Can we change this to single click, No i think because we may need to provide password for each file, if present.
So this screen is valid.

1

In some other sites , i have seen you have to do 2 mouse click for an upload.Normally developers design a file upload like below, a file browse input and upload button.

3

So how we can save one click, with just a single button click.

4

For that you can use bootstrap and jquery.

First add this style to your page.

<style type="text/css">
    .btn-file {
        position: relative;
        overflow: hidden;
    }

        .btn-file input[type=file] {
            position: absolute;
            top: 0;
            right: 0;
            min-width: 100%;
            min-height: 100%;
            font-size: 100px;
            text-align: right;
            filter: alpha(opacity=0);
            opacity: 0;
            outline: none;
            background: white;
            cursor: inherit;
            display: block;
        }
</style>

Place your input control via below code snippet.

<span class="btn btn-default btn-file">
    Upload Files <input type="file">
</span>

Use the below script to upload.

@section scripts
{
    <script type="text/javascript">
        $(document).ready(function () {
            $(document).on('change', '.btn-file :file', function () {
                var input = $(this);
                var files = input.get(0).files;
                if (files.length > 0) {
                    var data = new FormData();
                    for (i = 0; i < files.length; i++) {
                        data.append("file" + i, files[i]);
                    }
                    input.trigger("onclick");//Please keep this to fire the change event next time
  
                    $.ajax({
                        type: "POST",
                        url: "",
                        contentType: false,
                        processData: false,
                        data: data,
                        global: false,
                        success: function (response) {

                        },
                        error: function () {

                        }
                    });

                }
            });

            $(document).on('onclick', '.btn-file :file', function () {
                this.value = null;
            });
        });
    </script>
}

Posted in Jquery, MVC, SignalR | Tagged: , , , , | Leave a Comment »

SignalR in Web Farm or Web Garden Enviornment

Posted by vivekcek on May 23, 2016

I was trying to use SignalR 2 for one of my project and successfully implemented a progress bar using it.
Everything was working fine in our test server also. But fortunately i tested this SignalR 2 based progress bar in Web-garden mode of IIS,
Woww surprised nothing is working. Thanks God, because our production servers are load balanced Web Farm.

Any way found solution in Microsoft documentation. I will discuss that below.

Hope you have an understanding of SignalR.

1. Create an MVC 5 app.

2. Add Nuget package for SignalR.

Install-Package Microsoft.AspNet.SignalR

3.Now Paste the below code in your cshtml.

<input type="button" value="Submit" id="btnSubmit" />
<input type="hidden" id="connectionid" />

<div id="uploadModal"></div>

@section scripts
{
    <!--Reference the SignalR library. -->
    <script src="~/Scripts/jquery.signalR-2.2.0.min.js"></script>
    <!--Reference the autogenerated SignalR hub script. -->
    <script src="~/signalr/hubs"></script>
    <script type="text/javascript">

        $(document).ready(function() {
            var con = $.connection.uploaderHub;
            $.connection.hub.start().done(function() {
                $("#connectionid").val($.connection.hub.id);

            }).fail(function(e) {
                alert('There was an error');
                console.error(e);
            });
            con.client.print = function() {
                $("#uploadModal").append("Vivek");
            };

            $("#btnSubmit").click(function() {

                var connectionid = $("#connectionid").val();
                var url = '@Url.Action("Test", "Home")';
                url = url + '?connectionid=' + connectionid;
                $.ajax({
                    type: "POST",
                    url: url,
                    dataType: 'json',
                    contentType: "application/json; charset=utf-8",
                    success: function(messages) {

                    },
                    error: function() {

                    }
                });

            });

        });
    </script>
}

4. Now create an action in your controller.

        [HttpPost]
        public ActionResult Test(string connectionid)
        {
            var hubContext = GlobalHost.ConnectionManager.GetHubContext<UploaderHub>();
            hubContext.Clients.Client(connectionid).print();
            return Json(new { Success = "True" });
        }

5. Create a SignalR hub.

using Microsoft.AspNet.SignalR;

namespace SignalR.Controllers
{
    public  class UploaderHub:Hub
    {

    }
}

6. In your OWIN Startup.cs add the code below.

using Microsoft.Owin;
using Owin;

[assembly: OwinStartupAttribute(typeof(SignalR.Startup))]
namespace SignalR
{
    public partial class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.MapSignalR();
            ConfigureAuth(app);
        }
    }
}

Deploy this to IIS and click submit button, Which will print the text defined in client side print method.

Now increase the worker process count in your application pool to 5, Also set processor affinity true.
Try the same after some refresh, You will found the messaging is not working.

1

To Solve this you can use another SignalR package for SQL Server

Install-Package Microsoft.AspNet.SignalR.SqlServer -Version 2.2.0

Then update your OWIN Startup.cs add this.

using Microsoft.AspNet.SignalR;
using Microsoft.Owin;
using Owin;

[assembly: OwinStartupAttribute(typeof(SignalR.Startup))]
namespace SignalR
{
    public partial class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            string sqlConnectionString = "Connecton string to your SQL DB";
            GlobalHost.DependencyResolver.UseSqlServer(sqlConnectionString);
            app.MapSignalR();
            ConfigureAuth(app);
        }
    }
}

Which will create some tables, in the database you specified in your connection string.
And now debug…

Posted in AJAX, MVC, SignalR | Tagged: , , , | 2 Comments »

Real-time progress bar using JQuery UI and SignalR

Posted by vivekcek on December 26, 2012

So your web application do some long running process, like calling some 10 web services and consolidate information and display to user.In such scenarios it is a best practice to show a progress bar to the user, that display how much processing is finished or how much percentage completed.

Why SignalR?

SignalR can be used to avoid continuous polling to the server by client to know about the status of work.
SignalR can initiate call from the server to client after some operation is finished.

Other things you can learn from this post

1. Call SignalR hub method on page load
2. Redirect to another page from SignalR hub method.
3. Access the query string through java-script.

Example Idea

An application that post a status update to social medias like Facebook,twitter etc through single window.

6

Quick to code

1. I recommend Visual Studio 2012, because the web site template project include jquery and jquery ui pre installed.

2. Create a new website (not web application project)

1

3. Use Nuget Package Manager and install SignalR as shown below

2

4. Install Json2.js using Nuget as shown below.

3

5. Check the script folder and ensure all script files shown in below picture are present.

4

6. Ensure CSS for Jquery Ui is present in Content folder.

5

7. Create 3 WebForm’s Default.aspx, Progress.aspx and Result.aspx

8. In Default.aspx add a button. In the click event add below code.

 protected void Button1_Click(object sender, EventArgs e)
    {
        Response.Redirect("Progress.aspx?message=hai");
    }

9. In App_Code folder add a class named Social. This class perform a virtual log running process. This class contain a hub method named ‘postStatus(string message)’.We will call this method in the Progress.aspx page load.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Threading;
using SignalR;
using SignalR.Hubs;
/// <summary>
/// Summary description for Server
/// </summary>
namespace SignalR
{
    [HubName("social")]
    public class Social : Hub
    {

        public void postStatus(string message)
        {

           
            Caller.updateGaugeBar(10);
            Caller.displayMessage(String.Format("Posted to: {0} ...", "Facebook.com"));
            Thread.Sleep(2000);

            
            Caller.updateGaugeBar(40);
            Caller.displayMessage(String.Format("Posted to:: {0} ...", "googleplus.com"));
            Thread.Sleep(3000);

            
            Caller.updateGaugeBar(64);
            Caller.displayMessage(String.Format("Posted to:: {0} ...", "Twitter.com"));
            Thread.Sleep(2000);

            Caller.updateGaugeBar(77);
            Caller.displayMessage(String.Format("Posted to:: {0} ...", "Diggit.com"));
            Thread.Sleep(2000);

            Caller.updateGaugeBar(92);
            Caller.displayMessage(String.Format("Posted to:: {0} ...", "blogger.com"));
            Thread.Sleep(2000);

            Caller.displayMessage(String.Format("Processing Result"));
            Caller.updateGaugeBar(100);
            Thread.Sleep(2000);
            
            Caller.redirectMe("Result.aspx");
        }


    }
}

10. Add the below code in HTML of Progress.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Progress.aspx.cs" Inherits="Progress" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <link href="Content/themes/base/jquery-ui.css" rel="stylesheet" type="text/css" />
    <script src="Scripts/jquery-1.7.1.js" type="text/javascript"></script>
    <script src="Scripts/jquery-ui-1.8.20.js" type="text/javascript"></script>
    <script src="Scripts/json2.js" type="text/javascript"></script>
    <script src="Scripts/jquery.signalR-0.5.3.js" type="text/javascript"></script>
    <script type="text/javascript" src='<%= ResolveClientUrl("~/signalr/hubs") %>'></script>
    

    <script type="text/javascript">

        var proxy = $.connection.social;
        proxy.displayMessage = function (message) {
            $("#msg").html(message);
        };

        proxy.redirectMe = function (target) {
            var url = target;
            location.href = '<%= Page.ResolveUrl("'+url+'") %>';
        };

        proxy.updateGaugeBar = function (perc) {
            $("#bar").progressbar({value:perc})
        };

        $.connection.hub.start().done(function () {
            var msg = querySt("message");
            proxy.postStatus(msg);
        });

        function querySt(Key) {
            var url = window.location.href;
            KeysValues = url.split(/[\?&]+/);
            for (i = 0; i < KeysValues.length; i++) {
                KeyValue = KeysValues[i].split("=");
                if (KeyValue[0] == Key) {
                    return KeyValue[1];
                }
            }
        }


    </script>
</head>
<body>
    <form id="form1" runat="server">
     <div>
            <b>Status:</b>&nbsp;&nbsp;&nbsp;<span id="msg"></span>
        </div>
        <div id="bar"></div>
    </form>
</body>
</html>

Posted in SignalR | Tagged: , , , | Leave a Comment »

Append rows to table using SignalR,Jquery and ASP.NET

Posted by vivekcek on October 25, 2012

1. Create an ASP.NET website project in VS2012.

2. Use the Nuget package manager to add SignalR.

3. Create a class named signal in App_Code.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using SignalR;
using SignalR.Hubs;
/// <summary>
/// Summary description for signal
/// </summary>
[HubName("signals")]
public class signal:Hub
{
    public void GetList()
    {
        Employee emp = new Employee();
        emp.ID = "1";
        emp.Name = "Vivek";
        Address adrs = new Address();
        adrs.Value = "poomala";
        emp.Address = adrs;
        List<Employee> emps = new List<Employee>();
        emps.Add(emp);
        Caller.PostReslt(emps);
        System.Threading.Thread.Sleep(2000);

        emp = new Employee();
        emp.ID = "2";
        emp.Name = "chanthu";
        adrs = new Address();
        adrs.Value = "poomala";
        emp.Address = adrs;

        emps = new List<Employee>();
        emps.Add(emp);
        Caller.PostReslt(emps);
    }
    
    public class Employee
    {
        public string ID;
        public string Name;
        public Address Address;
    }
    public class Address
    {
        public string Value;
    }
}

4. Add a Webform named Default.aspx and paste the below code.

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <script src="Scripts/jquery-1.7.2.js" type="text/javascript"></script>
    <script src="Scripts/jquery.signalR-0.5.3.min.js" type="text/javascript"></script>
    <script src="<%=ResolveClientUrl("~/signalr/hubs") %>"></script>
    <script type="text/javascript">
        $(function () {
            var proxy = $.connection.signals;

            proxy.PostReslt = function (data) {

                for (i = 0; i < data.length;i++)
                {
                    var tbl = $('#tbl');
                    var row = $('<tr></tr>');
                    var col = $('<td></td>').text(data[i].ID)
                    var col1 = $('<td></td>').text(data[i].Name)
                    var col3 = $('<td></td>').text(data[i].Address.Value)
                    row.append(col);
                    row.append(col1);
                    row.append(col3);
                    tbl.append(row);
                }
               
            };

            $.connection.hub.start();

            $('#btn').click(

                function () {

                    proxy.getList();
                }
                );
        }
        );
    </script>
</head>
<body>
    <form id="form1" runat="server">
        <div>
        </div>
        <input type="button" id="btn" value="Send"/>
        <table id="tbl">
            <thead>
                <tr>
                    <th>ID</th>
                    <th>Name</th>
                    <th>Address</th>
                </tr>
            </thead>
            <tbody></tbody>
        </table>
    </form>
</body>
</html>

Posted in SignalR | Tagged: , , | Leave a Comment »