Arjun Arora
Arjun Arora

Reputation: 1006

SignalR2 not working in MVC5 using SqlDependency

I am hesitating while posting this question, as there are number of answers available on net for same But my bad luck, nothing is helping me out. For my web application i need notification part and for that i thought using SignalR 2 in same.

But its not working. Below is the complete code parts:

==>Hub Class

[HubName("MyHub")]
public class MyHub : Hub
{
    public static void Show()
    {
        IHubContext context = GlobalHost.ConnectionManager.GetHubContext<MyHub>();
        context.Clients.All.displayStatus();
    }
}

==>Global File

public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        SqlDependency.Start(ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString);
        AreaRegistration.RegisterAllAreas();
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);
    }

    protected void Application_End()
    {
        SqlDependency.Stop(ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString);
    }
}

==>Repository

public class DAL
{
    public List<DTO.Employee> GetEmployee()
    {
        List<DTO.Employee> l = new List<DTO.Employee>();
        try
        {
            using (var con = new SqlConnection(ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString))
            {
                con.Open();
                using (var cmd = new SqlCommand("select * from employee", con))
                {
                    cmd.Notification = null;
                    SqlDependency dep = new SqlDependency(cmd);
                    dep.OnChange += new OnChangeEventHandler(Dep_OnChange);

                    using (var drd = cmd.ExecuteReader())
                    {
                        while (drd.Read())
                        {
                            l.Add(new DTO.Employee()
                            {
                                Id = Convert.ToInt64(drd["id"]),
                                Name = Convert.ToString(drd["name"])
                            });
                        }
                    }
                }
            }
        }
        catch { }
        return l;
    }

    private void Dep_OnChange(object sender, SqlNotificationEventArgs e)
    {
        if (e.Type == SqlNotificationType.Change)
        {
            MyHub.Show();
        }
    }
}

==> Owin Startup Class

[assembly: OwinStartupAttribute(typeof(SignalR2_App1.Startup))]

namespace SignalR2_App1 { public partial class Startup { public void Configuration(IAppBuilder app) { app.MapSignalR(); } } }

==> View

<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 type="text/javascript">
    $(function () {
        var job = $.connection.MyHub;
        job.client.displayStatus = function () {
            getData();
        }
        $.connection.hub.start();
        getData();
    })
    function getData() {
        $.ajax({
            url: "/data/getdata",
            contentType: "application/json charset=utf-8",
            dataType: "json",
            type: "Post",
            success: function (result) {
                $.each(result, function (e, obj) {
                    $("#tbldata_tbody").append("<tr><td>" + obj.Id + "</td><td>" + obj.Name + "</td></tr>")
                })
            },
            error: function () {
                alert("Error");
            }
        })
    }
</script>
<body>
<table id="tbldata">
    <thead>
        <tr>
            <td>Id</td>
            <td>Name</td>
        </tr>
    </thead>
    <tbody id="tbldata_tbody"></tbody>
</table>

==>Action

[HttpPost]
    public JsonResult GetData()
    {
        DAL.DAL O = new DAL.DAL();
        return Json(O.GetEmployee());
    }

You can download the whole code from below link:
Code Link

Upvotes: 1

Views: 551

Answers (1)

Stephu
Stephu

Reputation: 3334

According your code I think that you do not understand all details of signalr. Here are some hints:

1. Inside your hub you do not need GlobalHost.ConnectionsManager

Inside the hub you have already a Clients property

2. Do not create an instance of you hub by yourself!

Inside you DAL you should not call

  MyHub.Show();

Instead grap HubContext:

GlobalHost.ConnectionManager.GetHubContext<MyHub>().Clients.All.displayStatus();

Better approach - Use Strongly-Types-Hubs:

According your code I think that you do not understand all details of signalr. I suggest you to read https://learn.microsoft.com/en-us/aspnet/signalr/overview/guide-to-the-api/hubs-api-guide-server

For example on the hub you should only define the methods which the clients can call on the server. For proper definition of the methods which the server can call on the clients you can use "Strongly-Types-Hubs". See: https://learn.microsoft.com/en-us/aspnet/signalr/overview/guide-to-the-api/hubs-api-guide-server#stronglytypedhubs

Background information about Hub object lifetime:

https://learn.microsoft.com/en-us/aspnet/signalr/overview/guide-to-the-api/hubs-api-guide-server:

You don't instantiate the Hub class or call its methods from your own code on the server; all that is done for you by the SignalR Hubs pipeline. SignalR creates a new instance of your Hub class each time it needs to handle a Hub operation such as when a client connects, disconnects, or makes a method call to the server.

Because instances of the Hub class are transient, you can't use them to maintain state from one method call to the next. Each time the server receives a method call from a client, a new instance of your Hub class processes the message. To maintain state through multiple connections and method calls, use some other method such as a database, or a static variable on the Hub class, or a different class that does not derive from Hub. If you persist data in memory, using a method such as a static variable on the Hub class, the data will be lost when the app domain recycles.

If you want to send messages to clients from your own code that runs outside the Hub class, you can't do it by instantiating a Hub class instance, but you can do it by getting a reference to the SignalR context object for your Hub class. For more information, see How to call client methods and manage groups from outside the Hub class later in this topic.

Upvotes: 1

Related Questions