2017-06-02 55 views
1

請遵循代碼:的SqlDependency具體SignalR用戶

_layout:

$(function() { 
    var connection = $.connection.notificationHub; 

    //signalr method for push server message to client 
    connection.client.addNotification = function (who) { 
     //send notification here 
     console.info("Send Notification") 
    }; 

    // Start hub 
    $.connection.hub.start().done(function() { 
     console.log("SignalR Started") 
    }); 
}); 

的Global.asax.cs:

public class Global : HttpApplication 
{ 
    string con = ConfigurationManager.ConnectionStrings["sqlConString"].ConnectionString; 
    protected void Application_Start() 
    { 
     AreaRegistration.RegisterAllAreas(); 
     FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); 
     RouteConfig.RegisterRoutes(RouteTable.Routes); 
     BundleConfig.RegisterBundles(BundleTable.Bundles); 

     //here in Application Start we will start Sql Dependency 
     SqlDependency.Start(con); 
    } 

    protected void Session_Start(object sender, EventArgs e) 
    { 
     NotificationComponent NC = new NotificationComponent(); 
     var currentTime = DateTime.Now; 
     HttpContext.Current.Session["LastUpdated"] = currentTime; 
     NC.RegisterNotification(currentTime); 
    } 

    protected void Application_End() 
    { 
     //here we will stop Sql Dependency 
     SqlDependency.Stop(con); 
    } 
} 

控制器:

[HttpPost] 
[ValidateAntiForgeryToken] 
public ActionResult MyAction(string parameter) 
{ 
    //Database Notification (Table - Contacts) -Add or Update 
    ctx.SaveChanges(); 
} 

NotificationHub:集線器

private readonly static ConnectionMapping<string> _connections = new ConnectionMapping<string>(); 

public static void SendNotification(string who) 
{ 
    IHubContext context = GlobalHost.ConnectionManager.GetHubContext<NotificationHub>(); 
    foreach (var connectionId in _connections.GetConnections(who)) 
    { 
     var result = context.Clients.Client(connectionId); 
     if (result != null) 
     { 
      result.addNotification(who); 
     } 
    } 
} 

Components.cs:

public void RegisterNotification(DateTime currentTime) 
{ 
    string conStr = ConfigurationManager.ConnectionStrings["sqlConString"].ConnectionString; 
    string sqlCommand = @"SELECT [ContactID],[ContactName],[ContactNo] from [dbo].[Contacts] where [AddedOn] > @AddedOn"; 
    //you can notice here I have added table name like this [dbo].[Contacts] with [dbo], its mendatory when you use Sql Dependency 
    using (SqlConnection con = new SqlConnection(conStr)) 
    { 
     SqlCommand cmd = new SqlCommand(sqlCommand, con); 
     cmd.Parameters.AddWithValue("@AddedOn", currentTime); 
     if (con.State != System.Data.ConnectionState.Open) 
     { 
      con.Open(); 
     } 
     cmd.Notification = null; 
     SqlDependency sqlDep = new SqlDependency(cmd); 
     sqlDep.OnChange += sqlDep_OnChange; 
     //we must have to execute the command here 
     using (SqlDataReader reader = cmd.ExecuteReader()) 
     { 
      // nothing need to add here now 
     } 
    } 
} 

//After code `ctx.SaveChanges()`, call the code below (50 times): 
void SqlDep_OnChange(object sender, SqlNotificationEventArgs e) //<-- Here Problem 
{ 

    //from here we will send notification message to client 
    NotificationHub.SendNotification("User1586"); 
    //... 

    //re-register notification 
    RegisterNotification(DateTime.Now); 

    //HERE -After this line "RegisterNotification(DateTime.Now);", it returns again to the line: "void SqlDep_OnChange(object sender, SqlNotificationEventArgs e)" 
} 

用戶 「User1586」 正在接收多個通知。 該行"void SqlDep_OnChange(object sender, SqlNotificationEventArgs e)"重複多次。 如果你有50個在線用戶,做50次在這條線:

void SqlDep_OnChange(object sender, SqlNotificationEventArgs e) 

如果你有1000個在線用戶,就1000倍,在這條線:

void SqlDep_OnChange(object sender, SqlNotificationEventArgs e). 

換句話說,用戶「User1586 「收到幾個通知。

我跟着這裏的例子:http://www.dotnetawesome.com/2016/05/push-notification-system-with-signalr.html

理念是數據庫更新後,將通知發送給特定的用戶。

任何解決方案?

回答

1

首先時,SQL依賴關係是不知道什麼樣的數據已經改變。所以你應該在事件處理程序中查詢。如果你想發送與用戶ID相對應的數據,並且只針對一個用戶,我建議你這樣做;

事件處理程序

private void SqlDependency_OnChange(object sender, SqlNotificationEventArgs e) 
{ 
    if (e.Info == SqlNotificationInfo.Insert) 
    { 
     RecordInfo info = GetLastInsertedRecord(); //Just a custom entity 
      if(info.UserId > 0) 
      NotificationHub.SendNotification(info.UserId); 
    } 
    RegisterNotification(DateTime.Now); 
} 

樞紐

public static List<UserConnection> ListUser { get; set; } 
public static void SendNotification(string who) 
{ 
    IHubContext context = GlobalHost.ConnectionManager.GetHubContext<MyHub>(); 
    // Get specific user from connected ones. 
    string Id = ListUser.Find(x => x.UserId == who).ConnectionId; 
    context.Clients.Client(Id).addNotification(who); // or another data 
} 
//Add every connected users to the list 
public override Task OnConnected() 
    { 
     ListUser = new List<UserConnection>(); 
     var us = new UserConnection(); 
     us.UserId = Context.QueryString["UserId"]; 
     us.ConnectionId = Context.ConnectionId; 
     ListUser.Add(us); 

     return base.OnConnected(); 
    } 

更新客戶端

$(function() { 
    var connection = $.connection.notificationHub; 
    //Pass the userId here as querystring 
    $.connection.hub.qs = "UserId=" + $("#labelHoldsUserId").val(); 
    //signalr method for push server message to client 
    connection.client.addNotification = function (who) { 
     //send notification here 
     console.log(who + " sends message"); 
    }; 

    // Start hub 
    $.connection.hub.start().done(function() { 
     console.log("SignalR Started") 
    }); 
}) 
+0

ibubi,拜託,我很感興趣。 – UserMat2017

+0

@ UserMat2017我已更新帖子 – ibubi

+0

非常感謝 – UserMat2017

0

看來,OnChange處理程序和SqlDependency實例都只適用於一個事件。事件觸發後,您取消訂閱處理程序,您需要將處理程序註冊到新的SqlDependency對象。

請參閱鏈接在這裏的全部細節:http://msdn.microsoft.com/en-us/library/a52dhwx7(v=vs.80).aspx

+1

我不明白,你能不能給我一個例子嗎? – UserMat2017