ASP.NET SignalR Hubs API ガイド - .NET クライアント (C#)

警告

このドキュメントは、SignalR の最新バージョン用ではありません。 SignalR の ASP.NET Coreを見てみましょう。

このドキュメントでは、Windows ストア (WinRT)、WPF、Silverlight、コンソール アプリケーションなど、.NET クライアントで SignalR バージョン 2 の Hubs API を使用する方法について説明します。

SignalR Hubs API を使用すると、サーバーから接続されたクライアント、およびクライアントからサーバーへのリモート プロシージャ コール (RPC) を実行できます。 サーバー コードでは、クライアントが呼び出すことができるメソッドを定義し、クライアントで実行されるメソッドを呼び出します。 クライアント コードでは、サーバーから呼び出すことができるメソッドを定義し、サーバーで実行されるメソッドを呼び出します。 SignalR は、クライアントからサーバーへのすべての配管を処理します。

SignalR には、永続的な接続と呼ばれる下位レベルの API も用意されています。 SignalR、Hubs、および永続的な接続の概要、または完全な SignalR アプリケーションを構築する方法を示すチュートリアルについては、「SignalR - はじめに」を参照してください。

このトピックで使用するソフトウェアのバージョン

このトピックの以前のバージョン

SignalR の以前のバージョンの詳細については、「 SignalR の古いバージョン」を参照してください。

質問とコメント

このチュートリアルが気に入った方法と、ページの下部にあるコメントで改善できる内容に関するフィードバックをお寄せください。 チュートリアルに直接関連しない質問がある場合は、 ASP.NET SignalR フォーラム または StackOverflow.com に投稿できます。

概要

このドキュメントは、次のトピックに分かれています。

サンプルの .NET クライアント プロジェクトについては、次のリソースを参照してください。

サーバーまたは 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 作成してプロキシを作成する必要があります。 接続を確立するには、 オブジェクトの メソッドをStartHubConnection呼び出します。

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();
}

注意

JavaScript クライアントの場合は、 メソッドを呼び出して Start 接続を確立する前に、少なくとも 1 つのイベント ハンドラーを登録する必要があります。 これは、.NET クライアントでは必要ありません。 JavaScript クライアントの場合、生成されたプロキシ コードは、サーバー上に存在するすべてのハブのプロキシを自動的に作成します。ハンドラーを登録することは、クライアントが使用するハブを指定する方法です。 ただし、.NET クライアントの場合は、ハブ プロキシを手動で作成するため、SignalR はプロキシを作成するハブを使用することを前提としています。

このサンプル コードでは、既定の "/signalr" URL を使用して SignalR サービスに接続します。 別のベース URL を指定する方法については、「 ASP.NET SignalR Hubs API ガイド - サーバー - /signalr URL」を参照してください

メソッドは Start 非同期的に実行されます。 接続が確立されるまで後続のコード行が実行されないようにするには、ASP.NET 4.5 非同期メソッドまたは.Wait()同期メソッドで を使用awaitします。 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

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();
}

Hub クラスを 属性で装飾する場合は HubName 、その名前を使用します。

サーバー上のハブ クラス

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

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();
}

同じ を使用して を複数回呼び出 HubConnection.CreateHubProxy すと、同 hubNameじキャッシュされたオブジェクトが 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 として指定します。 メソッドには、最大 8 個のOnパラメーター (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 返します。 または .Wait()を指定awaitしない場合、呼び出すメソッドの実行が完了する前に、次のコード行が実行されます。

接続の有効期間イベントを処理する方法

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));