ASP.NET Core 用 SignalR でハブを使用する

作成者: Rachel AppelKevin Griffin

SignalR Hubs API を使用すると、接続されたクライアントがサーバー上のメソッドを呼び出すことができます。 サーバーはクライアントから呼び出されるメソッドを定義し、クライアントはサーバーから呼び出されるメソッドを定義します。 SignalR は、リアルタイムのクライアントとサーバー間の通信を可能にするために必要なすべての処理を行います。

SignalR ハブを構成する

ハブでSignalR必要なサービスを登録するには、次を呼び出しますAddSignalRProgram.cs

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddSignalR();

エンドポイントを構成SignalRするには、次の中でもProgram.cs呼び出しますMapHub

app.MapRazorPages();
app.MapHub<ChatHub>("/Chat");

app.Run();

ハブを作成して使用する

から継承するクラスを宣言してハブを作成します Hub。 クライアントから呼び出し可能にするメソッドをクラスに追加 public します。

public class ChatHub : Hub
{
    public async Task SendMessage(string user, string message)
        => await Clients.All.SendAsync("ReceiveMessage", user, message);
}

Note

ハブは 一時的です

  • ハブ クラスのプロパティに状態を格納しないでください。 各ハブ メソッド呼び出しは、新しいハブ インスタンスで実行されます。
  • ハブが存在し続けることに依存する非同期メソッドを呼び出すときは、await を使います。 たとえば、Clients.All.SendAsync(...) などのメソッドは、await を指定せずに呼び出し、SendAsync が終了する前にハブ メソッドが完了した場合、失敗する可能性があります。

Context オブジェクト

この Hub クラスには、接続に Context 関する情報を含む次のプロパティを含むプロパティが含まれています。

プロパティ 説明
ConnectionId SignalR によって割り当てられる、接続の一意の ID を取得します。 接続ごとに 1 つの接続 ID があります。
UserIdentifier ユーザー識別子を取得します。 既定では、SignalR は、接続に関連付けられている ClaimsPrincipal からの ClaimTypes.NameIdentifier をユーザー識別子として使用します。
User 現在のユーザーに関連付けられている ClaimsPrincipal を取得します。
Items この接続のスコープ内でデータを共有するために使用できるキーと値のコレクションを取得します。 このコレクションにデータを格納することができ、ハブ メソッドの異なる呼び出しの間も、その接続について維持されます。
Features 接続で使用できる機能のコレクションを取得します。 現時点では、ほとんどのシナリオでこのコレクションは必要ないため、まだ詳細には記載されていません。
ConnectionAborted 接続が中止されたときに通知する CancellationToken を取得します。

Hub.Context には、次のメソッドも含まれます。

メソッド 説明
GetHttpContext 接続の HttpContext 場合、または null 接続が HTTP 要求に関連付けられていない場合に返します。 HTTP 接続の場合は、このメソッドを使用して、HTTP ヘッダーやクエリ文字列などの情報を取得します。
Abort 接続を中止します。

Clients オブジェクト

この Hub クラスには、 Clients サーバーとクライアント間の通信用に次のプロパティを含むプロパティが含まれています。

プロパティ 説明
All 接続されているすべてのクライアントでメソッドを呼び出します
Caller ハブ メソッドを呼び出したクライアントでメソッドを呼び出します
Others メソッドを呼び出したクライアントを除く、接続されているすべてのクライアントでメソッドを呼び出します

Hub.Clients には、次のメソッドも含まれます。

メソッド 説明
AllExcept 指定した接続を除く、接続されているすべてのクライアントでメソッドを呼び出します
Client 接続された特定の 1 つのクライアントでメソッドを呼び出します
Clients 接続された特定の複数のクライアントでメソッドを呼び出します
Group 指定したグループ内のすべての接続でメソッドを呼び出します
GroupExcept 指定した接続を除く、指定したグループ内のすべての接続でメソッドを呼び出します
Groups 複数の接続グループでメソッドを呼び出します
OthersInGroup ハブ メソッドを呼び出したクライアントを除く、接続のグループでメソッドを呼び出します
User 特定のユーザーに関連付けられているすべての接続でメソッドを呼び出します
Users 指定したユーザーに関連付けられているすべての接続でメソッドを呼び出します

SendAsync メソッドでは、前の表の各プロパティまたはメソッドからオブジェクトが返されます。 メソッドは SendAsync 、呼び出すクライアント メソッドの名前とパラメーターを受け取ります。

クライアントにメッセージを送信する

特定のクライアントに対して呼び出しを行うには、Clients オブジェクトのプロパティを使用します。 次の例では、3 つのハブメソッドがあります。

  • SendMessage を呼び出すと、Clients.All を使用して、接続されているすべてのクライアントにメッセージが送信されます。
  • SendMessageToCaller を呼び出すと、Clients.Caller を使用して、呼び出し元にメッセージが返送されます。
  • SendMessageToGroup を呼び出すと、SignalR Users グループ内のすべてのクライアントにメッセージが送信されます。
public async Task SendMessage(string user, string message)
    => await Clients.All.SendAsync("ReceiveMessage", user, message);

public async Task SendMessageToCaller(string user, string message)
    => await Clients.Caller.SendAsync("ReceiveMessage", user, message);

public async Task SendMessageToGroup(string user, string message)
    => await Clients.Group("SignalR Users").SendAsync("ReceiveMessage", user, message);

厳密に型指定されたハブ

使用 SendAsync の欠点は、呼び出されるクライアント メソッドを指定するために文字列に依存することです。 このため、メソッド名が間違って綴られていたり、クライアントに存在しなくなっていると、コードで実行時エラーが発生します。

使用する SendAsync 代わりに、クラスを厳密に入力 Hub します Hub<T>。 次の例では、 ChatHub クライアント メソッドが次のような IChatClientインターフェイスに抽出されています。

public interface IChatClient
{
    Task ReceiveMessage(string user, string message);
}

このインターフェイスを使用して、前の例を ChatHub 厳密に型指定するようにリファクタリングできます。

public class StronglyTypedChatHub : Hub<IChatClient>
{
    public async Task SendMessage(string user, string message)
        => await Clients.All.ReceiveMessage(user, message);

    public async Task SendMessageToCaller(string user, string message)
        => await Clients.Caller.ReceiveMessage(user, message);

    public async Task SendMessageToGroup(string user, string message)
        => await Clients.Group("SignalR Users").ReceiveMessage(user, message);
}

Hub<IChatClient> を使用すると、クライアント メソッドをコンパイル時にチェックできます。 これにより、インターフェイスで定義されているメソッドにのみアクセスを提供できるため Hub<T> 、文字列の使用に起因する問題を回避できます。 厳密に型指定された Hub<T> を使用すると、SendAsync は使用できなくなります。

Note

サフィックスは Async メソッド名から削除されません。 クライアント メソッドが定義 .on('MyMethodAsync')されていない限り、名前として使用 MyMethodAsync しないでください。

ハブ メソッドの名前を変更する

既定では、サーバー ハブ メソッドの名前は .NET メソッドの名前です。 特定のメソッドに対するこの既定の動作を変更するには、 HubMethodName 属性を使用します。 クライアントは、メソッドを呼び出すときに、.NET メソッド名の代わりにこの名前を使用する必要があります。

[HubMethodName("SendMessageToUser")]
public async Task DirectMessage(string user, string message)
    => await Clients.User(user).SendAsync("ReceiveMessage", user, message);

接続のイベントを処理する

SignalR Hubs API には、接続の管理と追跡のために、仮想メソッド OnConnectedAsyncOnDisconnectedAsync が用意されています。 クライアントが OnConnectedAsync ハブに接続したときにアクションを実行するように仮想メソッドをオーバーライドします (グループへの追加など)。

public override async Task OnConnectedAsync()
{
    await Groups.AddToGroupAsync(Context.ConnectionId, "SignalR Users");
    await base.OnConnectedAsync();
}

クライアントが切断するときにアクションを実行するには、OnDisconnectedAsync 仮想メソッドをオーバーライドします。 クライアントが意図的に切断された場合 (呼び出し connection.stop()など) は、パラメーターに exception 設定 nullされます。 ただし、ネットワーク障害などのエラーが原因でクライアントが切断された場合、このパラメーターにはエラー exception を記述する例外が含まれます。

public override async Task OnDisconnectedAsync(Exception? exception)
{
    await base.OnDisconnectedAsync(exception);
}

RemoveFromGroupAsyncOnDisconnectedAsync呼び出す必要はありません。自動的に処理されます。

エラーの処理

ハブ メソッドでスローされる例外は、メソッドを呼び出したクライアントに送信されます。 JavaScript クライアントでは、このメソッドは invokeJavaScript Promiseを返します。 クライアントは、返された Promise にハンドラーをアタッチcatchすることも、例外を処理するために使用asyncawaittry/catch/することもできます。

try {
  await connection.invoke("SendMessage", user, message);
} catch (err) {
  console.error(err);
}

ハブが例外をスローしても、接続は閉じられません。 既定では、 SignalR 次の例に示すように、一般的なエラー メッセージをクライアントに返します。

Microsoft.AspNetCore.SignalR.HubException: An unexpected error occurred invoking 'SendMessage' on the server.

予期しない例外には、データベース接続が失敗したときにトリガーされる例外でのデータベース サーバー名など、機密情報が含まれていることがよくあります。 セキュリティ対策として、SignalR では、これらの詳細なエラー メッセージは既定では公開されません。 例外の詳細が抑制される理由の詳細については、ASP.NET CoreSignalRのセキュリティに関する考慮事項を参照してください。

例外的な条件をクライアントに反映する必要がある場合は、クラスを使用します HubException 。 ハブ メソッドで a HubException がスローされた場合は、 SignalR変更されていない例外メッセージ全体をクライアントに送信します。

public Task ThrowException()
    => throw new HubException("This error will be sent to the client!");

Note

SignalR によってクライアントに送信されるのは、例外の Message プロパティだけです。 スタック トレースと例外のその他のプロパティは、クライアントでは使用できません。

その他のリソース

作成者: Rachel AppelKevin Griffin

サンプル コードを表示またはダウンロードする (ダウンロード方法)

SignalR ハブとは

SignalR Hubs API を使用すると、接続されているクライアント上のメソッドをサーバーから呼び出すことができます。 サーバーのコードでは、クライアントによって呼び出されるメソッドを定義します。 クライアントのコードでは、サーバーから呼び出されるメソッドを定義します。 クライアントからサーバーおよびサーバーからクライアントへのリアルタイム通信を可能にするバックグラウンドの処理はすべて、SignalR によって行われます。

SignalR ハブを構成する

ミドルウェアには SignalR 、次の呼び出し AddSignalRによって構成される一部のサービスが必要です。

services.AddSignalR();

ASP.NET Core アプリに機能を追加SignalRする場合は、メソッドUseEndpointsのコールバックで呼び出MapHubしてルートをStartup.Configure設定SignalRします。

app.UseRouting();
app.UseEndpoints(endpoints =>
{
    endpoints.MapHub<ChatHub>("/chathub");
});

ハブを作成して使用する

Hub から継承するクラスを宣言してハブを作成し、それにパブリック メソッドを追加します。 クライアントは、次のように public定義されているメソッドを呼び出すことができます。

public class ChatHub : Hub
{
    public Task SendMessage(string user, string message)
    {
        return Clients.All.SendAsync("ReceiveMessage", user, message);
    }
}

C# のメソッドの場合と同様に、複合型や配列など、戻り値の型とパラメーターを指定できます。 パラメーターと戻り値の複合オブジェクトおよび配列のシリアル化と逆シリアル化は、SignalR によって処理されます。

Note

ハブは一時的なものです。

  • ハブ クラスのプロパティに状態を格納しないでください。 ハブ メソッドのすべての呼び出しは、新しいハブ インスタンスで実行されます。
  • ハブが存在し続けることに依存する非同期メソッドを呼び出すときは、await を使います。 たとえば、Clients.All.SendAsync(...) などのメソッドは、await を指定せずに呼び出し、SendAsync が終了する前にハブ メソッドが完了した場合、失敗する可能性があります。

Context オブジェクト

Hub クラスの Context プロパティには、接続に関する情報が設定される次のプロパティが含まれます。

プロパティ 説明
ConnectionId SignalR によって割り当てられる、接続の一意の ID を取得します。 接続ごとに 1 つの接続 ID があります。
UserIdentifier ユーザー識別子を取得します。 既定では、SignalR は、接続に関連付けられている ClaimsPrincipal からの ClaimTypes.NameIdentifier をユーザー識別子として使用します。
User 現在のユーザーに関連付けられている ClaimsPrincipal を取得します。
Items この接続のスコープ内でデータを共有するために使用できるキーと値のコレクションを取得します。 このコレクションにデータを格納することができ、ハブ メソッドの異なる呼び出しの間も、その接続について維持されます。
Features 接続で使用できる機能のコレクションを取得します。 現時点では、ほとんどのシナリオでこのコレクションは必要ないため、まだ詳細には記載されていません。
ConnectionAborted 接続が中止されたときに通知する CancellationToken を取得します。

Hub.Context には、次のメソッドも含まれます。

メソッド 説明
GetHttpContext 接続の HttpContext 場合、または null 接続が HTTP 要求に関連付けられていない場合に返します。 HTTP 接続の場合は、このメソッドを使って、HTTP ヘッダーやクエリ文字列などの情報を取得できます。
Abort 接続を中止します。

Clients オブジェクト

Hub クラスの Clients プロパティには、サーバーとクライアントの間の通信に関する次のプロパティが含まれます。

プロパティ 説明
All 接続されているすべてのクライアントでメソッドを呼び出します
Caller ハブ メソッドを呼び出したクライアントでメソッドを呼び出します
Others メソッドを呼び出したクライアントを除く、接続されているすべてのクライアントでメソッドを呼び出します

Hub.Clients には、次のメソッドも含まれます。

メソッド 説明
AllExcept 指定した接続を除く、接続されているすべてのクライアントでメソッドを呼び出します
Client 接続された特定の 1 つのクライアントでメソッドを呼び出します
Clients 接続された特定の複数のクライアントでメソッドを呼び出します
Group 指定したグループ内のすべての接続でメソッドを呼び出します
GroupExcept 指定した接続を除く、指定したグループ内のすべての接続でメソッドを呼び出します
Groups 複数の接続グループでメソッドを呼び出します
OthersInGroup ハブ メソッドを呼び出したクライアントを除く、接続のグループでメソッドを呼び出します
User 特定のユーザーに関連付けられているすべての接続でメソッドを呼び出します
Users 指定したユーザーに関連付けられているすべての接続でメソッドを呼び出します

SendAsync メソッドでは、前の表の各プロパティまたはメソッドからオブジェクトが返されます。 SendAsync メソッドを使用すると、呼び出すクライアント メソッドの名前とパラメーターを指定できます。

クライアントにメッセージを送信する

特定のクライアントに対して呼び出しを行うには、Clients オブジェクトのプロパティを使用します。 次の例には、3 つのハブ メソッドがあります。

  • SendMessage を呼び出すと、Clients.All を使用して、接続されているすべてのクライアントにメッセージが送信されます。
  • SendMessageToCaller を呼び出すと、Clients.Caller を使用して、呼び出し元にメッセージが返送されます。
  • SendMessageToGroup を呼び出すと、SignalR Users グループ内のすべてのクライアントにメッセージが送信されます。
public Task SendMessage(string user, string message)
{
    return Clients.All.SendAsync("ReceiveMessage", user, message);
}

public Task SendMessageToCaller(string user, string message)
{
    return Clients.Caller.SendAsync("ReceiveMessage", user, message);
}

public Task SendMessageToGroup(string user, string message)
{
    return Clients.Group("SignalR Users").SendAsync("ReceiveMessage", user, message);
}

厳密に型指定されたハブ

SendAsync を使用する場合の欠点は、呼び出されるクライアント メソッドを指定するのに、マジック文字列が使用されることです。 このため、メソッド名が間違って綴られていたり、クライアントに存在しなくなっていると、コードで実行時エラーが発生します。

SendAsync を使用する代わりに、Hub<T> を使用して Hub を厳密に型指定する方法もあります。 次の例では、ChatHub クライアント メソッドが IChatClient というインターフェイスに抽出されています。

public interface IChatClient
{
    Task ReceiveMessage(string user, string message);
}

このインターフェイスを使用して、前の例を ChatHub リファクタリングできます。

    public class StronglyTypedChatHub : Hub<IChatClient>
    {
        public async Task SendMessage(string user, string message)
        {
            await Clients.All.ReceiveMessage(user, message);
        }

        public Task SendMessageToCaller(string user, string message)
        {
            return Clients.Caller.ReceiveMessage(user, message);
        }
}

Hub<IChatClient> を使用すると、クライアント メソッドをコンパイル時にチェックできます。 これにより、Hub<T> では、インターフェイスで定義されたメソッドへのアクセスのみを提供できるため、マジック文字列の使用による問題を回避できます。

厳密に型指定された Hub<T> を使用すると、SendAsync は使用できなくなります。 インターフェイスで定義されているどのメソッドも、引き続き非同期として定義できます。 実際、これらの各メソッドからは Task を返す必要があります。 これはインターフェイスであるため、async キーワードを使用しないでください。 次に例を示します。

public interface IClient
{
    Task ClientMethod();
}

Note

メソッド名からは Async サフィックスが除かれていません。 クライアント メソッドが .on('MyMethodAsync') で定義されていない場合は、名前として MyMethodAsync を使用しないでください。

ハブ メソッドの名前を変更する

既定では、サーバー ハブ メソッドの名前は .NET メソッドの名前です。 ただし、HubMethodName 属性を使ってこの既定値を変更し、メソッドの名前を手動で指定することができます。 クライアントは、メソッドを呼び出すときに、.NET メソッド名の代わりにこの名前を使用する必要があります。

[HubMethodName("SendMessageToUser")]
public Task DirectMessage(string user, string message)
{
    return Clients.User(user).SendAsync("ReceiveMessage", user, message);
}

接続のイベントを処理する

SignalR Hubs API には、接続の管理と追跡のために、仮想メソッド OnConnectedAsyncOnDisconnectedAsync が用意されています。 クライアントが OnConnectedAsync ハブに接続したときにアクションを実行するように仮想メソッドをオーバーライドします (グループへの追加など)。

public override async Task OnConnectedAsync()
{
    await Groups.AddToGroupAsync(Context.ConnectionId, "SignalR Users");
    await base.OnConnectedAsync();
}

クライアントが切断するときにアクションを実行するには、OnDisconnectedAsync 仮想メソッドをオーバーライドします。 クライアントが意図的に切断された場合 (たとえば、connection.stop() を呼び出すことによって)、exception パラメーターは null になります。 ただし、エラー (ネットワーク障害など) exception が原因でクライアントが切断された場合、パラメーターにはエラーを説明する例外が含まれます。

public override async Task OnDisconnectedAsync(Exception exception)
{
    await Clients.Group("SignalR Users").SendAsync("ReceiveMessage", "I", "disconnect");
    await base.OnDisconnectedAsync(exception);
}

RemoveFromGroupAsyncOnDisconnectedAsync呼び出す必要はありません。自動的に処理されます。

警告

セキュリティ警告: ConnectionId を公開すると、サーバーまたはクライアントのバージョンが SignalR ASP.NET Core 2.2 以前である場合、偽装される可能性があります。

エラーの処理

ハブ メソッドでスローされた例外は、メソッドを呼び出したクライアントに送信されます。 JavaScript クライアントでは、このメソッドは invokeJavaScript Promiseを返します。 クライアントが、promise にアタッチされたハンドラーを使用して catchエラーを受け取ると、そのハンドラーが呼び出され、JavaScript Error オブジェクトとして渡されます。

connection.invoke("SendMessage", user, message).catch(err => console.error(err));

ハブが例外をスローした場合、接続は閉じられません。 既定では、SignalR からは一般的なエラー メッセージがクライアントに返されます。 次に例を示します。

Microsoft.AspNetCore.SignalR.HubException: An unexpected error occurred invoking 'MethodName' on the server.

予期しない例外には、データベース接続が失敗したときにトリガーされる例外でのデータベース サーバー名など、機密情報が含まれていることがよくあります。 セキュリティ対策として、SignalR では、これらの詳細なエラー メッセージは既定では公開されません。 例外の詳細が抑制される理由の詳細については、ASP.NET CoreSignalRのセキュリティに関する考慮事項を参照してください。

例外の状態をクライアントに伝える必要が "ある" 場合は、HubException クラスを使用できます。 ハブ メソッドから a をHubExceptionスローすると、SignalRメッセージ全体がクライアントに送信され、変更されません。

public Task ThrowException()
{
    throw new HubException("This error will be sent to the client!");
}

Note

SignalR によってクライアントに送信されるのは、例外の Message プロパティだけです。 スタック トレースと例外のその他のプロパティは、クライアントでは使用できません。

その他のリソース

作成者: Rachel AppelKevin Griffin

サンプル コードを表示またはダウンロードする (ダウンロード方法)

SignalR ハブとは

SignalR Hubs API を使用すると、接続されているクライアント上のメソッドをサーバーから呼び出すことができます。 サーバーのコードでは、クライアントによって呼び出されるメソッドを定義します。 クライアントのコードでは、サーバーから呼び出されるメソッドを定義します。 クライアントからサーバーおよびサーバーからクライアントへのリアルタイム通信を可能にするバックグラウンドの処理はすべて、SignalR によって行われます。

SignalR ハブを構成する

ミドルウェアには SignalR 、次の呼び出し AddSignalRによって構成される一部のサービスが必要です。

services.AddSignalR();

ASP.NET Core アプリに機能を追加SignalRする場合は、メソッドを呼び出UseSignalRしてルートをStartup.Configure設定SignalRします。

app.UseSignalR(route =>
{
    route.MapHub<ChatHub>("/chathub");
});

ハブを作成して使用する

Hub から継承するクラスを宣言してハブを作成し、それにパブリック メソッドを追加します。 クライアントは、次のように public定義されているメソッドを呼び出すことができます。

public class ChatHub : Hub
{
    public Task SendMessage(string user, string message)
    {
        return Clients.All.SendAsync("ReceiveMessage", user, message);
    }
}

C# のメソッドの場合と同様に、複合型や配列など、戻り値の型とパラメーターを指定できます。 パラメーターと戻り値の複合オブジェクトおよび配列のシリアル化と逆シリアル化は、SignalR によって処理されます。

Note

ハブは一時的なものです。

  • ハブ クラスのプロパティに状態を格納しないでください。 ハブ メソッドのすべての呼び出しは、新しいハブ インスタンスで実行されます。
  • ハブが存在し続けることに依存する非同期メソッドを呼び出すときは、await を使います。 たとえば、Clients.All.SendAsync(...) などのメソッドは、await を指定せずに呼び出し、SendAsync が終了する前にハブ メソッドが完了した場合、失敗する可能性があります。

Context オブジェクト

Hub クラスの Context プロパティには、接続に関する情報が設定される次のプロパティが含まれます。

プロパティ 説明
ConnectionId SignalR によって割り当てられる、接続の一意の ID を取得します。 接続ごとに 1 つの接続 ID があります。
UserIdentifier ユーザー識別子を取得します。 既定では、SignalR は、接続に関連付けられている ClaimsPrincipal からの ClaimTypes.NameIdentifier をユーザー識別子として使用します。
User 現在のユーザーに関連付けられている ClaimsPrincipal を取得します。
Items この接続のスコープ内でデータを共有するために使用できるキーと値のコレクションを取得します。 このコレクションにデータを格納することができ、ハブ メソッドの異なる呼び出しの間も、その接続について維持されます。
Features 接続で使用できる機能のコレクションを取得します。 現時点では、ほとんどのシナリオでこのコレクションは必要ないため、まだ詳細には記載されていません。
ConnectionAborted 接続が中止されたときに通知する CancellationToken を取得します。

Hub.Context には、次のメソッドも含まれます。

メソッド 説明
GetHttpContext 接続の HttpContext 場合、または null 接続が HTTP 要求に関連付けられていない場合に返します。 HTTP 接続の場合は、このメソッドを使って、HTTP ヘッダーやクエリ文字列などの情報を取得できます。
Abort 接続を中止します。

Clients オブジェクト

Hub クラスの Clients プロパティには、サーバーとクライアントの間の通信に関する次のプロパティが含まれます。

プロパティ 説明
All 接続されているすべてのクライアントでメソッドを呼び出します
Caller ハブ メソッドを呼び出したクライアントでメソッドを呼び出します
Others メソッドを呼び出したクライアントを除く、接続されているすべてのクライアントでメソッドを呼び出します

Hub.Clients には、次のメソッドも含まれます。

メソッド 説明
AllExcept 指定した接続を除く、接続されているすべてのクライアントでメソッドを呼び出します
Client 接続された特定の 1 つのクライアントでメソッドを呼び出します
Clients 接続された特定の複数のクライアントでメソッドを呼び出します
Group 指定したグループ内のすべての接続でメソッドを呼び出します
GroupExcept 指定した接続を除く、指定したグループ内のすべての接続でメソッドを呼び出します
Groups 複数の接続グループでメソッドを呼び出します
OthersInGroup ハブ メソッドを呼び出したクライアントを除く、接続のグループでメソッドを呼び出します
User 特定のユーザーに関連付けられているすべての接続でメソッドを呼び出します
Users 指定したユーザーに関連付けられているすべての接続でメソッドを呼び出します

SendAsync メソッドでは、前の表の各プロパティまたはメソッドからオブジェクトが返されます。 SendAsync メソッドを使用すると、呼び出すクライアント メソッドの名前とパラメーターを指定できます。

クライアントにメッセージを送信する

特定のクライアントに対して呼び出しを行うには、Clients オブジェクトのプロパティを使用します。 次の例には、3 つのハブ メソッドがあります。

  • SendMessage を呼び出すと、Clients.All を使用して、接続されているすべてのクライアントにメッセージが送信されます。
  • SendMessageToCaller を呼び出すと、Clients.Caller を使用して、呼び出し元にメッセージが返送されます。
  • SendMessageToGroup を呼び出すと、SignalR Users グループ内のすべてのクライアントにメッセージが送信されます。
public Task SendMessage(string user, string message)
{
    return Clients.All.SendAsync("ReceiveMessage", user, message);
}

public Task SendMessageToCaller(string user, string message)
{
    return Clients.Caller.SendAsync("ReceiveMessage", user, message);
}

public Task SendMessageToGroup(string user, string message)
{
    return Clients.Group("SignalR Users").SendAsync("ReceiveMessage", user, message);
}

厳密に型指定されたハブ

SendAsync を使用する場合の欠点は、呼び出されるクライアント メソッドを指定するのに、マジック文字列が使用されることです。 このため、メソッド名が間違って綴られていたり、クライアントに存在しなくなっていると、コードで実行時エラーが発生します。

SendAsync を使用する代わりに、Hub<T> を使用して Hub を厳密に型指定する方法もあります。 次の例では、ChatHub クライアント メソッドが IChatClient というインターフェイスに抽出されています。

public interface IChatClient
{
    Task ReceiveMessage(string user, string message);
}

このインターフェイスを使用して、前の例を ChatHub リファクタリングできます。

    public class StronglyTypedChatHub : Hub<IChatClient>
    {
        public async Task SendMessage(string user, string message)
        {
            await Clients.All.ReceiveMessage(user, message);
        }

        public Task SendMessageToCaller(string user, string message)
        {
            return Clients.Caller.ReceiveMessage(user, message);
        }
}

Hub<IChatClient> を使用すると、クライアント メソッドをコンパイル時にチェックできます。 これにより、Hub<T> では、インターフェイスで定義されたメソッドへのアクセスのみを提供できるため、マジック文字列の使用による問題を回避できます。

厳密に型指定された Hub<T> を使用すると、SendAsync は使用できなくなります。 インターフェイスで定義されているどのメソッドも、引き続き非同期として定義できます。 実際、これらの各メソッドからは Task を返す必要があります。 これはインターフェイスであるため、async キーワードを使用しないでください。 次に例を示します。

public interface IClient
{
    Task ClientMethod();
}

Note

メソッド名からは Async サフィックスが除かれていません。 クライアント メソッドが .on('MyMethodAsync') で定義されていない場合は、名前として MyMethodAsync を使用しないでください。

ハブ メソッドの名前を変更する

既定では、サーバー ハブ メソッドの名前は .NET メソッドの名前です。 ただし、HubMethodName 属性を使ってこの既定値を変更し、メソッドの名前を手動で指定することができます。 クライアントは、メソッドを呼び出すときに、.NET メソッド名の代わりにこの名前を使用する必要があります。

[HubMethodName("SendMessageToUser")]
public Task DirectMessage(string user, string message)
{
    return Clients.User(user).SendAsync("ReceiveMessage", user, message);
}

接続のイベントを処理する

SignalR Hubs API には、接続の管理と追跡のために、仮想メソッド OnConnectedAsyncOnDisconnectedAsync が用意されています。 クライアントが OnConnectedAsync ハブに接続したときにアクションを実行するように仮想メソッドをオーバーライドします (グループへの追加など)。

public override async Task OnConnectedAsync()
{
    await Groups.AddToGroupAsync(Context.ConnectionId, "SignalR Users");
    await base.OnConnectedAsync();
}

クライアントが切断するときにアクションを実行するには、OnDisconnectedAsync 仮想メソッドをオーバーライドします。 クライアントが意図的に切断された場合 (たとえば、connection.stop() を呼び出すことによって)、exception パラメーターは null になります。 ただし、エラー (ネットワーク障害など) exception が原因でクライアントが切断された場合、パラメーターにはエラーを説明する例外が含まれます。

public override async Task OnDisconnectedAsync(Exception exception)
{
    await Clients.Group("SignalR Users").SendAsync("ReceiveMessage", "I", "disconnect");
    await base.OnDisconnectedAsync(exception);
}

RemoveFromGroupAsyncOnDisconnectedAsync呼び出す必要はありません。自動的に処理されます。

警告

セキュリティ警告: ConnectionId を公開すると、サーバーまたはクライアントのバージョンが SignalR ASP.NET Core 2.2 以前である場合、偽装される可能性があります。

エラーの処理

ハブ メソッドでスローされた例外は、メソッドを呼び出したクライアントに送信されます。 JavaScript クライアントでは、このメソッドは invokeJavaScript Promiseを返します。 クライアントが、promise にアタッチされたハンドラーを使用して catchエラーを受け取ると、そのハンドラーが呼び出され、JavaScript Error オブジェクトとして渡されます。

connection.invoke("SendMessage", user, message).catch(err => console.error(err));

ハブが例外をスローした場合、接続は閉じられません。 既定では、SignalR からは一般的なエラー メッセージがクライアントに返されます。 次に例を示します。

Microsoft.AspNetCore.SignalR.HubException: An unexpected error occurred invoking 'MethodName' on the server.

予期しない例外には、データベース接続が失敗したときにトリガーされる例外でのデータベース サーバー名など、機密情報が含まれていることがよくあります。 セキュリティ対策として、SignalR では、これらの詳細なエラー メッセージは既定では公開されません。 例外の詳細が抑制される理由の詳細については、ASP.NET CoreSignalRのセキュリティに関する考慮事項を参照してください。

例外の状態をクライアントに伝える必要が "ある" 場合は、HubException クラスを使用できます。 ハブ メソッドから a をHubExceptionスローすると、SignalRメッセージ全体がクライアントに送信され、変更されません。

public Task ThrowException()
{
    throw new HubException("This error will be sent to the client!");
}

Note

SignalR によってクライアントに送信されるのは、例外の Message プロパティだけです。 スタック トレースと例外のその他のプロパティは、クライアントでは使用できません。

その他のリソース

作成者: Rachel AppelKevin Griffin

SignalR Hubs API を使用すると、接続されたクライアントがサーバー上のメソッドを呼び出すことができます。 サーバーはクライアントから呼び出されるメソッドを定義し、クライアントはサーバーから呼び出されるメソッドを定義します。 SignalR は、リアルタイムのクライアントとサーバー間の通信を可能にするために必要なすべての処理を行います。

SignalR ハブを構成する

ハブでSignalR必要なサービスを登録するには、次を呼び出しますAddSignalRProgram.cs

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddSignalR();

エンドポイントを構成SignalRするには、次の中でもProgram.cs呼び出しますMapHub

app.MapRazorPages();
app.MapHub<ChatHub>("/Chat");

app.Run();

ハブを作成して使用する

から継承するクラスを宣言してハブを作成します Hub。 クライアントから呼び出し可能にするメソッドをクラスに追加 public します。

public class ChatHub : Hub
{
    public async Task SendMessage(string user, string message)
        => await Clients.All.SendAsync("ReceiveMessage", user, message);
}

Note

ハブは 一時的です

  • ハブ クラスのプロパティに状態を格納しないでください。 各ハブ メソッド呼び出しは、新しいハブ インスタンスで実行されます。
  • ハブが存在し続けることに依存する非同期メソッドを呼び出すときは、await を使います。 たとえば、Clients.All.SendAsync(...) などのメソッドは、await を指定せずに呼び出し、SendAsync が終了する前にハブ メソッドが完了した場合、失敗する可能性があります。

Context オブジェクト

この Hub クラスには、接続に Context 関する情報を含む次のプロパティを含むプロパティが含まれています。

プロパティ 説明
ConnectionId SignalR によって割り当てられる、接続の一意の ID を取得します。 接続ごとに 1 つの接続 ID があります。
UserIdentifier ユーザー識別子を取得します。 既定では、SignalR は、接続に関連付けられている ClaimsPrincipal からの ClaimTypes.NameIdentifier をユーザー識別子として使用します。
User 現在のユーザーに関連付けられている ClaimsPrincipal を取得します。
Items この接続のスコープ内でデータを共有するために使用できるキーと値のコレクションを取得します。 このコレクションにデータを格納することができ、ハブ メソッドの異なる呼び出しの間も、その接続について維持されます。
Features 接続で使用できる機能のコレクションを取得します。 現時点では、ほとんどのシナリオでこのコレクションは必要ないため、まだ詳細には記載されていません。
ConnectionAborted 接続が中止されたときに通知する CancellationToken を取得します。

Hub.Context には、次のメソッドも含まれます。

メソッド 説明
GetHttpContext 接続の HttpContext 場合、または null 接続が HTTP 要求に関連付けられていない場合に返します。 HTTP 接続の場合は、このメソッドを使用して、HTTP ヘッダーやクエリ文字列などの情報を取得します。
Abort 接続を中止します。

Clients オブジェクト

この Hub クラスには、 Clients サーバーとクライアント間の通信用に次のプロパティを含むプロパティが含まれています。

プロパティ 説明
All 接続されているすべてのクライアントでメソッドを呼び出します
Caller ハブ メソッドを呼び出したクライアントでメソッドを呼び出します
Others メソッドを呼び出したクライアントを除く、接続されているすべてのクライアントでメソッドを呼び出します

Hub.Clients には、次のメソッドも含まれます。

メソッド 説明
AllExcept 指定した接続を除く、接続されているすべてのクライアントでメソッドを呼び出します
Client 接続された特定の 1 つのクライアントでメソッドを呼び出します
Clients 接続された特定の複数のクライアントでメソッドを呼び出します
Group 指定したグループ内のすべての接続でメソッドを呼び出します
GroupExcept 指定した接続を除く、指定したグループ内のすべての接続でメソッドを呼び出します
Groups 複数の接続グループでメソッドを呼び出します
OthersInGroup ハブ メソッドを呼び出したクライアントを除く、接続のグループでメソッドを呼び出します
User 特定のユーザーに関連付けられているすべての接続でメソッドを呼び出します
Users 指定したユーザーに関連付けられているすべての接続でメソッドを呼び出します

SendAsync メソッドでは、前の表の各プロパティまたはメソッドからオブジェクトが返されます。 メソッドは SendAsync 、呼び出すクライアント メソッドの名前とパラメーターを受け取ります。

およびメソッドによってClient返されるオブジェクトには、クライアントからの結果InvokeAsync待機するために使用できるメソッドも含まれています。Caller

クライアントにメッセージを送信する

特定のクライアントに対して呼び出しを行うには、Clients オブジェクトのプロパティを使用します。 次の例では、3 つのハブメソッドがあります。

  • SendMessage を呼び出すと、Clients.All を使用して、接続されているすべてのクライアントにメッセージが送信されます。
  • SendMessageToCaller を呼び出すと、Clients.Caller を使用して、呼び出し元にメッセージが返送されます。
  • SendMessageToGroup を呼び出すと、SignalR Users グループ内のすべてのクライアントにメッセージが送信されます。
public async Task SendMessage(string user, string message)
    => await Clients.All.SendAsync("ReceiveMessage", user, message);

public async Task SendMessageToCaller(string user, string message)
    => await Clients.Caller.SendAsync("ReceiveMessage", user, message);

public async Task SendMessageToGroup(string user, string message)
    => await Clients.Group("SignalR Users").SendAsync("ReceiveMessage", user, message);

厳密に型指定されたハブ

使用 SendAsync の欠点は、呼び出されるクライアント メソッドを指定するために文字列に依存することです。 このため、メソッド名が間違って綴られていたり、クライアントに存在しなくなっていると、コードで実行時エラーが発生します。

使用する別の SendAsync 方法は、クラスを厳密に型指定 Hub することです Hub<T>。 次の例では、 ChatHub クライアント メソッドが次のように呼び出 IChatClientされたインターフェイスに抽出されています。

public interface IChatClient
{
    Task ReceiveMessage(string user, string message);
}

このインターフェイスを使用して、前の例を ChatHub 厳密に型指定するようにリファクタリングできます。

public class StronglyTypedChatHub : Hub<IChatClient>
{
    public async Task SendMessage(string user, string message)
        => await Clients.All.ReceiveMessage(user, message);

    public async Task SendMessageToCaller(string user, string message)
        => await Clients.Caller.ReceiveMessage(user, message);

    public async Task SendMessageToGroup(string user, string message)
        => await Clients.Group("SignalR Users").ReceiveMessage(user, message);
}

Hub<IChatClient> を使用すると、クライアント メソッドをコンパイル時にチェックできます。 これにより、インターフェイスで定義されているメソッドにのみアクセスを提供できるため Hub<T> 、文字列の使用によって発生する問題を回避できます。 厳密に型指定された Hub<T> を使用すると、SendAsync は使用できなくなります。

Note

サフィックスは Async メソッド名から削除されません。 クライアント メソッドが定義 .on('MyMethodAsync')されていない限り、名前として使用 MyMethodAsync しないでください。

クライアントの結果

サーバーは、クライアントを呼び出すだけでなく、クライアントから結果を要求することもできます。 これには、サーバーが使用 ISingleClientProxy.InvokeAsync する必要があり、クライアントは .On ハンドラーから結果を返す必要があります。

サーバーで API を使用するには 2 つの方法があります。1 つ目は、Hub メソッドで呼び出すかCaller、プロパティをClients呼び出Client(...)す方法です。

public class ChatHub : Hub
{
    public async Task<string> WaitForMessage(string connectionId)
    {
        var message = await Clients.Client(connectionId).InvokeAsync<string>(
            "GetMessage");
        return message;
    }
}

Note

Hub メソッドから使用するには InvokeAsync 、オプションを MaximumParallelInvocationsPerClient 1 より大きい値に設定する必要があります。

これは、将来のリリースで対処される予定です。 詳しくは、 クライアント呼び出しからの値の戻り値のサポートを参照してください。

2 つ目の方法は、次のインスタンスIHubContext<T>を呼び出すClient(...)方法です。

async Task SomeMethod(IHubContext<MyHub> context)
{
    string result = await context.Clients.Client(connectionID).InvokeAsync<string>(
        "GetMessage");
}

厳密に型指定されたハブは、インターフェイス メソッドから値を返すこともできます。

public interface IClient
{
    Task<string> GetMessage();
}

public class ChatHub : Hub<IClient>
{
    public async Task<string> WaitForMessage(string connectionId)
    {
        string message = await Clients.Client(connectionId).GetMessage();
        return message;
    }
}

次に示すように、クライアントはハンドラーで結果を .On(...) 返します。

.NET クライアント

hubConnection.On("GetMessage", async () =>
{
    Console.WriteLine("Enter message:");
    var message = await Console.In.ReadLineAsync();
    return message;
});

Typescript クライアント

hubConnection.on("GetMessage", async () => {
    let promise = new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve("message");
        }, 100);
    });
    return promise;
});

Note

クライアントの結果は Azure SignalR サービスでは機能しません。

これは、将来のリリースで対処される予定です。 詳しくは、 クライアント呼び出しからの値の戻り値のサポートを参照してください。

ハブ メソッドの名前を変更する

既定では、サーバー ハブ メソッドの名前は .NET メソッドの名前です。 特定のメソッドに対するこの既定の動作を変更するには、 HubMethodName 属性を使用します。 クライアントは、メソッドを呼び出すときに、.NET メソッド名の代わりにこの名前を使用する必要があります。

[HubMethodName("SendMessageToUser")]
public async Task DirectMessage(string user, string message)
    => await Clients.User(user).SendAsync("ReceiveMessage", user, message);

ハブにサービスを挿入する

ハブ コンストラクターには DI からのサービスをパラメーターとして指定することができ、それはクラスのプロパティに格納してハブ メソッドで使用できます。

異なるハブ メソッドまたはコードを記述する別の方法として複数のサービスを挿入する場合、ハブ メソッドは DI からのサービスを受け入れることもできます。 既定では、ハブ メソッドパラメーターは、可能であれば DI から検査および解決されます。

services.AddSingleton<IDatabaseService, DatabaseServiceImpl>();

// ...

public class ChatHub : Hub
{
    public Task SendMessage(string user, string message, IDatabaseService dbService)
    {
        var userName = dbService.GetUserName(user);
        return Clients.All.SendAsync("ReceiveMessage", userName, message);
    }
}

サービスからのパラメーターの暗黙的な解決が望ましくない場合は、 DisableImplicitFromServicesParameters を使用して無効にします。 ハブ メソッドで DI から解決されるパラメーターを明示的に指定するには、このオプションをDisableImplicitFromServicesParameters使用し、DI から解決する必要があるハブ メソッド パラメーターに実装IFromServiceMetadataする属性またはカスタム属性を使用[FromServices]します。

services.AddSingleton<IDatabaseService, DatabaseServiceImpl>();
services.AddSignalR(options =>
{
    options.DisableImplicitFromServicesParameters = true;
});

// ...

public class ChatHub : Hub
{
    public Task SendMessage(string user, string message,
        [FromServices] IDatabaseService dbService)
    {
        var userName = dbService.GetUserName(user);
        return Clients.All.SendAsync("ReceiveMessage", userName, message);
    }
}

Note

この機能では、DI 実装によって必要に応じて実装される機能を使用 IServiceProviderIsServiceします。 アプリの DI コンテナーでこの機能がサポートされていない場合、ハブ メソッドへのサービスの挿入はサポートされません。

接続のイベントを処理する

SignalR Hubs API には、接続の管理と追跡のために、仮想メソッド OnConnectedAsyncOnDisconnectedAsync が用意されています。 仮想メソッドを OnConnectedAsync オーバーライドして、クライアントがハブに接続するときにアクションを実行します (グループへの追加など):

public override async Task OnConnectedAsync()
{
    await Groups.AddToGroupAsync(Context.ConnectionId, "SignalR Users");
    await base.OnConnectedAsync();
}

クライアントが切断するときにアクションを実行するには、OnDisconnectedAsync 仮想メソッドをオーバーライドします。 クライアントが呼び出しconnection.stop()exceptionなどで意図的に切断した場合、パラメーターは null. ただし、ネットワーク障害などのエラーが原因でクライアントが切断された場合、 exception このパラメーターにはエラーを記述する例外が含まれます。

public override async Task OnDisconnectedAsync(Exception? exception)
{
    await base.OnDisconnectedAsync(exception);
}

RemoveFromGroupAsyncOnDisconnectedAsync呼び出す必要はありません。自動的に処理されます。

エラーの処理

ハブ メソッドでスローされた例外は、メソッドを呼び出したクライアントに送信されます。 JavaScript クライアントでは、このメソッドは invokeJavaScript Promiseを返します。 クライアントは、catch返された Promise にハンドラーをアタッチすることも、例外を処理するために使用asyncawaittry/catch/することもできます。

try {
  await connection.invoke("SendMessage", user, message);
} catch (err) {
  console.error(err);
}

ハブが例外をスローしても、接続は閉じられません。 既定では、 SignalR 次の例に示すように、一般的なエラー メッセージをクライアントに返します。

Microsoft.AspNetCore.SignalR.HubException: An unexpected error occurred invoking 'SendMessage' on the server.

予期しない例外には、データベース接続が失敗したときにトリガーされる例外でのデータベース サーバー名など、機密情報が含まれていることがよくあります。 セキュリティ対策として、SignalR では、これらの詳細なエラー メッセージは既定では公開されません。 例外の詳細が抑制される理由の詳細については、「ASP.NET CoreSignalRのセキュリティに関する考慮事項」を参照してください。

例外的な条件をクライアントに伝達する必要がある場合は、クラスを使用します HubException 。 ハブ メソッドで a HubException がスローされた場合は、 SignalR変更されていない例外メッセージ全体をクライアントに送信します。

public Task ThrowException()
    => throw new HubException("This error will be sent to the client!");

Note

SignalR によってクライアントに送信されるのは、例外の Message プロパティだけです。 スタック トレースと例外のその他のプロパティは、クライアントでは使用できません。

その他のリソース