SignalR 疑难解答 (SignalR 1.x)
警告
本文档不适用于最新版本的 SignalR。 查看 ASP.NET Core SignalR。
本文档介绍 SignalR 的常见故障排除问题。
本文档包含以下部分。
在客户端和服务器之间调用方法以无提示方式失败
本部分介绍客户端和服务器之间方法调用失败而不显示有意义的错误消息的可能原因。 在 SignalR 应用程序中,服务器没有有关客户端实现的方法的信息;当服务器调用客户端方法时,方法名称和参数数据将发送到客户端,并且仅当该方法以服务器指定的格式存在时才执行。 如果在客户端上找不到匹配的方法,则不会发生任何操作,并且不会在服务器上引发错误消息。
若要进一步调查未调用的客户端方法,可以在中心上调用 start 方法之前启用日志记录,以查看来自服务器的调用。 若要在 JavaScript 应用程序中启用日志记录,请参阅 如何 (JavaScript 客户端版本) 启用客户端日志记录 。 若要在 .NET 客户端应用程序中启用日志记录,请参阅 如何启用客户端日志记录 (.NET 客户端版本) 。
方法拼写错误、方法签名错误或中心名称不正确
如果被调用方法的名称或签名与客户端上的相应方法不完全匹配,则调用将失败。 验证服务器调用的方法名称是否与客户端上方法的名称匹配。 此外,SignalR 使用适用于 JavaScript 的 camel 大小写方法创建中心代理,因此将在客户端代理中调用sendMessage
服务器上调用的方法SendMessage
。 如果在服务器端代码中使用 HubName
属性,请验证使用的名称是否与用于在客户端上创建中心的名称匹配。 如果不使用 HubName
属性,请验证 JavaScript 客户端中中心的名称是否为 camel 大小写,例如 chatHub 而不是 ChatHub。
客户端上的方法名称重复
验证客户端上是否有仅因大小写而异的重复方法。 如果客户端应用程序有一个名为 sendMessage
的方法,请验证是否也没有名为 SendMessage
的方法。
客户端上缺少 JSON 分析程序
SignalR 要求存在 JSON 分析程序来序列化服务器和客户端之间的调用。 如果客户端没有内置的 JSON 分析程序 ((例如 Internet Explorer 7) ),则需要在应用程序中包括一个。 可以 在此处下载 JSON 分析程序。
混合中心和 PersistentConnection 语法
SignalR 使用两种通信模型:Hubs 和 PersistentConnections。 调用这两个通信模型的语法在客户端代码中有所不同。 如果在服务器代码中添加了中心,请验证所有客户端代码是否都使用正确的中心语法。
在 JavaScript 客户端中创建 PersistentConnection 的 JavaScript 客户端代码
var myConnection = $.connection('/echo');
在 Javascript 客户端中创建中心代理的 JavaScript 客户端代码
var myHub = $.connection.MyHub;
将路由映射到 PersistentConnection 的 C# 服务器代码
RouteTable.Routes.MapConnection<MyConnection>("my", "/echo");
将路由映射到中心或多个中心的 C# 服务器代码(如果有多个应用程序)
RouteTable.Routes.MapHubs();
添加订阅之前启动的连接
如果在将可从服务器调用的方法添加到代理之前启动中心连接,则不会收到消息。 以下 JavaScript 代码无法正确启动中心:
不允许接收中心消息的 JavaScript 客户端代码不正确
var chat = $.connection.chatHub;
$.connection.hub.start().done(function () {
chat.client.broadcastMessage = function (name, message) {...};
});
而是在调用 Start 之前添加方法订阅:
将订阅正确添加到中心的 JavaScript 客户端代码
var chat = $.connection.chatHub;
chat.client.broadcastMessage = function (name, message) {...};
$.connection.hub.start().done(function () {
...
});
中心代理上缺少方法名称
验证是否在客户端上订阅了服务器上定义的方法。 即使服务器定义了 方法,它仍必须添加到客户端代理。 可以通过以下方式将方法添加到客户端代理 (请注意,该方法将添加到 client
中心的成员,而不是直接) 中心:
将方法添加到中心代理的 JavaScript 客户端代码
// Method added to proxy in JavaScript:
myHubProxy.server.method1 = function (param1, param2) {...};
//Multiple methods added to proxy in JavaScript using jQuery:
$.extend(myHubProxy.server, {
method1: function (param1, param2) {...},
method2: function (param3, param4) {...}
});
未声明为 Public 的中心或中心方法
若要在客户端上可见,必须将中心实现和方法声明为 public
。
从其他应用程序访问中心
只能通过实现 SignalR 客户端的应用程序访问 SignalR 中心。 SignalR 无法与其他通信库(如 SOAP 或 WCF Web services) (互操作。) 如果没有可用于目标平台的 SignalR 客户端,则无法直接访问服务器的终结点。
手动序列化数据
SignalR 将自动使用 JSON 来序列化方法参数 - 无需自行执行。
远程中心方法未在 OnDisconnected 函数中的客户端上执行
此行为是设计使然。 调用 时 OnDisconnected
,中心已进入 Disconnected
状态,不允许调用其他中心方法。
正确执行 OnDisconnected 事件中的代码的 C# 服务器代码
public class MyHub : Hub
{
public override Task OnDisconnected()
{
// Do what you want here
return base.OnDisconnected();
}
}
已达到连接限制
在 Windows 7 等客户端操作系统上使用完整版本的 IIS 时,将施加 10 个连接限制。 使用客户端 OS 时,请改用 IIS Express 以避免此限制。
跨域连接未正确设置
如果跨域连接 (SignalR URL 与托管页面不在同一域中的连接,) 未正确设置,则连接可能会失败,且不会显示错误消息。 有关如何启用跨域通信的信息,请参阅 如何建立跨域连接。
使用 NTLM (Active Directory 的连接) 在 .NET 客户端中不起作用
如果未正确配置连接,则使用域安全性的 .NET 客户端应用程序中的连接可能会失败。 若要在域环境中使用 SignalR,请设置所需的连接属性,如下所示:
实现连接凭据的 C# 客户端代码
connection.Credentials = CredentialCache.DefaultCredentials;
其他连接问题
本部分介绍连接期间发生的特定症状或错误消息的原因和解决方案。
“必须先调用 Start 才能发送数据”错误
如果代码在启动连接之前引用 SignalR 对象,则通常会看到此错误。 必须在连接完成后添加处理程序等将调用服务器上定义的方法的连接。 请注意,对 Start
的调用是异步的,因此调用后的代码可能会在调用完成之前执行。 在连接完全启动后添加处理程序的最佳方法是将它们放入回调函数中,该回调函数作为参数传递给 start 方法:
正确添加引用 SignalR 对象的事件处理程序的 JavaScript 客户端代码
$.connection.hub.start().done(function () {
// Wire up Send button to call NewContosoChatMessage on the server.
$('#newContosoChatMessage').click(function () {
contosoChatHubProxy.server.newContosoChatMessage(
$('#displayname').val(), $('#message').val());
$('#message').val('').focus();
});
如果在仍然引用 SignalR 对象时连接停止,也会出现此错误。
“301 永久移动”或“302 暂时移动”错误
如果项目包含名为 SignalR 的文件夹,则可能会出现此错误,该文件夹将干扰自动创建的代理。 若要避免此错误,请不要在应用程序中使用名为 SignalR
的文件夹,或关闭自动生成代理。 有关更多详细信息 ,请参阅生成的代理及其用途 。
.NET 或 Silverlight 客户端中的“403 禁止访问”错误
此错误可能发生在未正确启用跨域通信的跨域环境中。 有关如何启用跨域通信的信息,请参阅 如何建立跨域连接。 若要在 Silverlight 客户端中建立跨域连接,请参阅 从 Silverlight 客户端建立跨域连接。
“404 找不到”错误
此问题有多种原因。 验证以下所有内容:
- 中心代理地址引用的格式不正确: 如果对生成的中心代理地址的引用的格式不正确,则通常会看到此错误。 验证是否已正确引用中心地址。 有关详细信息 ,请参阅如何引用动态生成的代理 。
- 在添加中心路由之前,将路由添加到应用程序: 如果应用程序使用其他路由,请验证添加的第一个路由是否是对 的
MapHubs
调用。
“500 内部服务器错误”
这是一个非常通用的错误,原因可能有多种。 错误的详细信息应显示在服务器的事件日志中,或者可以通过调试服务器找到。 可以通过在服务器上启用详细错误来获取更详细的错误信息。 有关详细信息,请参阅 如何处理中心类中的错误。
“TypeError: <hubType> is undefined”错误
如果未正确调用 , MapHubs
则会导致此错误。 有关详细信息 ,请参阅如何注册 SignalR 路由和配置 SignalR 选项 。
JsonSerializationException 未由用户代码处理
验证发送到方法的参数是否不包含不可序列化的类型, (如文件句柄或数据库连接) 。 如果需要在服务器端对象上使用不希望发送到客户端的成员, (出于安全性或序列化) 的原因,请使用 JSONIgnore
属性。
“协议错误:未知传输”错误
如果客户端不支持 SignalR 使用的传输,则可能会发生此错误。 有关哪些浏览器可用于 SignalR 的信息,请参阅 传输和回退 。
“JavaScript 中心代理生成已禁用。”
如果 DisableJavaScriptProxies
设置了 ,同时在 中也包括对动态生成的代理 signalr/hubs
的引用,则会发生此错误。 有关手动创建代理的详细信息,请参阅 生成的代理及其用途。
“连接 ID 的格式不正确”或“在活动 SignalR 连接期间用户标识无法更改”错误
如果使用身份验证,并且客户端在连接停止之前已注销,则可能会看到此错误。 解决方法是在注销客户端之前停止 SignalR 连接。
“未捕获错误:SignalR: jQuery 未找到。 请确保在SignalR.js文件“错误之前引用 jQuery
SignalR JavaScript 客户端要求运行 jQuery。 验证对 jQuery 的引用是否正确、使用的路径是否有效,以及对 jQuery 的引用是否在对 SignalR 的引用之前。
“未捕获的 TypeError: 无法读取未定义的属性'<property>'”错误
此错误是由于未正确引用 jQuery 或中心代理。 验证对 jQuery 和中心代理的引用是否正确、使用的路径是否有效,以及对 jQuery 的引用是否在对中心代理的引用之前。 对中心代理的默认引用应如下所示:
正确引用中心代理的 HTML 客户端代码
<script src="/signalr/hubs"></script>
“RuntimeBinderException 未由用户代码处理”错误
使用 不正确的重载 Hub.On
时,可能会发生此错误。 如果方法具有返回值,则必须将返回类型指定为泛型类型参数:
在客户端 (上定义的方法,没有生成的代理)
MyHub.On<ReturnType>("MethodName", LocalMethod);
连接 ID 不一致或页面加载之间的连接中断
此行为是设计使然。 由于中心对象托管在页面对象中,因此在页面刷新时会销毁中心。 多页应用程序需要维护用户和连接 ID 之间的关联,以便它们在页面加载之间保持一致。 连接 ID 可以存储在服务器上 ConcurrentDictionary
对象或数据库中。
“值不能为 null”错误
当前不支持具有可选参数的服务器端方法;如果省略可选参数,该方法将失败。 有关详细信息,请参阅可选参数。
Firebug 中的“Firefox 无法在地址>处与服务器<建立连接”错误
如果 WebSocket 传输协商失败,而是使用另一个传输,则可以在 Firebug 中看到此错误消息。 此行为是设计使然。
.NET 客户端应用程序中的“远程证书根据验证过程无效”错误
如果服务器需要自定义客户端证书,则可以在发出请求之前将 x509certificate 添加到连接。 使用 Connection.AddClientCertificate
将证书添加到连接。
身份验证超时后连接断开
此行为是设计使然。 连接处于活动状态时,无法修改身份验证凭据;若要刷新凭据,必须停止并重启连接。
使用 jQuery Mobile 时,将调用 OnConnected 两次
jQuery Mobile 的 initializePage
函数强制重新执行每个页面中的脚本,从而创建第二个连接。 此问题的解决方案包括:
- 在 JavaScript 文件之前包括对 jQuery Mobile 的引用。
initializePage
通过设置$.mobile.autoInitializePage = false
禁用函数。- 等待页面完成初始化,然后再启动连接。
使用服务器发送事件在 Silverlight 应用程序中延迟消息
在 Silverlight 上使用服务器发送的事件时,消息会延迟。 若要强制改用长轮询,请在启动连接时使用以下方法:
connection.Start(new LongPollingTransport());
使用 Forever Frame 协议的“权限被拒绝”
这是一个已知问题, 如此处所述。 可以使用最新的 JQuery 库看到此症状;解决方法是将应用程序降级到 JQuery 1.8.2。
编译和服务器端错误
以下部分包含编译器和服务器端运行时错误的可能解决方案。
对中心实例的引用为 null
由于是为每个连接创建中心实例,因此无法自行在代码中创建中心实例。 若要从中心本身外部调用中心上的方法,请参阅 如何从中心类外部调用客户端方法和管理组 ,了解如何获取对中心上下文的引用。
HTTPContext.Current.Session 为 null
此行为是设计使然。 SignalR 不支持 ASP.NET 会话状态,因为启用会话状态会中断双工消息传送。
没有合适的方法可替代
如果使用旧版文档或博客中的代码,可能会看到此错误。 验证是否未引用已更改或已弃用的方法的名称, (如 OnConnectedAsync
) 。
HostContextExtensions.WebSocketServerUrl 为 null
此行为是设计使然。 此成员已弃用,不应使用。
“名为'signalr.hubs'的路由已在路由集合中”错误
如果 MapHubs
应用程序调用了两次 ,则会出现此错误。 一些示例应用程序直接在全局应用程序文件中调用 MapHubs
;另一些示例应用程序在包装类中调用 。 确保应用程序不会同时执行这两项操作。
Visual Studio 问题
本部分介绍 Visual Studio 中遇到的问题。
“脚本文档”节点未显示在解决方案资源管理器
调试时,我们的一些教程会将你定向到 解决方案资源管理器 中的“脚本文档”节点。 此节点由 JavaScript 调试器生成,仅在 Internet Explorer 中调试浏览器客户端时显示;如果使用 Chrome 或 Firefox,则不会显示 节点。 如果另一个客户端调试器(如 Silverlight 调试器)正在运行,JavaScript 调试器也不会运行。
SignalR 不适用于 Visual Studio 2008 或更早版本
此行为是设计使然。 SignalR 需要.NET Framework 4 或更高版本;这需要在 Visual Studio 2010 或更高版本中开发 SignalR 应用程序。
IIS 问题
本部分包含 Internet Information Services 的问题。
MapHubs 调用后网站崩溃
此问题已在最新版本的 SignalR 中修复。 通过使用 NuGet 更新安装,验证是否正在使用最新发布的 SignalR 版本。
Azure 问题
本部分包含 Microsoft Azure 的问题。
更改主题名称后,不会通过 Azure 底板接收消息
Azure 底板使用的主题不适合用户配置。