SignalR 疑難排解
作者: Patrick Fletcher
警告
本檔不適用於最新版的 SignalR。 請查看ASP.NET Core SignalR。
本檔說明 SignalR 的常見疑難排解問題。
本主題中使用的軟體版本
- Visual Studio 2013
- .NET 4.5
- SignalR 第 2 版
本主題的舊版
如需舊版 SignalR 的相關資訊,請參閱 SignalR 舊版。
問題和批註
請留下您喜歡本教學課程的意見反應,以及我們可以在頁面底部的批註中改善的內容。 如果您有與教學課程不直接相關的問題,您可以將問題張貼到 ASP.NET SignalR 論壇 或 StackOverflow.com。
本檔包含下列各節。
- 在用戶端與伺服器之間以無訊息方式呼叫方法會失敗
- 將 IIS Websocket 設定為 ping/pong 以偵測不正確用戶端
- 其他連線問題
- 編譯和伺服器端錯誤
- Visual Studio 問題
- Internet Information Services 問題
- Microsoft Azure 問題
在用戶端與伺服器之間以無訊息方式呼叫方法會失敗
本節說明用戶端與伺服器之間方法呼叫失敗的可能原因,而不會產生有意義的錯誤訊息。 在 SignalR 應用程式中,伺服器沒有用戶端實作之方法的相關資訊;當伺服器叫用用戶端方法時,方法名稱和參數資料會傳送至用戶端,而且只有在方法存在於伺服器指定的格式時,才會執行方法。 如果在用戶端上找不到相符的方法,則不會發生任何動作,而且伺服器上不會引發任何錯誤訊息。
若要進一步調查未呼叫的用戶端方法,您可以在中樞上呼叫 start 方法之前開啟記錄功能,以查看來自伺服器的呼叫。 若要在 JavaScript 應用程式中啟用記錄,請參閱 如何啟用用戶端記錄 (JavaScript 用戶端版本) 。 若要在 .NET 用戶端應用程式中啟用記錄,請參閱 如何啟用用戶端記錄 (.NET 用戶端版本) 。
拼錯的方法、不正確的方法簽章或不正確的中樞名稱
如果所呼叫方法的名稱或簽章與用戶端上的適當方法不完全相符,呼叫將會失敗。 確認伺服器呼叫的方法名稱符合用戶端上方法的名稱。 此外,SignalR 會使用 Camel 大小寫方法建立中樞 Proxy,如同 JavaScript 中的適當方法,因此會在用戶端 Proxy 中呼叫伺服器上呼叫 SendMessage
sendMessage
的方法。 如果您在伺服器端程式碼中使用 HubName
屬性,請確認所使用的名稱符合用來在用戶端上建立中樞的名稱。 如果您未使用 HubName
屬性,請確認 JavaScript 用戶端中的中樞名稱為 camel 大小寫,例如 chatHub,而不是 ChatHub。
用戶端上的重複方法名稱
請確認用戶端上沒有重複的方法,只有大小寫不同。 如果您的用戶端應用程式有一個稱為 sendMessage
的方法,請確認也有一個呼叫 SendMessage
的方法。
用戶端上遺漏 JSON 剖析器
SignalR 需要有 JSON 剖析器,才能序列化伺服器與用戶端之間的呼叫。 如果您的用戶端沒有內建 JSON 剖析器 (,例如 Internet Explorer 7) ,您必須在應用程式中包含一個。 您可以 在這裡下載 JSON 剖析器。
混合中樞和 PersistentConnection 語法
SignalR 使用兩種通訊模型:中樞和 PersistentConnections。 在用戶端程式代碼中呼叫這兩個通訊模型的語法不同。 如果您已在伺服器程式碼中新增中樞,請確認您的所有用戶端程式代碼都使用適當的中樞語法。
在 JavaScript 用戶端中建立 PersistentConnection 的 JavaScript 用戶端程式代碼
var myConnection = $.connection('/echo');
在 JAVAscript 用戶端中建立中樞 Proxy 的 JavaScript 用戶端程式代碼
var myHub = $.connection.MyHub;
將路由對應至 PersistentConnection 的 C# 伺服器程式碼
RouteTable.Routes.MapConnection<MyConnection>("my", "/echo");
將路由對應至中樞的 C# 伺服器程式碼,或如果您有多個應用程式,則對應至多個中樞
App.MapSignalR();
在新增訂用帳戶之前啟動連線
如果在將可從伺服器呼叫的方法新增至 Proxy 之前啟動中樞的連線,將不會收到訊息。 下列 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 () {
...
});
中樞 Proxy 上遺漏方法名稱
確認伺服器上定義的 方法已在用戶端上訂閱。 即使伺服器定義 方法,它仍必須新增至用戶端 Proxy。 方法可以透過下列方式新增至用戶端 Proxy (請注意,方法會新增至 client
中樞的成員,而不是直接) 中樞:
將方法新增至中樞 Proxy 的 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
。
從不同的應用程式存取中樞
SignalR 中樞只能透過實作 SignalR 用戶端的應用程式來存取。 SignalR 無法與其他通訊程式庫交互操作 (,例如 SOAP 或 WCF Web 服務。) 如果目標平臺沒有 SignalR 用戶端可用,就無法直接存取伺服器的端點。
手動序列化資料
SignalR 會自動使用 JSON 來序列化您的方法參數-不需要自行執行。
OnDisconnected 函式中未在用戶端上執行的遠端中樞方法
這是設計的行為。 呼叫 時 OnDisconnected
,中樞已進入 Disconnected
狀態,這不允許呼叫進一步的中樞方法。
在 OnDisconnected 事件中正確執行程式碼的 C# 伺服器程式碼
public class MyHub : Hub
{
public override Task OnDisconnected()
{
// Do what you want here
return base.OnDisconnected();
}
}
OnDisconnect 不會在一致時間引發
這是設計的行為。 當使用者嘗試從具有使用中 SignalR 連線的頁面流覽時,SignalR 用戶端會盡最大努力嘗試通知伺服器用戶端連線將會停止。 如果 SignalR 用戶端嘗試無法連線到伺服器,伺服器會在稍後可設定 DisconnectTimeout
之後處置連線,此時 OnDisconnected
會引發事件。 如果 SignalR 用戶端的嘗試成功,事件 OnDisconnected
將會立即引發。
如需設定 DisconnectTimeout
的相關資訊,請參閱 處理連線存留期事件:DisconnectTimeout。
已達到連線限制
在 Windows 7 等用戶端作業系統上使用完整版的 IIS 時,會加總 10 個連線限制。 使用用戶端 OS 時,請改用 IIS Express 以避免此限制。
跨網域連線未正確設定
如果跨網域連線 (SignalR URL 不在與主控頁面相同的網域中,) 未正確設定,連線可能會失敗,而不會顯示錯誤訊息。 如需如何啟用跨網域通訊的資訊,請參閱 如何建立跨網域連線。
在 .NET 用戶端中使用 NTLM (Active Directory) 連線
如果連線未正確設定,使用網域安全性的 .NET 用戶端應用程式中的連線可能會失敗。 若要在網域環境中使用 SignalR,請設定必要的連線屬性,如下所示:
實作連線認證的 C# 用戶端程式代碼
connection.Credentials = CredentialCache.DefaultCredentials;
將 IIS Websocket 設定為 ping/pong 以偵測不正確用戶端
SignalR 伺服器不知道用戶端是否無效,而且依賴來自基礎 Websocket 的通知進行連線失敗,也就是 OnClose
回呼。 此問題的其中一個解決方案是設定 IIS Websocket 為您執行 ping/pong。 這可確保您的連線會在意外中斷時關閉。 如需詳細資訊,請參閱 此 stackoverflow 文章。
其他連線問題
本節說明連線期間發生之特定徵兆或錯誤訊息的原因和解決方案。
「必須先呼叫開始,才能傳送資料」錯誤
如果程式碼在啟動連接之前參考 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 的資料夾,就會干擾自動建立的 Proxy,可能會看到此錯誤。 若要避免此錯誤,請勿在應用程式中使用名為 SignalR
的資料夾,或關閉自動產生 Proxy。 如需詳細資訊,請參閱 產生的 Proxy 及其用途 。
.NET 或 Silverlight 用戶端中的「403 禁止」錯誤
此錯誤可能會在未正確啟用跨網域通訊的跨網域環境中發生。 如需如何啟用跨網域通訊的資訊,請參閱 如何建立跨網域連線。 若要在 Silverlight 用戶端中建立跨網域連線,請參閱 Silverlight 用戶端的跨網域連線。
「404 找不到」 錯誤
此問題有幾個原因。 確認下列所有專案:
中樞 Proxy 位址參考的格式不正確: 如果產生的中樞 Proxy 位址的參考格式不正確,通常會看到此錯誤。 確認已正確建立中樞位址的參考。 如需詳細資訊 ,請參閱如何參考動態產生的 Proxy 。
在新增中樞路由之前,先將路由新增至應用程式: 如果您的應用程式使用其他路由,請確認新增的第一個路由是 呼叫
MapSignalR
。針對無副檔名 URL 使用 IIS 7 或 7.5: 使用 IIS 7 或 7.5 需要無延伸模組 URL 的更新,讓伺服器能夠存取位於
/signalr/hubs
的中樞定義。 您可以 在這裡找到更新。IIS 快取過期或損毀: 若要確認快取內容未過期,請在 PowerShell 視窗中輸入下列命令以清除快取:
net stop w3svc Remove-Item -Path "C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files\root\*" -Force -Recurse net start w3svc
「500 內部伺服器錯誤」
這是非常泛型的錯誤,可能會有各種不同的原因。 錯誤的詳細資料應該會出現在伺服器的事件記錄檔中,或可透過偵錯伺服器找到。 在伺服器上開啟詳細錯誤,可能會取得更詳細的錯誤資訊。 如需詳細資訊,請參閱 如何在 Hub 類別中處理錯誤。
如果防火牆或 Proxy 未正確設定,則通常也會看到此錯誤,導致要求標頭重寫。 解決方案是在防火牆或 Proxy 上確定已啟用埠 80。
「未預期的回應碼:500」
如果應用程式中所使用的 .NET Framework 版本與 Web.Config 中指定的版本不符,就可能發生此錯誤。解決方案是確認應用程式設定和Web.Config檔案都使用 .NET 4.5。
「TypeError: < hubType > 未定義」 錯誤
如果未正確呼叫 , MapSignalR
就會產生此錯誤。 如需詳細資訊 ,請參閱如何註冊 SignalR 中介軟體和設定 SignalR 選項 。
使用者程式碼未處理 JsonSerializationException
確認您傳送至方法的參數不包含不可序列化的類型, (例如檔案控制碼或資料庫連線) 。 如果您需要在伺服器端物件上使用您不想傳送給用戶端的成員, (基於安全性或序列化) 的原因,請使用 JSONIgnore
屬性。
「通訊協定錯誤:未知傳輸」錯誤
如果用戶端不支援 SignalR 使用的傳輸,就可能發生此錯誤。 如需哪些瀏覽器可以搭配 SignalR 使用的資訊,請參閱 傳輸和後援 。
「JavaScript Hub Proxy 產生已停用」。
如果在 DisableJavaScriptProxies
設定時也包含動態產生 Proxy signalr/hubs
的參考,則會發生此錯誤。 如需手動建立 Proxy 的詳細資訊,請參閱 產生的 Proxy 及其用途。
「連線識別碼的格式不正確」或「使用者身分識別無法在作用中的 SignalR 連線期間變更」錯誤
如果使用驗證,而且用戶端會在連線停止之前登出,可能會看到此錯誤。 解決方案是在登出用戶端之前停止 SignalR 連線。
「未攔截的錯誤: SignalR: jQuery 找不到。 請確定在SignalR.js檔案之前參考 jQuery」 錯誤
SignalR JavaScript 用戶端需要 jQuery 才能執行。 確認 jQuery 的參考正確、使用的路徑有效,而且 jQuery 的參考是在 SignalR 的參考之前。
「未攔截的 TypeError:無法讀取未定義的屬性 ' < property > '」錯誤
此錯誤會導致未正確參考 jQuery 或中樞 Proxy。 確認對 jQuery 和中樞 Proxy 的參考是否正確、使用的路徑有效,而且 jQuery 的參考是在中樞 Proxy 的參考之前。 中樞 Proxy 的預設參考看起來應該如下所示:
正確參考中樞 Proxy 的 HTML 用戶端程式代碼
<script src="/signalr/hubs"></script>
「RuntimeBinderException 未由使用者程式碼處理」錯誤
使用 的多載 Hub.On
不正確時,可能會發生此錯誤。 如果方法有傳回值,則必須將傳回型別指定為泛型型別參數:
在用戶端上定義的方法 (,而不產生 Proxy)
MyHub.On<ReturnType>("MethodName", LocalMethod);
連線識別碼不一致,或頁面載入之間的連接中斷
這是設計的行為。 由於中樞物件裝載于頁面物件中,因此在重新整理頁面時會終結中樞。 多頁應用程式必須維護使用者與連線識別碼之間的關聯,以便在頁面載入之間保持一致。 連線識別碼可以儲存在物件或資料庫中的伺服器上 ConcurrentDictionary
。
「值不可為 Null」錯誤
目前不支援具有選擇性參數的伺服器端方法;如果省略選擇性參數,方法將會失敗。 如需詳細資訊,請參閱選擇性參數 (機器翻譯)。
Firebug 中的「Firefox 無法建立伺服器位址 <> 連線」錯誤
如果 WebSocket 傳輸的交涉失敗,而是改用另一個傳輸,就可以在 Firebug 中看到此錯誤訊息。 這是設計的行為。
.NET 用戶端應用程式中的「遠端憑證無效」錯誤
如果您的伺服器需要自訂用戶端憑證,您可以在提出要求之前,將 x509certificate 新增至連線。 使用 Connection.AddClientCertificate
將憑證新增至連線。
驗證逾時後連線中斷
這是設計的行為。 連線處於作用中狀態時,無法修改驗證認證;若要重新整理認證,必須停止並重新啟動連線。
使用 jQuery Mobile 時,OnConnected 會呼叫兩次
jQuery Mobile 的函 initializePage
式會強制重新執行每個頁面中的腳本,進而建立第二個連線。 此問題的解決方案包括:
- 在 JavaScript 檔案之前包含 jQuery Mobile 的參考。
- 藉由設定
$.mobile.autoInitializePage = false
來停用函initializePage
式。 - 等候頁面完成初始化,再啟動連線。
使用伺服器傳送的事件,Silverlight 應用程式中的訊息會延遲
在 Silverlight 上使用伺服器傳送的事件時,訊息會延遲。 若要強制改用長時間輪詢,請在啟動連線時使用下列專案:
connection.Start(new LongPollingTransport());
使用 Forever Frame 通訊協定的「許可權遭拒」
這是已知的問題, 此處所述。 使用最新的 JQuery 程式庫可能會看到此徵兆;因應措施是將您的應用程式降級為 JQuery 1.8.2。
「InvalidOperationException:不是有效的 Web 通訊端要求。
如果使用 WebSocket 通訊協定,但網路 Proxy 正在修改要求標頭,就可能發生此錯誤。 解決方案是設定 Proxy 以允許埠 80 上的 WebSocket。
當用戶端在伺服器上呼叫方法時,無法解析「例外狀況: < 方法名稱 > 方法」
此錯誤可能是使用無法在 JSON 承載中探索到的資料類型,例如 Array。 因應措施是使用 JSON 可探索的資料類型,例如 IList。 如需詳細資訊,請參閱 .NET 用戶端無法使用陣列參數呼叫中樞方法。
編譯和伺服器端錯誤
下一節包含編譯器和伺服器端執行時間錯誤的可能解決方案。
中樞實例的參考為 Null
由於會為每個連線建立中樞實例,因此您無法自行在程式碼中建立中樞的實例。 若要從中樞本身外部呼叫中樞上的方法,請參閱 如何呼叫用戶端方法,以及從 Hub 類別外部管理群組 ,以瞭解如何取得中樞內容的參考。
HTTPCoNtext.Current.Session 為 null
這是設計的行為。 SignalR 不支援 ASP.NET 會話狀態,因為啟用會話狀態會中斷雙工傳訊。
沒有適當的覆寫方法
如果您使用舊版檔或部落格中的程式碼,可能會看到此錯誤。 請確認您未參考已變更或已被取代的方法名稱 (,例如 OnConnectedAsync
) 。
HostCoNtextExtensions.WebSocketServerUrl 為 null
這是設計的行為。 此成員已被取代,不應使用。
「名為 'signalr.hubs' 的路由已在路由集合中」錯誤
如果 MapSignalR
應用程式呼叫兩次,就會看到此錯誤。 有些範例應用程式會直接在 Startup 類別中呼叫 MapSignalR
;其他應用程式則會在包裝函式類別中呼叫 。 請確定您的應用程式不會同時執行兩者。
未使用 WebSocket
如果您已確認您的伺服器和用戶端符合支援 的平臺 檔中所列的 WebSocket (需求) ,則必須在伺服器上啟用 WebSocket。 您可以在這裡找到執行這項操作的指示。
$.connection 未定義
此錯誤表示頁面上的腳本未正確載入,或中樞 Proxy 無法連線或存取不正確。 確認頁面上的腳本參考對應至您專案中載入的腳本,而且當伺服器執行時,可以在瀏覽器中存取 /signalr/hubs。
找不到編譯動態運算式所需的一或多個類型
此錯誤表示 Microsoft.CSharp
程式庫遺失。 在 [ 元件架構 > ] 索引標籤中新增它。
無法從 Visual Basic 中的 Clients.Caller 或強型別中樞存取呼叫端狀態;「從類型 'Task (Of Object) ' 轉換成類型 'String' 無效」錯誤
若要存取 Visual Basic 或強型別中樞中的呼叫端狀態,請使用 Clients.CallerState
SignalR 2.1 中引進的屬性 () ,而不是 Clients.Caller
。
Visual Studio 問題
本節說明 Visual Studio 中遇到的問題。
指令檔節點不會出現在Solution Explorer
我們的部分教學課程會在偵錯時,引導您前往Solution Explorer中的「指令檔」節點。 這個節點是由 JavaScript 偵錯工具所產生,而且只會在 Internet Explorer 中偵錯瀏覽器用戶端時出現;如果使用 Chrome 或 Firefox,則不會顯示節點。 如果另一個用戶端偵錯工具正在執行,例如 Silverlight 偵錯工具,JavaScript 偵錯工具也不會執行。
SignalR 無法在 Visual Studio 2008 或更早版本上運作
這是設計的行為。 SignalR 需要.NET Framework 4 或更新版本;這需要在 Visual Studio 2010 或更新版本中開發 SignalR 應用程式。 SignalR 的伺服器元件需要 .NET Framework 4.5。
IIS 問題
本節包含 Internet Information Services 的問題。
SignalR 可在 Visual Studio 開發伺服器上運作,但不適用於 IIS
IIS 7.0 和 7.5 支援 SignalR,但必須新增無擴充 URL 的支援。 若要新增對無延伸模組 URL 的支援,請參閱 https://support.microsoft.com/kb/980368
SignalR 需要 ASP.NET 安裝在伺服器上, (ASP.NET 預設不會安裝在 IIS 上) 。 若要安裝 ASP.NET,請參閱 下載 ASP.NET。
Microsoft Azure 問題
本節包含 Microsoft Azure 的問題。
在 Azure 背景工作角色中裝載 SignalR 時的 FileLoadException
在 Azure 背景工作角色中裝載 SignalR 可能會導致例外狀況「無法載入檔案或元件 'Microsoft.Owin, Version=2.0.0.0」。 這是 NuGet 的已知問題;系結重新導向不會在 Azure 背景工作角色專案中自動新增。 若要修正此問題,您可以手動新增系結重新導向。 將下列幾行新增至 app.config
背景工作角色專案的檔案。
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Microsoft.Owin" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.0.2.0" newVersion="2.0.2.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Owin.Security" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.0.2.0" newVersion="2.0.2.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
更改主題名稱之後,不會透過 Azure 後板接收訊息
Azure 背板所使用的主題會在內部維護;它們不是使用者可設定的。