ASP.NET SignalR Hubs API ガイド - .NET クライアント (C#)
警告
このドキュメントは、最新版の SignalR に対するものではありません。 ASP.NET Core SignalR に関する記事を参照してください。
このドキュメントでは、Windows ストア (WinRT)、WPF、Silverlight、コンソール アプリケーションなどの .NET クライアントで SignalR バージョン 2 用の Hubs API を使用する方法の概要について説明します。
SignalR Hubs API を使うと、サーバーから接続されたクライアントに、およびクライアントからサーバーに、リモート プロシージャ コール (RPC) を行うことができます。 サーバー コードでは、クライアントから呼び出すことができるメソッドを定義し、クライアント上で実行されるメソッドを呼び出します。 クライアント コードでは、サーバーから呼び出すことができるメソッドを定義し、サーバー上で実行されるメソッドを呼び出します。 クライアントとサーバーの間のやり取りはすべて、SignalR によって自動的に処理されます。
SignalR は、永続的接続と呼ばれる下位レベルの API も提供します。 SignalR、Hubs、永続的な接続の概要、または完全な SignalR アプリケーションを構築する方法を示すチュートリアルについては、「SignalR の概要」を参照してください。
このトピックで使用されるソフトウェアのバージョン
- Visual Studio 2017
- .NET 4.5
- SignalR バージョン 2
このトピックの以前のバージョン
SignalR の以前のバージョンの詳細については、「SignalR の以前のバージョン」を参照してください。
質問とコメント
このチュートリアルの感想、改善に関するフィードバックをページの下部にあるコメント欄にお寄せください。 チュートリアルに直接関連しない質問がある場合は、ASP.NET SignalR フォーラムまたは StackOverflow.com に投稿できます。
概要
このドキュメントは、次のトピックに分かれています。
サンプルの .NET クライアント プロジェクトについては、次のリソースを参照してください。
- GitHub.com の gustavo-armenta/ SignalR-Samples (WinRT、Silverlight、コンソール アプリの例)。
- GitHub.com の DamianEdwards / SignalR-MoveShapeDemo / MoveShape.Desktop (WPF の例)。
- GitHub.com の SignalR / Microsoft.AspNet.SignalR.Client.Samples (コンソール アプリの例)。
サーバーまたは JavaScript クライアントをプログラミングする方法のドキュメントについては、次のリソースを参照してください。
API リファレンス トピックへのリンクは、API の .NET 4.5 バージョンへのリンクです。 .NET 4 を使用している場合は、.NET 4 バージョンの API トピックを参照してください。
クライアントのセットアップ
(Microsoft.AspNet.SignalR パッケージではなく) Microsoft.AspNet.SignalR.Client NuGet パッケージをインストールします。 このパッケージでは、.NET 4 と .NET 4.5 の両方について、WinRT、Silverlight、WPF、コンソール アプリケーション、Windows Phone クライアントをサポートします。
クライアント上にある SignalR のバージョンがサーバー上にあるバージョンと異なるとき、SignalR では多くの場合、その違いに適応できます。 たとえば、SignalR バージョン 2 を実行しているサーバーでは、1.1.x がインストールされているクライアントと、バージョン 2 がインストールされているクライアントがサポートされます。 サーバー上のバージョンとクライアント上のバージョンの違いが大きすぎる場合、またはクライアントがサーバーより新しい場合、クライアントで接続を確立しようとしたときに 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
オブジェクトを作成し、プロキシを作成する必要があります。 接続を確立するには、HubConnection
オブジェクトの Start
メソッドを呼び出します。
using (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();
}
Note
JavaScript クライアントの場合、接続を確立するために Start
メソッドを呼び出す前に、少なくとも 1 つのイベント ハンドラーを登録する必要があります。 これは、.NET クライアントでは必要ありません。 JavaScript クライアントの場合、生成されたプロキシ コードでは、サーバー上に存在するすべてのハブのプロキシを自動的に作成します。ハンドラーを登録することは、クライアントで使用するハブを指定する方法です。 ただし、.NET クライアントの場合は、ハブ プロキシを手動で作成するため、SignalR では、プロキシを作成するハブを使用することを前提としています。
サンプル コードでは、既定の URL "/signalr" を使って SignalR サービスに接続します。 異なるベース URL を指定する方法については、「ASP.NET SignalR Hubs API ガイド - サーバー」の「/signalr URL」をご覧ください。
Start
メソッドは非同期的に実行されます。 接続が確立される後まで後続のコード行が実行されないようにするには、ASP.NET 4.5 非同期メソッドで await
を使用するか、同期メソッドで .Wait()
を使用します。 WinRT クライアントでは .Wait()
を使用しないでください。
await connection.Start();
connection.Start().Wait();
Silverlight クライアントからのクロスドメイン接続
Silverlight クライアントからのクロスドメイン接続を有効にする方法については、ドメイン境界を越えてサービスを使用できるようにするに関する記事を参照してください。
接続を構成する方法
接続を確立する前に、次のいずれかのオプションを指定できます。
- コンカレント接続の制限。
- クエリ文字列のパラメーター。
- トランスポート方法。
- HTTP ヘッダー。
- クライアント証明書。
WPF クライアントでのコンカレント接続の最大数を設定する方法
WPF クライアントでは、コンカレント接続の最大数を既定値の 2 から増やす必要がある場合があります。 推奨値は 10 です。
using (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 メソッドに渡します。 次の例は、クライアント コードでトランスポート方法を指定する方法を示しています。
using (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 名前空間には、トランスポートを指定するために使用できる次のクラスが含まれています。
- LongPollingTransport
- ServerSentEventsTransport
- WebSocketTransport (サーバーとクライアントの両方で .NET 4.5 を使用する場合にのみ使用できます)。
- AutoTransport (クライアントとサーバーの両方でサポートされている最適なトランスポートを自動的に選択します。これが既定のトランスポートです。これを
Start
メソッドに渡すと、何も渡さないのと同じ効果があります)。
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();
ハブ プロキシを作成する方法
ハブによってサーバーから呼び出すことができるメソッドをクライアントで定義し、サーバーのハブでメソッドを呼び出すには、接続オブジェクトで CreateHubProxy
を呼び出してハブのプロキシを作成します。 CreateHubProxy
に渡す文字列は、ハブ クラスの名前、または HubName
属性によって指定された名前 (サーバーで使用された場合) です。 名前の照合では大文字と小文字は区別されません。
サーバーでのハブ クラス
public class StockTickerHub : Hub
ハブ クラスのクライアント プロキシを作成する
using (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();
}
ハブ クラスを HubName
属性で装飾する場合は、その名前を使用します。
サーバーでのハブ クラス
[HubName("stockTicker")]
public class StockTickerHub : Hub
ハブ クラスのクライアント プロキシを作成する
using (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();
}
同じ hubName
を使用して複数回 HubConnection.CreateHubProxy
を呼び出すと、同じキャッシュされた IHubProxy
オブジェクトが取得されます。
サーバーが呼び出すことのできるメソッドをクライアントで定義する方法
サーバーから呼び出すことができるメソッドを定義するには、プロキシの On
メソッドを使用してイベント ハンドラーを登録します。
メソッド名の照合では大文字と小文字が区別されません。 たとえば、サーバーでの Clients.All.UpdateStockPrice
は、クライアントでは updateStockPrice
、updatestockprice
、または UpdateStockPrice
を実行します。
クライアント プラットフォームによって、UI を更新するためのメソッド コードの記述方法に関する要件が異なります。 次に示す例は、WinRT (Windows ストア .NET) クライアント用です。 WPF、Silverlight、コンソール アプリケーションの例については、このトピックの後半の別のセクションで説明します。
パラメーターのないメソッド
処理しているメソッドにパラメーターがない場合は、On
メソッドの非ジェネリック オーバーロードを使用します。
パラメーターのないクライアント メソッドを呼び出すサーバー コード
public class StockTickerHub : Hub
{
public void NotifyAllClients()
{
Clients.All.Notify();
}
}
パラメーターを指定せずにサーバーから呼び出されるメソッドの WinRT クライアント コード (このトピックで後述する WPF と Silverlight の例を参照)
using (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
メソッドには、最大 8 個のパラメーター (Windows Phone 7 では 4 個) を指定できる汎用オーバーロードがあります。 次の例では、1 つのパラメーターが 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
メソッドを使用します。
サーバー メソッドに戻り値がない場合は、Invoke
メソッドの非ジェネリック オーバーロードを使用します。
戻り値がないメソッドのサーバー コード
public class StockTickerHub : Hub
{
public void JoinGroup(string groupName)
{
Groups.Add(Context.ConnectionId, groupName);
}
}
戻り値のないメソッドを呼び出すクライアント コード
stockTickerHubProxy.Invoke("JoinGroup", "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;
App.MapSignalR(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
プロパティを設定します。
using (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));