MVC SignalR not firing from Controller Post Method

2019-08-27 17:30发布

问题:

When Saving schedule to calendar it must auto update the activity logs on my notification bar in my Home Controller. It saves the data but only show when notification bar is refreshed. It seems that Hub is not starting when saved.

CalendarController.cs

       [HttpPost]
        public JsonResult SaveSchedule(Schedule s)
        {
            var userid = User.Identity.GetUserId();
            var profile = _context.Profiles.Single(p => p.Id == userid);
            var status = false;

            if (s.Schedule_ID > 0)
            {
                //Update
                var v = _context.Schedules.Where(a => a.Schedule_ID == s.Schedule_ID).FirstOrDefault();
                if (v != null)
                {
                    v.Shift = s.Shift;
                }

            }

            var activitylog = new ActivityLog
            {
                UserId = userid,
                LogDate = DateTime.Now,
                Activity = ActivityHelper.GetActivityLog(4, profile.FirstName)

            };
             // save to data and must be shown on notification bar
            _context.ActivityLogs.Add(activitylog);
            _context.SaveChanges();
            ActivityHub.StartLogging();
            status = true;
            return new JsonResult { Data = new { status = status } };
        }

HomeController.cs

public JsonResult GetLogs()
        {
            return Json(ActivityHelper.GetActivityLogs(), JsonRequestBehavior.AllowGet);
        }

ActivityHub.cs

 public class ActivityHub : Hub
    {
        public static void StartLogging()
        {
            IHubContext context = GlobalHost.ConnectionManager.GetHubContext<ActivityHub>();

            //calls the signalR client part to execute javascript method
            context.Clients.All.displayLog();
        }
    }

My CSHTML

<script>
    $(function () {
   var activityFromHub = $.connection.activityHub;
        $.connection.hub.start().done(function () {
            FetchLogs();
        });

        activityFromHub.client.displayLog = function () {
            console.log('Hub Started');
            FetchLogs();
        }

function FetchLogs() {

            $.ajax({
                type: 'GET',
                url: '/Home/GetLogs',
                datatype: 'json',
                success: function (data) {
                    $("#logs tr").remove();
                    data = $.parseJSON(data);
                    if (data.length > 0) {
                           .... do some append here
                    }
                },
                error: function (error) {
                    alert("error");
                }
            });
        }
});
</script>

ActivityHelper.cs

static readonly string connString = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;

public static class ActivityHelper
    {
            public static string GetActivityLogs()
            {
                string sqlCommand = @"my select query here";
                try
                {
                    var messages = new List<ActivityLog>();
                    using(var connection = new SqlConnection(connString))
                    {
                        connection.Open();
                        using (SqlConnection con = new SqlConnection(connString))
                        {
                            SqlCommand cmd = new SqlCommand(sqlCommand, con);
                            if(con.State != System.Data.ConnectionState.Open)
                            {
                                con.Open();
                            }
                            cmd.Notification = null;
                            SqlDependency dependency = new SqlDependency(cmd);
                            dependency.OnChange += new OnChangeEventHandler(dependency_OnChange);

                            var reader = cmd.ExecuteReader();

                            while (reader.Read())
                            {
                                messages.Add(item: new ActivityLog
                                {
                                    Activity = reader["Activity"] != DBNull.Value ? (string)reader["Activity"] : "",
                                    LogDate = (DateTime)reader["LogDate"]
                                });
                            }
                        }
                    }
                    var jsonSerialiser = new JavaScriptSerializer();
                    var json = jsonSerialiser.Serialize(messages);
                    return json;

                }
                catch(Exception ex)
                {
                    throw;
                }
            }



public static void dependency_OnChange(object sender, SqlNotificationEventArgs e)
        {
            if (e.Type == SqlNotificationType.Change)
            {
                SqlDependency dependency = sender as SqlDependency;
                dependency.OnChange -= dependency_OnChange;

                var activityHub = GlobalHost.ConnectionManager.GetHubContext<ActivityHub>();
                GetActivityLogs();
            }
        }

}

回答1:

FIRST METHOD First Solution change your javascript code like this. If this not works move to the second method:

 $(function () {
   var activityFromHub = $.connection.ActivityHub;
        $.connection.hub.start().done(function () {
            FetchLogs();
        });

        activityFromHub.client.displayLog = function () {
            console.log('Hub Started');
            FetchLogs();
        }
});

SECOND METHOD:

Each client connecting to a hub passes a unique connection id. You can retrieve this value in the Context.ConnectionId property of the hub context. And i found there is nothing happening like this. You may try this solution.

I think the simplest solution for your question is to use groups. http://www.asp.net/signalr/overview/guide-to-the-api/working-with-groups

Your hub class would contain methods to join a group:

public Task JoinGroup(string groupName)
{
    return Groups.Add(Context.ConnectionId, groupName);
}

public Task LeaveGroup(string groupName)
{
    return Groups.Remove(Context.ConnectionId, groupName);
}

and your hub will be look like this:

public static void StartLogging(string groupName)
{
   IHubContext context = GlobalHost.ConnectionManager.GetHubContext<ActivityHub>();
   context.Clients.Group(groupName).displayLog();

   //calls the signalR client part to execute javascript method
   //context.Clients.All.displayLog();
}

And change your javascript as like this:

$(function () {
   var activityFromHub = $.connection.ActivityHub;
        $.connection.hub.start().done(function () {
            activityFromHub.server.joinGroup("Group1");
            activityFromHub.server.StartLogging("Group1");
            FetchLogs();
        });

        activityFromHub.client.displayLog = function () {
            console.log('Hub Started');
            FetchLogs();
        }
});

I hope this will resolve your issue. If you are still facing issue. Please leave comments. Thank you.