ASP.NET SignalR 中樞 API 指南 - .NET 用戶端 (SignalR 1.x)

作者: Patrick FletcherTom Dykstra

警告

本檔不適用於最新版的 SignalR。 請查看ASP.NET Core SignalR

本檔提供在 .NET 用戶端中使用 SignalR 第 2 版中樞 API 的簡介,例如 Windows 市集 (WinRT) 、WPF、Silverlight 和主控台應用程式。

SignalR Hubs API 可讓您 (RPC 進行遠端程序呼叫,) 從伺服器連線到用戶端,以及從用戶端到伺服器。 在伺服器程式碼中,您會定義可由用戶端呼叫的方法,並呼叫在用戶端上執行的方法。 在用戶端程式代碼中,您會定義可從伺服器呼叫的方法,並呼叫在伺服器上執行的方法。 SignalR 會為您處理所有用戶端對伺服器管線。

SignalR 也提供稱為持續性連線的較低層級 API。 如需 SignalR、中樞和持續性連線的簡介,或示範如何建置完整 SignalR 應用程式的教學課程,請參閱 SignalR - 使用者入門

概觀

本文件包含下列章節:

如需範例 .NET 用戶端專案,請參閱下列資源:

如需如何對伺服器或 JavaScript 用戶端進行程式設計的檔,請參閱下列資源:

API 參考主題的連結是 API 的 .NET 4.5 版本。 如果您使用 .NET 4,請參閱 .NET 4 版本的 API 主題

用戶端設定

安裝 Microsoft.AspNet.SignalR.Client NuGet 套件, (不是 Microsoft.AspNet.SignalR 套件) 。 此套件同時支援 .NET 4 和 .NET 4.5 的 WinRT、Silverlight、WPF、主控台應用程式和Windows Phone用戶端。

如果您在用戶端上擁有的 SignalR 版本與您在伺服器上擁有的版本不同,SignalR 通常能夠適應差異。 例如,當 SignalR 2.0 版發行且您在伺服器上安裝時,伺服器將支援已安裝 1.1.x 的用戶端,以及已安裝 2.0 的用戶端。 如果伺服器上的版本與用戶端上的版本之間的差異太大,SignalR 會在用戶端嘗試建立連線時擲回 InvalidOperationException 例外狀況。 錯誤訊息為 「 You are using a version of the client that isn't compatible with the server. Client version X.X, server version X.X 」。

如何建立連線

您必須先建立 HubConnection 物件並建立 Proxy,才能建立連線。 若要建立連接,請在 物件上 HubConnection 呼叫 Start 方法。

var hubConnection = new HubConnection("http://www.contoso.com/");
IHubProxy stockTickerHubProxy = hubConnection.CreateHubProxy("StockTickerHub");
stockTickerHubProxy.On<Stock>("UpdateStockPrice", stock => Console.WriteLine("Stock update for {0} new price {1}", stock.Symbol, stock.Price));
await hubConnection.Start();

注意

針對 JavaScript 用戶端,您必須先註冊至少一個事件處理常式, Start 再呼叫 方法來建立連線。 .NET 用戶端不需要這樣做。 針對 JavaScript 用戶端,產生的 Proxy 程式碼會自動為所有存在於伺服器上的中樞建立 Proxy,而註冊處理常式是指出用戶端想要使用哪一個中樞的方式。 但對於 .NET 用戶端,您手動建立中樞 Proxy,因此 SignalR 會假設您將使用您建立 Proxy 的任何中樞。

範例程式碼會使用預設的 「/signalr」 URL 來連線到您的 SignalR 服務。 如需如何指定不同基底 URL 的資訊,請參閱 ASP.NET SignalR 中樞 API 指南 - 伺服器 - /signalr URL

方法會 Start 以非同步方式執行。 為了確保在建立連線之後,後續的程式程式碼不會執行,請在 await ASP.NET 4.5 非同步方法或 .Wait() 同步方法中使用 。 請勿在 WinRT 用戶端中使用 .Wait()

await connection.Start();
connection.Start().Wait();

HubConnection 類別是安全執行緒。

來自 Silverlight 用戶端的跨網域連線

如需如何從 Silverlight 用戶端啟用跨網域連線的資訊,請參閱 跨網域界限提供服務

如何設定連線

建立連線之前,您可以指定下列任何選項:

  • 並行連線限制。
  • 查詢字串參數。
  • 傳輸方法。
  • HTTP 標頭。
  • 用戶端憑證。

如何在 WPF 用戶端中設定並行連線數目上限

在 WPF 用戶端中,您可能必須從其預設值 2 增加並行連線數目上限。 建議值是 10。

var hubConnection = new HubConnection("http://www.contoso.com/");
IHubProxy stockTickerHubProxy = hubConnection.CreateHubProxy("StockTickerHub");
stockTickerHubProxy.On<Stock>("UpdateStockPrice", stock => Console.WriteLine("Stock update for {0} new price {1}", stock.Symbol, stock.Price));
ServicePointManager.DefaultConnectionLimit = 10;
await hubConnection.Start();

如需詳細資訊,請參閱 ServicePointManager.DefaultConnectionLimit

如何指定查詢字串參數

如果您想要在用戶端連接時將資料傳送至伺服器,您可以將查詢字串參數新增至連線物件。 下列範例示範如何在用戶端程式代碼中設定查詢字串參數。

var querystringData = new Dictionary<string, string>();
querystringData.Add("contosochatversion", "1.0");
var connection = new HubConnection("http://contoso.com/", querystringData);

下列範例示範如何在伺服器程式碼中讀取查詢字串參數。

public class StockTickerHub : Hub
{
    public override Task OnConnected()
    {
        var version = Context.QueryString["contosochatversion"];
        if (version != "1.0")
        {
            Clients.Caller.notifyWrongVersion();
        }
        return base.OnConnected();
    }
}

如何指定傳輸方法

在連線過程中,SignalR 用戶端通常會與伺服器交涉,以判斷伺服器和用戶端所支援的最佳傳輸。 如果您已經知道要使用哪個傳輸,可以略過此交涉程式。 若要指定傳輸方法,請將傳輸物件傳入 Start 方法。 下列範例示範如何在用戶端程式代碼中指定傳輸方法。

var hubConnection = new HubConnection("http://www.contoso.com/");
IHubProxy stockTickerHubProxy = hubConnection.CreateHubProxy("StockTickerHub");
stockTickerHubProxy.On<Stock>("UpdateStockPrice", stock => Console.WriteLine("Stock update for {0} new price {1}", stock.Symbol, stock.Price));
await hubConnection.Start(new LongPollingTransport());

Microsoft.AspNet.SignalR.Client.Transports命名空間包含下列類別,可用來指定傳輸。

ForeverFrame 傳輸不會包含在這份清單中,因為它只供瀏覽器使用。

如需如何在伺服器程式碼中檢查傳輸方法的資訊,請參閱 ASP.NET SignalR Hubs API 指南 - 伺服器 - 如何從 CoNtext 屬性取得用戶端的相關資訊。 如需傳輸和後援的詳細資訊,請參閱 SignalR 簡介 - 傳輸和後援

如何指定 HTTP 標頭

若要設定 HTTP 標頭,請使用 Headers 連線物件上的 屬性。 下列範例示範如何新增 HTTP 標頭。

hubConnection = new hubConnection("http://www.contoso.com/");
connection.Headers.Add("headername", "headervalue");
IHubProxy stockTickerHubProxy = hubConnection.CreateHubProxy("StockTickerHub");
stockTickerHubProxy.On<Stock>("UpdateStockPrice", stock => Console.WriteLine("Stock update for {0} new price {1}", stock.Symbol, stock.Price));
await connection.Start();

如何指定用戶端憑證

若要新增用戶端憑證,請在 AddClientCertificate 連線物件上使用 方法。

hubConnection = new hubConnection("http://www.contoso.com/");
hubConnection.AddClientCertificate(X509Certificate.CreateFromCertFile("MyCert.cer"));
IHubProxy stockTickerHubProxy = hubConnection.CreateHubProxy("StockTickerHub");
stockTickerHubProxy.On<Stock>("UpdateStockPrice", stock => Console.WriteLine("Stock update for {0} new price {1}", stock.Symbol, stock.Price));
await connection.Start();

如何建立中樞 Proxy

若要在用戶端上定義中樞可以從伺服器呼叫的方法,以及在伺服器中樞上叫用方法,請在連線物件上呼叫 CreateHubProxy 來建立中樞的 Proxy。 您傳入 CreateHubProxy 的字串是您中樞類別的名稱,或是在伺服器上使用屬性所 HubName 指定的名稱。 名稱比對不區分大小寫。

伺服器上的中樞類別

public class StockTickerHub : Hub

建立中樞類別的用戶端 Proxy

var hubConnection = new HubConnection("http://www.contoso.com/");
IHubProxy stockTickerHubProxy = hubConnection.CreateHubProxy("StockTickerHub");
stockTickerHubProxy.On<Stock>("UpdateStockPrice", stock => Console.WriteLine("Stock update for {0} new price {1}", stock.Symbol, stock.Price));
await hubConnection.Start();

如果您使用 屬性裝飾 Hub 類別 HubName ,請使用該名稱。

伺服器上的中樞類別

[HubName("stockTicker")]
public class StockTickerHub : Hub

建立中樞類別的用戶端 Proxy

var hubConnection = new HubConnection("http://www.contoso.com/");
IHubProxy stockTickerHubProxy = hubConnection.CreateHubProxy("stockTicker");
stockTickerHubProxy.On<Stock>("UpdateStockPrice", stock => 
    Console.WriteLine("Stock update for {0} new price {1}", stock.Symbol, stock.Price));
await hubConnection.Start();

Proxy 物件是安全線程。 事實上,如果您使用相同的 hubName 呼叫 HubConnection.CreateHubProxy 多次,您會收到相同的快 IHubProxy 取物件。

如何在伺服器可以呼叫的用戶端上定義方法

若要定義伺服器可以呼叫的方法,請使用 Proxy On 的 方法來註冊事件處理常式。

方法名稱比對不區分大小寫。 例如, Clients.All.UpdateStockPrice 在伺服器上,將會在用戶端上執行 updateStockPriceupdatestockpriceUpdateStockPrice

不同的用戶端平臺對於如何撰寫方法程式碼來更新 UI 有不同的需求。 顯示的範例適用于 WinRT (Windows 市集 .NET) 用戶端。 本主題稍後的個別章節提供 WPF、Silverlight 和主控台應用程式範例。

不含參數的方法

如果您要處理的方法沒有參數,請使用 方法的非泛型多載 On

呼叫不含參數之用戶端方法的伺服器程式碼

public class StockTickerHub : Hub
{
    public void NotifyAllClients()
    {
         Clients.All.Notify();
    }
}

本主題 稍後的 WPF 和 Silverlight 範例 (從伺服器呼叫之方法的 WinRT 用戶端程式代碼)

var hubConnection = new HubConnection("http://www.contoso.com/");
IHubProxy stockTickerHubProxy = hubConnection.CreateHubProxy("StockTickerHub");
stockTickerHub.On("notify", () =>
    // Context is a reference to SynchronizationContext.Current
    Context.Post(delegate
    {
        textBox.Text += "Notified!\n";
    }, null)
);
await hubConnection.Start();

具有參數的方法,指定參數類型

如果您要處理的方法具有參數,請將參數的類型指定為方法的 On 泛型型別。 方法有泛型多載 On ,可讓您在 Windows Phone 7) 上指定最多 8 個參數 (4 個參數。 在下列範例中,會將一個參數傳送至 UpdateStockPrice 方法。

使用 參數呼叫用戶端方法的伺服器程式碼

public void BroadcastStockPrice(Stock stock)
{
    context.Clients.Others.UpdateStockPrice(stock);
}

用於 參數的 Stock 類別

public class Stock
{
    public string Symbol { get; set; }
    public decimal Price { get; set; }
}

使用參數從伺服器呼叫的方法 WinRT 用戶端程式代碼 (請參閱本主題稍後的 WPF 和 Silverlight 範例)

stockTickerHubProxy.On<Stock>("UpdateStockPrice", stock => 
    // Context is a reference to SynchronizationContext.Current
    Context.Post(delegate
    {
        textBox.Text += string.Format("Stock update for {0} new price {1}\n", stock.Symbol, stock.Price);
    }, null)
);

具有參數的方法,指定參數的動態物件

除了將參數指定為方法的 On 泛型型別,您也可以將參數指定為動態物件:

使用 參數呼叫用戶端方法的伺服器程式碼

public void BroadcastStockPrice(Stock stock)
{
    context.Clients.Others.UpdateStockPrice(stock);
}

用於 參數的 Stock 類別

public class Stock
{
    public string Symbol { get; set; }
    public decimal Price { get; set; }
}

使用參數從伺服器呼叫之方法的 WinRT 用戶端程式代碼, (請參閱本主題稍後的 WPF 和 Silverlight 範例)

stockTickerHubProxy.On("UpdateStockPrice", stock => 
    // Context is a reference to SynchronizationContext.Current
    Context.Post(delegate
    {
        textBox.Text += string.Format("Stock update for {0} new price {1}\n", stock.Symbol, stock.Price);
    }, null)
);

如何移除處理常式

若要移除處理常式,請呼叫其 Dispose 方法。

從伺服器呼叫之方法的用戶端程式代碼

var updateStockPriceHandler = stockTickerHubProxy.On<Stock>("UpdateStockPrice", stock => 
    Context.Post(delegate
    {
        textBox.Text += string.Format("Stock update for {0} new price {1}\n", stock.Symbol, stock.Price);
    }, null)
);

要移除處理常式的用戶端程式代碼

updateStockPriceHandler.Dispose();

如何從用戶端呼叫伺服器方法

若要在伺服器上呼叫 方法,請使用 Invoke 中樞 Proxy 上的 方法。

如果伺服器方法沒有傳回值,請使用 方法的非泛型多載 Invoke

沒有傳回值之方法的伺服器程式碼

public class StockTickerHub : Hub
{
    public void JoinGroup(string groupName)
    {
        Groups.Add(Context.ConnectionId, groupName); 
    }
}

呼叫沒有傳回值之方法的用戶端程式代碼

stockTickerHubProxy.Invoke("JoinGroup", hubConnection.ConnectionID, "SignalRChatRoom");

如果伺服器方法有傳回值,請將傳回型別指定為方法的 Invoke 泛型型別。

具有傳回值且採用複雜類型參數之方法的伺服器程式碼

public IEnumerable<Stock> AddStock(Stock stock)
{
    _stockTicker.AddStock(stock);
    return _stockTicker.GetAllStocks();
}

用於參數和傳回值的 Stock 類別

public class Stock
{
    public string Symbol { get; set; }
    public decimal Price { get; set; }
}

在 ASP.NET 4.5 非同步方法中呼叫具有傳回值並採用複雜類型參數的方法用戶端程式代碼

var stocks = await stockTickerHub.Invoke<IEnumerable<Stock>>("AddStock", new Stock() { Symbol = "MSFT" });
foreach (Stock stock in stocks)
{
    textBox.Text += string.Format("Symbol: {0} price: {1}\n", stock.Symbol, stock.Price);
}

在同步方法中呼叫具有傳回值並採用複雜型別參數的方法用戶端程式代碼

var stocks = stockTickerHub.Invoke<IEnumerable<Stock>>("AddStock", new Stock() { Symbol = "MSFT" }).Result;
foreach (Stock stock in stocks)
{
    textBox.Text += string.Format("Symbol: {0} price: {1}\n", stock.Symbol, stock.Price);
}

方法會 Invoke 以非同步方式執行,並傳 Task 回 物件。 如果您未指定 await.Wait() ,下一行程式碼將會在您叫用的方法完成執行之前執行。

如何處理連線存留期事件

SignalR 提供下列您可以處理的連線存留期事件:

  • Received:在連線上收到任何資料時引發。 提供收到的資料。
  • ConnectionSlow:當用戶端偵測到緩慢或經常卸載連線時引發。
  • Reconnecting:基礎傳輸開始重新連線時引發。
  • Reconnected:當基礎傳輸重新連線時引發。
  • StateChanged:當連接狀態變更時引發。 提供舊狀態和新狀態。 如需線上狀態值的相關資訊,請參閱 ConnectionState 列舉
  • Closed:連線已中斷連線時引發。

例如,如果您想要針對不是嚴重但造成間歇性連線問題的錯誤顯示警告訊息,例如連線速度緩慢或經常卸載,請處理 ConnectionSlow 事件。

hubConnection.ConnectionSlow += () => Console.WriteLine("Connection problems.");

如需詳細資訊,請參閱 瞭解及處理 SignalR 中的連線存留期事件

如何處理錯誤

如果您未在伺服器上明確啟用詳細的錯誤訊息,則 SignalR 在錯誤之後傳回的例外狀況物件會包含有關錯誤的最低資訊。 例如,如果呼叫 newContosoChatMessage 失敗,錯誤物件中的錯誤訊息包含 「 There was an error invoking Hub method 'contosoChatHub.newContosoChatMessage'. 」不建議基於安全性考慮將詳細的錯誤訊息傳送至生產中的用戶端,但如果您想要啟用詳細的錯誤訊息以進行疑難排解,請在伺服器上使用下列程式碼。

var hubConfiguration = new HubConfiguration();
hubConfiguration.EnableDetailedErrors = true;
RouteTable.Routes.MapHubs(hubConfiguration);

若要處理 SignalR 引發的錯誤,您可以在連線物件上新增 事件的處理常式 Error

hubConnection.Error += ex => Console.WriteLine("SignalR error: {0}", ex.Message);

若要處理來自方法調用的錯誤,請將程式碼包裝在 try-catch 區塊中。

try
{
    IEnumerable<Stock> stocks = await stockTickerHub.Invoke<IEnumerable<Stock>>("GetAllStocks");
    foreach (Stock stock in stocks)
    {
        Console.WriteLine("Symbol: {0} price: {1}", stock.Symbol, stock.Price);
    }
}
catch (Exception ex)
{
    Console.WriteLine("Error invoking GetAllStocks: {0}", ex.Message);
}

如何啟用用戶端記錄

若要啟用用戶端記錄,請在 TraceLevel 連線物件上設定 和 TraceWriter 屬性。

var hubConnection = new HubConnection("http://www.contoso.com/");
hubConnection.TraceLevel = TraceLevels.All;
hubConnection.TraceWriter = Console.Out;
IHubProxy stockTickerHubProxy = hubConnection.CreateHubProxy("StockTickerHub");
stockTickerHubProxy.On<Stock>("UpdateStockPrice", stock => Console.WriteLine("Stock update for {0} new price {1}", stock.Symbol, stock.Price));
await hubConnection.Start();

伺服器可呼叫之用戶端方法的 WPF、Silverlight 和主控台應用程式程式碼範例

稍早示範的程式碼範例,可用來定義伺服器可以呼叫的用戶端方法,以套用至 WinRT 用戶端。 下列範例顯示 WPF、Silverlight 和主控台應用程式用戶端的對等程式碼。

不含參數的方法

不含參數之從伺服器呼叫之方法的 WPF 用戶端程式代碼

stockTickerHub.On<Stock>("notify", () =>
    Dispatcher.InvokeAsync(() =>
        {
            SignalRTextBlock.Text += string.Format("Notified!");
        })
);

從不含參數之伺服器呼叫之方法的 Silverlight 用戶端程式代碼

stockTickerHub.On<Stock>("notify", () =>
    // Context is a reference to SynchronizationContext.Current
    Context.Post(delegate
    {
        textBox.Text += "Notified!";
    }, null)
);

無參數之從伺服器呼叫之方法的主控台應用程式用戶端程式代碼

stockTickerHubProxyProxy.On("Notify", () => Console.WriteLine("Notified!"));

具有參數的方法,指定參數類型

使用 參數從伺服器呼叫之方法的 WPF 用戶端程式代碼

stockTickerHubProxy.On<Stock>("UpdateStockPrice", stock => 
    Dispatcher.InvokeAsync(() =>
        {
            textBox.Text += string.Format("Stock update for {0} new price {1}\n", stock.Symbol, stock.Price);
        })
);

使用 參數從伺服器呼叫之方法的 Silverlight 用戶端程式代碼

stockTickerHubProxy.On<Stock>("UpdateStockPrice", stock => 
    // Context is a reference to SynchronizationContext.Current
    Context.Post(delegate
    {
        textBox.Text += string.Format("Stock update for {0} new price {1}\n", stock.Symbol, stock.Price);
    }, null)
);

使用 參數從伺服器呼叫之方法的主控台應用程式用戶端程式代碼

stockTickerHubProxy.On<Stock>("UpdateStockPrice", stock => 
    Console.WriteLine("Symbol {0} Price {1}", stock.Symbol, stock.Price));

具有參數的方法,指定參數的動態物件

使用 參數的動態物件,從伺服器呼叫之方法的 WPF 用戶端程式代碼

stockTickerHubProxy.On("UpdateStockPrice", stock => 
    Dispatcher.InvokeAsync(() =>
        {
            textBox.Text += string.Format("Stock update for {0} new price {1}\n", stock.Symbol, stock.Price);
        })
);

使用 參數的動態物件,從伺服器呼叫之方法的 Silverlight 用戶端程式代碼

stockTickerHubProxy.On("UpdateStockPrice", stock => 
    // Context is a reference to SynchronizationContext.Current
    Context.Post(delegate
    {
        textBox.Text += string.Format("Stock update for {0} new price {1}\n", stock.Symbol, stock.Price);
    }, null)
);

使用 參數的動態物件,從伺服器呼叫的方法主控台應用程式用戶端程式代碼

stockTickerHubProxy.On("UpdateStockPrice", stock => 
    Console.WriteLine("Symbol {0} Price {1}", stock.Symbol, stock.Price));