我遇到的问题是让我的SignalR服务器/集线器在我的SignalR客户端上调用javascript函数。
有问题的SignalR代码已在ASP.net MVC4项目中使用VB.net与MySQL和Entity framework v5实现。我正在使用IISExpress在Visual Studio 2012中的本地开发计算机上调试系统。
global.asax.vb:
Sub Application_Start()
MiniProfilerEF.Initialize()
AreaRegistration.RegisterAllAreas()
' Register the default hubs route: ~/signalr
RouteTable.Routes.MapHubs()
WebApiConfig.Register(GlobalConfiguration.Configuration)
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters)
RouteConfig.RegisterRoutes(RouteTable.Routes)
BundleConfig.RegisterBundles(BundleTable.Bundles)
AuthConfig.RegisterAuth()
' Register custom view
ViewEngines.Engines.Add(New CustomViewEngine())
End Sub
SignalR初始化javascript:
$(function () {
// Proxy created on the fly
var notification = $.connection.notificationHub;
//$.connection.notificationHub.logging = true;
// Declare functions that can be run on the client by the server
notification.client.sendNotification = onAddNotification;
// Testing code only
$("#testButton").click(function () {
// Run test function on server
notification.server.runTest();
});
// Map the onConnect and onDisconnect functions
notification.client.connected = function () { };
notification.client.disconnected = function () { };
//$.connection.hub.start();
$.connection.hub.start(function () {
alert("Notification system connected");
});
});
// Process a newly received notification from the server
function onAddNotification(message) {
// Convert the passed json message back into an object
var obj = JSON.parse(message);
var parsedDate = new Date(parseInt(obj.Timestamp.substr(6)));
// Update the notification list
$('#notifications').prepend('<li>' + obj.Message + ' at ' + dateFormat(parsedDate, "default") + '</li>');
// Update the new notification count
var count = document.getElementById("notification_count")
if (count.textContent) {
//W3C DOM
count.textContent = obj.Count;
} else if (anchor.innerText) {
//Microsoft DOM
count.innerText = obj.Count;
}
//document.getElementById("notification_count").innerHTML = obj.Count + '<i class="splashy-comment"></i>';
// Show a brief notification message
$.sticky(obj.Message, { autoclose: 2000, position: "top-right", type: "st-info" });
};
集线器类:
Public Class NotificationHub
Inherits Hub
ReadOnly Group As String = "Notification"
Public Function RunTest()
Dim testMessage As New SignalR_Notification_Message
testMessage.Count = 3
testMessage.Message = "Some test message"
testMessage.Timestamp = Now
Call Notify(testMessage, "joebloggs")
End Function
Public Overrides Function OnConnected() As Task
Dim db As New MyEntities
Dim userName As String = Context.User.Identity.Name
Dim connectionID = Context.ConnectionId
Dim conn As SignalR_Connection
' Attempt to find a retrieve a connection entry with the same Connection ID
conn = db.SignalR_Connection.Where(Function(s) s.Connection_ID = connectionID).FirstOrDefault
' If the connection does not already exist, add it
If IsNothing(conn) Then
conn = New SignalR_Connection
' Create the new connection entry
conn.Connection_ID = connectionID
conn.Username = userName
conn.Group = Group
' Attempt to save the new connection entry
Try
db.SignalR_Connection.Add(conn)
db.SaveChanges()
Catch ex As Exception
Dim a As String = ""
a = ""
End Try
End If
Return MyBase.OnConnected()
End Function
Public Overrides Function OnDisconnected() As Task
Dim db As New MyEntities
Dim userName As String = Context.User.Identity.Name
Dim connectionId As String = Context.ConnectionId
Dim conn As SignalR_Connection
' Attempt to find a retrieve the connection entry
conn = db.SignalR_Connection.Where(Function(s) s.Connection_ID = connectionId And s.Username = userName).FirstOrDefault
' Attempt to remove the connection entry
Try
db.SignalR_Connection.Remove(conn)
db.SaveChanges()
Catch ex As Exception
Dim a As String = ""
a = ""
End Try
Return MyBase.OnDisconnected()
End Function
''' <summary>
''' Send the notification to the client
''' </summary>
Public Sub Notify(Message As SignalR_Notification_Message, Username As String)
Dim ConnectionIDs As List(Of String)
Dim Serializer As New JavaScriptSerializer()
Dim json As String
' Attempt to convert the object into json before sending
Try
json = Serializer.Serialize(Message)
Catch ex As Exception
Exit Sub
End Try
' Get the connection id's this message must go to
ConnectionIDs = GetUsersConnectionID(Username)
If Not IsNothing(ConnectionIDs) Then
' Send the message to all connection ID's
For Each ConnectionID In ConnectionIDs
Clients.Client(ConnectionID).sendNotification(json)
Next
End If
End Sub
''' <summary>
''' Retrieve a list of connection ID's for the current user
''' </summary>
Public Function GetUsersConnectionID(Username As String) As List(Of String)
Dim db As New MyEntities
' Attempt to find a retrieve the connection entries
Return db.SignalR_Connection.AsNoTracking.Where(Function(s) s.Username = Username).Select(Function(s) s.Connection_ID).ToList
End Function
End Class
HTML(部分视图):
@ModelType Geo_sight.NotificationWindowModel
<div class="modal hide fade" id="myNotifications">
<div class="modal-header">
<button class="close" data-dismiss="modal">×</button>
<h3>Notifications</h3>
</div>
<div class="modal-body">
<ul class="unstyled" id="notifications">
@For Each Notification In Model.Notifications
@<li>@Html.Raw(Notification.Text)</li>
Next
</ul>
</div>
<div class="modal-footer">
<a href="javascript:void(0)" class="btn" id="testButton">Send test</a>
</div>
在 onAddNotification 函数的第一行设置断点:
var obj = JSON.parse(message);
每当调用Hub中的 Notify 函数时,几乎从不调用客户端函数!
我已经检查了我的〜/ signalr / hubs 脚本,客户端功能定义下没有列出任何内容,但是是服务器上的内容(见下文)。它是否正确?我想客户端功能应该在这里?
proxies.notificationHub = this.createHubProxy('notificationHub');
proxies.notificationHub.client = { };
proxies.notificationHub.server = {
getUsersConnectionID: function (Username) {
return proxies.notificationHub.invoke.apply(proxies.notificationHub, $.merge(["GetUsersConnectionID"], $.makeArray(arguments)));
},
notify: function (Message, Username) {
return proxies.notificationHub.invoke.apply(proxies.notificationHub, $.merge(["Notify"], $.makeArray(arguments)));
},
runTest: function () {
return proxies.notificationHub.invoke.apply(proxies.notificationHub, $.merge(["RunTest"], $.makeArray(arguments)));
}
};
return proxies;
通过稍微调试,我可以让客户端运行但完全随机且非常偶然地只需在前一个signalR发送呼叫结束后几秒钟再次按下我的测试按钮。
以下是Firebug控制台的一个示例...
随着越来越多的测试和调试,我遇到了客户端功能何时执行且未调用的特性......
从我之前的更新中可以看出,SignalR选择使用长轮询,超时时间约为35秒。
对客户端函数进行了多次进一步的重复调用后,似乎只有在长轮询生命的大约前10秒内进行的调用才能到达客户端并成功运行该函数。在此期间之后发出的电话似乎没有通过。
我想这意味着我的代码是合理的,但为什么会发生这种情况?
SignalR常见问题解答
我也在这里发现了类似问题:SignalR Wiki FAQ's
我使用的是Windows 7 Professional,但我没有使用IIS(我正在使用IIS Express),所以这可能是同样的问题吗?