Używanie koncentratorów w programie SignalR dla platformy ASP.NET Core

Przez Rachel Appel i Kevin Griffin

Interfejs SignalR API usługi Hubs umożliwia połączonym klientom wywoływanie metod na serwerze. Serwer definiuje metody wywoływane z klienta, a klient definiuje metody wywoływane z serwera. SignalR dba o wszystko, co jest wymagane, aby umożliwić komunikację między klientem i klientem w czasie rzeczywistym.

Konfigurowanie SignalR koncentratorów

Aby zarejestrować usługi wymagane przez SignalR centra, wywołaj metodę AddSignalR w pliku Program.cs:

var builder = WebApplication.CreateBuilder(args);

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

Aby skonfigurować SignalR punkty końcowe, wywołaj metodę MapHub, również w pliku Program.cs:

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

app.Run();

Uwaga

zestawy ASP.NET Core SignalR po stronie serwera są teraz instalowane przy użyciu zestawu .NET Core SDK. Aby uzyskać więcej informacji, zobacz SignalR zestawy w strukturze udostępnionej .

Tworzenie centrów i korzystanie z nich

Utwórz centrum, deklarując klasę dziedziczącą z Hubklasy . Dodaj public metody do klasy, aby umożliwić ich wywoływanie z klientów:

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

Uwaga

Koncentratory są przejściowe:

  • Nie przechowuj stanu we właściwości klasy centrum. Każde wywołanie metody centrum jest wykonywane w nowym wystąpieniu centrum.
  • Nie tworzy wystąpienia koncentratora bezpośrednio za pośrednictwem wstrzykiwania zależności. Aby wysyłać komunikaty do klienta z innego miejsca w aplikacji, użyj polecenia IHubContext.
  • Użyj await funkcji podczas wywoływania metod asynchronicznych, które zależą od centrum pozostającego przy życiu. Na przykład metoda taka jak Clients.All.SendAsync(...) może zakończyć się niepowodzeniem, jeśli zostanie wywołana bez await , a metoda centrum zostanie ukończona przed zakończeniem SendAsync .

Obiekt Context

Klasa Hub zawiera właściwość zawierającą Context następujące właściwości z informacjami o połączeniu:

Właściwości opis
ConnectionId Pobiera unikatowy identyfikator połączenia przypisanego przez SignalR. Dla każdego połączenia istnieje jeden identyfikator połączenia.
UserIdentifier Pobiera identyfikator użytkownika. Domyślnie SignalR używa ClaimTypes.NameIdentifier elementu z skojarzonego ClaimsPrincipal z połączeniem jako identyfikatora użytkownika.
User ClaimsPrincipal Pobiera element skojarzony z bieżącym użytkownikiem.
Items Pobiera kolekcję klucz/wartość, która może służyć do udostępniania danych w zakresie tego połączenia. Dane mogą być przechowywane w tej kolekcji i będą utrwalane dla połączenia między różnymi wywołaniami metod centrum.
Features Pobiera kolekcję funkcji dostępnych w połączeniu. Na razie ta kolekcja nie jest potrzebna w większości scenariuszy, więc nie została jeszcze szczegółowo udokumentowana.
ConnectionAborted Pobiera element CancellationToken , który powiadamia o przerwaniu połączenia.

Hub.Context Zawiera również następujące metody:

Metoda opis
GetHttpContext HttpContext Zwraca wartość dla połączenia lub null jeśli połączenie nie jest skojarzone z żądaniem HTTP. W przypadku połączeń HTTP użyj tej metody, aby uzyskać informacje, takie jak nagłówki HTTP i ciągi zapytania.
Abort Przerywa połączenie.

Obiekt Klienci

Klasa Hub zawiera właściwość zawierającą Clients następujące właściwości komunikacji między serwerem a klientem:

Właściwości opis
All Wywołuje metodę na wszystkich połączonych klientach
Caller Wywołuje metodę na kliencie, który wywołał metodę centrum
Others Wywołuje metodę na wszystkich połączonych klientach z wyjątkiem klienta, który wywołał metodę

Hub.Clients Zawiera również następujące metody:

Metoda opis
AllExcept Wywołuje metodę na wszystkich połączonych klientach z wyjątkiem określonych połączeń
Client Wywołuje metodę na określonym połączonym kliencie
Clients Wywołuje metodę dla określonych połączonych klientów
Group Wywołuje metodę dla wszystkich połączeń w określonej grupie
GroupExcept Wywołuje metodę dla wszystkich połączeń w określonej grupie, z wyjątkiem określonych połączeń
Groups Wywołuje metodę w wielu grupach połączeń
OthersInGroup Wywołuje metodę w grupie połączeń, z wyłączeniem klienta, który wywołał metodę centrum
User Wywołuje metodę dla wszystkich połączeń skojarzonych z określonym użytkownikiem
Users Wywołuje metodę dla wszystkich połączeń skojarzonych z określonymi użytkownikami

Każda właściwość lub metoda w poprzednich tabelach zwraca obiekt z SendAsync metodą . Metoda SendAsync otrzymuje nazwę metody klienta do wywołania i wszystkich parametrów.

Obiekt zwracany przez Client metody i Caller zawiera również metodę InvokeAsync , która może służyć do oczekiwania na wynik od klienta.

Wysyłanie komunikatów do klientów

Aby wykonywać wywołania do określonych klientów, użyj właściwości Clients obiektu. W poniższym przykładzie istnieją trzy metody koncentratora:

  • SendMessage wysyła komunikat do wszystkich połączonych klientów przy użyciu polecenia Clients.All.
  • SendMessageToCaller wysyła wiadomość z powrotem do wywołującego przy użyciu polecenia Clients.Caller.
  • SendMessageToGroup wysyła komunikat do wszystkich klientów w SignalR Users grupie.
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);

Silnie typizowane koncentratory

Wadą użycia SendAsync jest to, że opiera się na ciągu, aby określić metodę klienta do wywołania. Spowoduje to pozostawienie kodu otwartego na błędy środowiska uruchomieniowego, jeśli nazwa metody jest błędnie wpisać lub brakuje jej w kliencie.

Alternatywą do użycia SendAsync jest silnie typizowanej Hub klasy za pomocą Hub<T>polecenia . W poniższym przykładzie ChatHub metoda klienta została wyodrębniona do interfejsu o nazwie IChatClient:

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

Ten interfejs może służyć do refaktoryzacji poprzedniego ChatHub przykładu, aby był silnie typowany:

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

Użycie Hub<IChatClient> umożliwia sprawdzanie czasu kompilacji metod klienta. Zapobiega to problemom spowodowanym używaniem ciągów, ponieważ Hub<T> może zapewnić dostęp tylko do metod zdefiniowanych w interfejsie. Użycie silnie typizowanego Hub<T> elementu wyłącza możliwość używania elementu SendAsync.

Uwaga

Sufiks Async nie jest usuwany z nazw metod. Chyba że metoda klienta jest zdefiniowana za .on('MyMethodAsync')pomocą metody , nie używaj MyMethodAsync jej jako nazwy.

Wyniki klienta

Oprócz wykonywania wywołań do klientów serwer może zażądać wyniku od klienta. Wymaga to, aby serwer używał ISingleClientProxy.InvokeAsync polecenia , a klient zwrócił wynik z programu .On obsługi.

Istnieją dwa sposoby używania interfejsu API na serwerze, a pierwszą metodą jest wywołanie Client(...) lub Caller na Clients właściwość w metodzie Hub:

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

Drugim sposobem jest wywołanie Client(...) wystąpienia IHubContext<T>klasy :

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

Silnie typizowane koncentratory mogą również zwracać wartości z metod interfejsu:

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

Klienci zwracają wyniki w swoich .On(...) programach obsługi, jak pokazano poniżej:

Klient .NET

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

Klient typescript

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

Klienta środowiska Java

hubConnection.onWithResult("GetMessage", () -> {
    return Single.just("message");
});

Zmienianie nazwy metody centrum

Domyślnie nazwa metody centrum serwera to nazwa metody .NET. Aby zmienić to domyślne zachowanie dla określonej metody, użyj atrybutu HubMethodName . Klient powinien użyć tej nazwy zamiast nazwy metody .NET podczas wywoływania metody:

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

Wstrzykiwanie usług do centrum

Konstruktory koncentratora mogą akceptować usługi z di jako parametry, które mogą być przechowywane we właściwościach klasy do użycia w metodzie piasty.

W przypadku wstrzykiwania wielu usług dla różnych metod centrum lub jako alternatywnego sposobu pisania kodu metody centrum mogą również akceptować usługi z di. Domyślnie parametry metody centrum są sprawdzane i rozpoznawane z di, jeśli to możliwe.

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

Jeśli nie jest wymagane niejawne rozpoznawanie parametrów z usług, wyłącz je za pomocą polecenia DisableImplicitFromServicesParameters. Aby jawnie określić, które parametry są rozpoznawane z di w metodach koncentratora, użyj opcji i użyj DisableImplicitFromServicesParameters atrybutu [FromServices] lub atrybutu niestandardowego, który implementuje IFromServiceMetadata parametry metody centrum, które powinny zostać rozpoznane z di.

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

Uwaga

Ta funkcja korzysta z IServiceProviderIsServiceelementu , który jest opcjonalnie implementowany przez implementacje di. Jeśli kontener DI aplikacji nie obsługuje tej funkcji, wstrzykiwanie usług do metod centrum nie jest obsługiwane.

Obsługa usług kluczy w iniekcji zależności

Usługi kluczy odnoszą się do mechanizmu rejestrowania i pobierania usług wstrzykiwania zależności (DI) przy użyciu kluczy. Usługa jest skojarzona z kluczem przez wywołanie AddKeyedSingleton metody (lub AddKeyedScopedAddKeyedTransient) w celu jej zarejestrowania. Uzyskaj dostęp do zarejestrowanej usługi, określając klucz za pomocą atrybutu [FromKeyedServices] . Poniższy kod pokazuje, jak używać usług kluczy:

using Microsoft.AspNetCore.SignalR;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddKeyedSingleton<ICache, BigCache>("big");
builder.Services.AddKeyedSingleton<ICache, SmallCache>("small");

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

var app = builder.Build();

app.MapRazorPages();
app.MapHub<MyHub>("/myHub");

app.Run();

public interface ICache
{
    object Get(string key);
}
public class BigCache : ICache
{
    public object Get(string key) => $"Resolving {key} from big cache.";
}

public class SmallCache : ICache
{
    public object Get(string key) => $"Resolving {key} from small cache.";
}

public class MyHub : Hub
{
    public void SmallCacheMethod([FromKeyedServices("small")] ICache cache)
    {
        Console.WriteLine(cache.Get("signalr"));
    }

    public void BigCacheMethod([FromKeyedServices("big")] ICache cache)
    {
        Console.WriteLine(cache.Get("signalr"));
    }
}

Obsługa zdarzeń dla połączenia

Interfejs SignalR API usługi Hubs udostępnia OnConnectedAsync metody i OnDisconnectedAsync wirtualne do zarządzania połączeniami i śledzenia ich. Zastąpij metodę wirtualną OnConnectedAsync , aby wykonywać akcje, gdy klient łączy się z centrum, na przykład dodając ją do grupy:

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

Zastąpij metodę wirtualną OnDisconnectedAsync , aby wykonywać akcje po rozłączeniu klienta. Jeśli klient rozłącza się celowo, na przykład przez wywołanie connection.stop()metody , exception parametr jest ustawiony na nullwartość . Jeśli jednak klient rozłącza się z powodu błędu, takiego jak awaria sieci, exception parametr zawiera wyjątek opisujący błąd:

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

RemoveFromGroupAsync nie musi być wywoływana w elemecie OnDisconnectedAsync, jest automatycznie obsługiwana.

Obsługa błędów

Wyjątki zgłaszane w metodach centrum są wysyłane do klienta, który wywołał metodę. Na kliencie invoke JavaScript metoda zwraca kod JavaScript Promise. Klienci mogą dołączyć procedurę catch obsługi do zwróconej obietnicy lub użyć polecenia try/catch w async/await celu obsługi wyjątków:

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

Połączenie nie są zamykane, gdy centrum zgłasza wyjątek. Domyślnie SignalR zwraca ogólny komunikat o błędzie do klienta, jak pokazano w poniższym przykładzie:

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

Nieoczekiwane wyjątki często zawierają poufne informacje, takie jak nazwa serwera bazy danych w wyjątku wyzwalanym w przypadku niepowodzenia połączenia z bazą danych. SignalR domyślnie nie ujawnia tych szczegółowych komunikatów o błędach jako środka zabezpieczeń. Aby uzyskać więcej informacji o tym, dlaczego szczegóły wyjątku są pomijane, zobacz Zagadnienia dotyczące zabezpieczeń w programie ASP.NET Core SignalR.

Jeśli do klienta należy propagować wyjątkowy warunek, użyj HubException klasy . Jeśli element HubException jest zgłaszany w metodzie centrum, SignalRwysyła cały komunikat o wyjątku do klienta, niezmodyfikowany:

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

Uwaga

SignalR wysyła Message tylko właściwość wyjątku do klienta. Ślad stosu i inne właściwości wyjątku nie są dostępne dla klienta.

Dodatkowe zasoby

Przez Rachel Appel i Kevin Griffin

Interfejs SignalR API usługi Hubs umożliwia połączonym klientom wywoływanie metod na serwerze. Serwer definiuje metody wywoływane z klienta, a klient definiuje metody wywoływane z serwera. SignalR dba o wszystko, co jest wymagane, aby umożliwić komunikację między klientem i klientem w czasie rzeczywistym.

Konfigurowanie SignalR koncentratorów

Aby zarejestrować usługi wymagane przez SignalR centra, wywołaj metodę AddSignalR w pliku Program.cs:

var builder = WebApplication.CreateBuilder(args);

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

Aby skonfigurować SignalR punkty końcowe, wywołaj metodę MapHub, również w pliku Program.cs:

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

app.Run();

Uwaga

zestawy ASP.NET Core SignalR po stronie serwera są teraz instalowane przy użyciu zestawu .NET Core SDK. Aby uzyskać więcej informacji, zobacz SignalR zestawy w strukturze udostępnionej .

Tworzenie centrów i korzystanie z nich

Utwórz centrum, deklarując klasę dziedziczącą z Hubklasy . Dodaj public metody do klasy, aby umożliwić ich wywoływanie z klientów:

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

Uwaga

Koncentratory są przejściowe:

  • Nie przechowuj stanu we właściwości klasy centrum. Każde wywołanie metody centrum jest wykonywane w nowym wystąpieniu centrum.
  • Nie tworzy wystąpienia koncentratora bezpośrednio za pośrednictwem wstrzykiwania zależności. Aby wysyłać komunikaty do klienta z innego miejsca w aplikacji, użyj polecenia IHubContext.
  • Użyj await funkcji podczas wywoływania metod asynchronicznych, które zależą od centrum pozostającego przy życiu. Na przykład metoda taka jak Clients.All.SendAsync(...) może zakończyć się niepowodzeniem, jeśli zostanie wywołana bez await , a metoda centrum zostanie ukończona przed zakończeniem SendAsync .

Obiekt Context

Klasa Hub zawiera właściwość zawierającą Context następujące właściwości z informacjami o połączeniu:

Właściwości opis
ConnectionId Pobiera unikatowy identyfikator połączenia przypisanego przez SignalR. Dla każdego połączenia istnieje jeden identyfikator połączenia.
UserIdentifier Pobiera identyfikator użytkownika. Domyślnie SignalR używa ClaimTypes.NameIdentifier elementu z skojarzonego ClaimsPrincipal z połączeniem jako identyfikatora użytkownika.
User ClaimsPrincipal Pobiera element skojarzony z bieżącym użytkownikiem.
Items Pobiera kolekcję klucz/wartość, która może służyć do udostępniania danych w zakresie tego połączenia. Dane mogą być przechowywane w tej kolekcji i będą utrwalane dla połączenia między różnymi wywołaniami metod centrum.
Features Pobiera kolekcję funkcji dostępnych w połączeniu. Na razie ta kolekcja nie jest potrzebna w większości scenariuszy, więc nie została jeszcze szczegółowo udokumentowana.
ConnectionAborted Pobiera element CancellationToken , który powiadamia o przerwaniu połączenia.

Hub.Context Zawiera również następujące metody:

Metoda opis
GetHttpContext HttpContext Zwraca wartość dla połączenia lub null jeśli połączenie nie jest skojarzone z żądaniem HTTP. W przypadku połączeń HTTP użyj tej metody, aby uzyskać informacje, takie jak nagłówki HTTP i ciągi zapytania.
Abort Przerywa połączenie.

Obiekt Klienci

Klasa Hub zawiera właściwość zawierającą Clients następujące właściwości komunikacji między serwerem a klientem:

Właściwości opis
All Wywołuje metodę na wszystkich połączonych klientach
Caller Wywołuje metodę na kliencie, który wywołał metodę centrum
Others Wywołuje metodę na wszystkich połączonych klientach z wyjątkiem klienta, który wywołał metodę

Hub.Clients Zawiera również następujące metody:

Metoda opis
AllExcept Wywołuje metodę na wszystkich połączonych klientach z wyjątkiem określonych połączeń
Client Wywołuje metodę na określonym połączonym kliencie
Clients Wywołuje metodę dla określonych połączonych klientów
Group Wywołuje metodę dla wszystkich połączeń w określonej grupie
GroupExcept Wywołuje metodę dla wszystkich połączeń w określonej grupie, z wyjątkiem określonych połączeń
Groups Wywołuje metodę w wielu grupach połączeń
OthersInGroup Wywołuje metodę w grupie połączeń, z wyłączeniem klienta, który wywołał metodę centrum
User Wywołuje metodę dla wszystkich połączeń skojarzonych z określonym użytkownikiem
Users Wywołuje metodę dla wszystkich połączeń skojarzonych z określonymi użytkownikami

Każda właściwość lub metoda w poprzednich tabelach zwraca obiekt z SendAsync metodą . Metoda SendAsync otrzymuje nazwę metody klienta do wywołania i wszystkich parametrów.

Obiekt zwracany przez Client metody i Caller zawiera również metodę InvokeAsync , która może służyć do oczekiwania na wynik od klienta.

Wysyłanie komunikatów do klientów

Aby wykonywać wywołania do określonych klientów, użyj właściwości Clients obiektu. W poniższym przykładzie istnieją trzy metody koncentratora:

  • SendMessage wysyła komunikat do wszystkich połączonych klientów przy użyciu polecenia Clients.All.
  • SendMessageToCaller wysyła wiadomość z powrotem do wywołującego przy użyciu polecenia Clients.Caller.
  • SendMessageToGroup wysyła komunikat do wszystkich klientów w SignalR Users grupie.
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);

Silnie typizowane koncentratory

Wadą użycia SendAsync jest to, że opiera się na ciągu, aby określić metodę klienta do wywołania. Spowoduje to pozostawienie kodu otwartego na błędy środowiska uruchomieniowego, jeśli nazwa metody jest błędnie wpisać lub brakuje jej w kliencie.

Alternatywą do użycia SendAsync jest silnie typizowanej Hub klasy za pomocą Hub<T>polecenia . W poniższym przykładzie ChatHub metoda klienta została wyodrębniona do interfejsu o nazwie IChatClient:

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

Ten interfejs może służyć do refaktoryzacji poprzedniego ChatHub przykładu, aby był silnie typowany:

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

Użycie Hub<IChatClient> umożliwia sprawdzanie czasu kompilacji metod klienta. Zapobiega to problemom spowodowanym używaniem ciągów, ponieważ Hub<T> może zapewnić dostęp tylko do metod zdefiniowanych w interfejsie. Użycie silnie typizowanego Hub<T> elementu wyłącza możliwość używania elementu SendAsync.

Uwaga

Sufiks Async nie jest usuwany z nazw metod. Chyba że metoda klienta jest zdefiniowana za .on('MyMethodAsync')pomocą metody , nie używaj MyMethodAsync jej jako nazwy.

Wyniki klienta

Oprócz wykonywania wywołań do klientów serwer może zażądać wyniku od klienta. Wymaga to, aby serwer używał ISingleClientProxy.InvokeAsync polecenia , a klient zwrócił wynik z programu .On obsługi.

Istnieją dwa sposoby używania interfejsu API na serwerze, a pierwszą metodą jest wywołanie Client(...) lub Caller na Clients właściwość w metodzie Hub:

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

Drugim sposobem jest wywołanie Client(...) wystąpienia IHubContext<T>klasy :

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

Silnie typizowane koncentratory mogą również zwracać wartości z metod interfejsu:

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

Klienci zwracają wyniki w swoich .On(...) programach obsługi, jak pokazano poniżej:

Klient .NET

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

Klient typescript

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

Klienta środowiska Java

hubConnection.onWithResult("GetMessage", () -> {
    return Single.just("message");
});

Zmienianie nazwy metody centrum

Domyślnie nazwa metody centrum serwera to nazwa metody .NET. Aby zmienić to domyślne zachowanie dla określonej metody, użyj atrybutu HubMethodName . Klient powinien użyć tej nazwy zamiast nazwy metody .NET podczas wywoływania metody:

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

Wstrzykiwanie usług do centrum

Konstruktory koncentratora mogą akceptować usługi z di jako parametry, które mogą być przechowywane we właściwościach klasy do użycia w metodzie piasty.

W przypadku wstrzykiwania wielu usług dla różnych metod centrum lub jako alternatywnego sposobu pisania kodu metody centrum mogą również akceptować usługi z di. Domyślnie parametry metody centrum są sprawdzane i rozpoznawane z di, jeśli to możliwe.

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

Jeśli nie jest wymagane niejawne rozpoznawanie parametrów z usług, wyłącz je za pomocą polecenia DisableImplicitFromServicesParameters. Aby jawnie określić, które parametry są rozpoznawane z di w metodach koncentratora, użyj opcji i użyj DisableImplicitFromServicesParameters atrybutu [FromServices] lub atrybutu niestandardowego, który implementuje IFromServiceMetadata parametry metody centrum, które powinny zostać rozpoznane z di.

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

Uwaga

Ta funkcja korzysta z IServiceProviderIsServiceelementu , który jest opcjonalnie implementowany przez implementacje di. Jeśli kontener DI aplikacji nie obsługuje tej funkcji, wstrzykiwanie usług do metod centrum nie jest obsługiwane.

Obsługa zdarzeń dla połączenia

Interfejs SignalR API usługi Hubs udostępnia OnConnectedAsync metody i OnDisconnectedAsync wirtualne do zarządzania połączeniami i śledzenia ich. Zastąpij metodę wirtualną OnConnectedAsync , aby wykonywać akcje, gdy klient łączy się z centrum, na przykład dodając ją do grupy:

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

Zastąpij metodę wirtualną OnDisconnectedAsync , aby wykonywać akcje po rozłączeniu klienta. Jeśli klient rozłącza się celowo, na przykład przez wywołanie connection.stop()metody , exception parametr jest ustawiony na nullwartość . Jeśli jednak klient rozłącza się z powodu błędu, takiego jak awaria sieci, exception parametr zawiera wyjątek opisujący błąd:

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

RemoveFromGroupAsync nie musi być wywoływana w elemecie OnDisconnectedAsync, jest automatycznie obsługiwana.

Obsługa błędów

Wyjątki zgłaszane w metodach centrum są wysyłane do klienta, który wywołał metodę. Na kliencie invoke JavaScript metoda zwraca kod JavaScript Promise. Klienci mogą dołączyć procedurę catch obsługi do zwróconej obietnicy lub użyć polecenia try/catch w async/await celu obsługi wyjątków:

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

Połączenie nie są zamykane, gdy centrum zgłasza wyjątek. Domyślnie SignalR zwraca ogólny komunikat o błędzie do klienta, jak pokazano w poniższym przykładzie:

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

Nieoczekiwane wyjątki często zawierają poufne informacje, takie jak nazwa serwera bazy danych w wyjątku wyzwalanym w przypadku niepowodzenia połączenia z bazą danych. SignalR domyślnie nie ujawnia tych szczegółowych komunikatów o błędach jako środka zabezpieczeń. Aby uzyskać więcej informacji o tym, dlaczego szczegóły wyjątku są pomijane, zobacz Zagadnienia dotyczące zabezpieczeń w programie ASP.NET Core SignalR.

Jeśli do klienta należy propagować wyjątkowy warunek, użyj HubException klasy . Jeśli element HubException jest zgłaszany w metodzie centrum, SignalRwysyła cały komunikat o wyjątku do klienta, niezmodyfikowany:

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

Uwaga

SignalR wysyła Message tylko właściwość wyjątku do klienta. Ślad stosu i inne właściwości wyjątku nie są dostępne dla klienta.

Dodatkowe zasoby

Przez Rachel Appel i Kevin Griffin

Interfejs SignalR API usługi Hubs umożliwia połączonym klientom wywoływanie metod na serwerze. Serwer definiuje metody wywoływane z klienta, a klient definiuje metody wywoływane z serwera. SignalR dba o wszystko, co jest wymagane, aby umożliwić komunikację między klientem i klientem w czasie rzeczywistym.

Konfigurowanie SignalR koncentratorów

Aby zarejestrować usługi wymagane przez SignalR centra, wywołaj metodę AddSignalR w pliku Program.cs:

var builder = WebApplication.CreateBuilder(args);

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

Aby skonfigurować SignalR punkty końcowe, wywołaj metodę MapHub, również w pliku Program.cs:

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

app.Run();

Uwaga

zestawy ASP.NET Core SignalR po stronie serwera są teraz instalowane przy użyciu zestawu .NET Core SDK. Aby uzyskać więcej informacji, zobacz SignalR zestawy w strukturze udostępnionej .

Tworzenie centrów i korzystanie z nich

Utwórz centrum, deklarując klasę dziedziczącą z Hubklasy . Dodaj public metody do klasy, aby umożliwić ich wywoływanie z klientów:

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

Uwaga

Koncentratory są przejściowe:

  • Nie przechowuj stanu we właściwości klasy centrum. Każde wywołanie metody centrum jest wykonywane w nowym wystąpieniu centrum.
  • Nie tworzy wystąpienia koncentratora bezpośrednio za pośrednictwem wstrzykiwania zależności. Aby wysyłać komunikaty do klienta z innego miejsca w aplikacji, użyj polecenia IHubContext.
  • Użyj await funkcji podczas wywoływania metod asynchronicznych, które zależą od centrum pozostającego przy życiu. Na przykład metoda taka jak Clients.All.SendAsync(...) może zakończyć się niepowodzeniem, jeśli zostanie wywołana bez await , a metoda centrum zostanie ukończona przed zakończeniem SendAsync .

Obiekt Context

Klasa Hub zawiera właściwość zawierającą Context następujące właściwości z informacjami o połączeniu:

Właściwości opis
ConnectionId Pobiera unikatowy identyfikator połączenia przypisanego przez SignalR. Dla każdego połączenia istnieje jeden identyfikator połączenia.
UserIdentifier Pobiera identyfikator użytkownika. Domyślnie SignalR używa ClaimTypes.NameIdentifier elementu z skojarzonego ClaimsPrincipal z połączeniem jako identyfikatora użytkownika.
User ClaimsPrincipal Pobiera element skojarzony z bieżącym użytkownikiem.
Items Pobiera kolekcję klucz/wartość, która może służyć do udostępniania danych w zakresie tego połączenia. Dane mogą być przechowywane w tej kolekcji i będą utrwalane dla połączenia między różnymi wywołaniami metod centrum.
Features Pobiera kolekcję funkcji dostępnych w połączeniu. Na razie ta kolekcja nie jest potrzebna w większości scenariuszy, więc nie została jeszcze szczegółowo udokumentowana.
ConnectionAborted Pobiera element CancellationToken , który powiadamia o przerwaniu połączenia.

Hub.Context Zawiera również następujące metody:

Metoda opis
GetHttpContext HttpContext Zwraca wartość dla połączenia lub null jeśli połączenie nie jest skojarzone z żądaniem HTTP. W przypadku połączeń HTTP użyj tej metody, aby uzyskać informacje, takie jak nagłówki HTTP i ciągi zapytania.
Abort Przerywa połączenie.

Obiekt Klienci

Klasa Hub zawiera właściwość zawierającą Clients następujące właściwości komunikacji między serwerem a klientem:

Właściwości opis
All Wywołuje metodę na wszystkich połączonych klientach
Caller Wywołuje metodę na kliencie, który wywołał metodę centrum
Others Wywołuje metodę na wszystkich połączonych klientach z wyjątkiem klienta, który wywołał metodę

Hub.Clients Zawiera również następujące metody:

Metoda opis
AllExcept Wywołuje metodę na wszystkich połączonych klientach z wyjątkiem określonych połączeń
Client Wywołuje metodę na określonym połączonym kliencie
Clients Wywołuje metodę dla określonych połączonych klientów
Group Wywołuje metodę dla wszystkich połączeń w określonej grupie
GroupExcept Wywołuje metodę dla wszystkich połączeń w określonej grupie, z wyjątkiem określonych połączeń
Groups Wywołuje metodę w wielu grupach połączeń
OthersInGroup Wywołuje metodę w grupie połączeń, z wyłączeniem klienta, który wywołał metodę centrum
User Wywołuje metodę dla wszystkich połączeń skojarzonych z określonym użytkownikiem
Users Wywołuje metodę dla wszystkich połączeń skojarzonych z określonymi użytkownikami

Każda właściwość lub metoda w poprzednich tabelach zwraca obiekt z SendAsync metodą . Metoda SendAsync otrzymuje nazwę metody klienta do wywołania i wszystkich parametrów.

Wysyłanie komunikatów do klientów

Aby wykonywać wywołania do określonych klientów, użyj właściwości Clients obiektu. W poniższym przykładzie istnieją trzy metody koncentratora:

  • SendMessage wysyła komunikat do wszystkich połączonych klientów przy użyciu polecenia Clients.All.
  • SendMessageToCaller wysyła wiadomość z powrotem do wywołującego przy użyciu polecenia Clients.Caller.
  • SendMessageToGroup wysyła komunikat do wszystkich klientów w SignalR Users grupie.
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);

Silnie typizowane koncentratory

Wadą użycia SendAsync jest to, że opiera się na ciągu, aby określić metodę klienta do wywołania. Spowoduje to pozostawienie kodu otwartego na błędy środowiska uruchomieniowego, jeśli nazwa metody jest błędnie wpisać lub brakuje jej w kliencie.

Alternatywą do użycia SendAsync jest silnie typizowanej Hub klasy za pomocą Hub<T>polecenia . W poniższym przykładzie ChatHub metoda klienta została wyodrębniona do interfejsu o nazwie IChatClient:

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

Ten interfejs może służyć do refaktoryzacji poprzedniego ChatHub przykładu, aby był silnie typowany:

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

Użycie Hub<IChatClient> umożliwia sprawdzanie czasu kompilacji metod klienta. Zapobiega to problemom spowodowanym używaniem ciągów, ponieważ Hub<T> może zapewnić dostęp tylko do metod zdefiniowanych w interfejsie. Użycie silnie typizowanego Hub<T> elementu wyłącza możliwość używania elementu SendAsync.

Uwaga

Sufiks Async nie jest usuwany z nazw metod. Chyba że metoda klienta jest zdefiniowana za .on('MyMethodAsync')pomocą metody , nie używaj MyMethodAsync jej jako nazwy.

Zmienianie nazwy metody centrum

Domyślnie nazwa metody centrum serwera to nazwa metody .NET. Aby zmienić to domyślne zachowanie dla określonej metody, użyj atrybutu HubMethodName . Klient powinien użyć tej nazwy zamiast nazwy metody .NET podczas wywoływania metody:

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

Obsługa zdarzeń dla połączenia

Interfejs SignalR API usługi Hubs udostępnia OnConnectedAsync metody i OnDisconnectedAsync wirtualne do zarządzania połączeniami i śledzenia ich. Zastąpij metodę wirtualną OnConnectedAsync , aby wykonywać akcje, gdy klient łączy się z centrum, na przykład dodając ją do grupy:

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

Zastąpij metodę wirtualną OnDisconnectedAsync , aby wykonywać akcje po rozłączeniu klienta. Jeśli klient rozłącza się celowo, na przykład przez wywołanie connection.stop()metody , exception parametr jest ustawiony na nullwartość . Jeśli jednak klient rozłącza się z powodu błędu, takiego jak awaria sieci, exception parametr zawiera wyjątek opisujący błąd:

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

RemoveFromGroupAsync nie musi być wywoływana w elemecie OnDisconnectedAsync, jest automatycznie obsługiwana.

Obsługa błędów

Wyjątki zgłaszane w metodach centrum są wysyłane do klienta, który wywołał metodę. Na kliencie invoke JavaScript metoda zwraca kod JavaScript Promise. Klienci mogą dołączyć procedurę catch obsługi do zwróconej obietnicy lub użyć polecenia try/catch w async/await celu obsługi wyjątków:

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

Połączenie nie są zamykane, gdy centrum zgłasza wyjątek. Domyślnie SignalR zwraca ogólny komunikat o błędzie do klienta, jak pokazano w poniższym przykładzie:

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

Nieoczekiwane wyjątki często zawierają poufne informacje, takie jak nazwa serwera bazy danych w wyjątku wyzwalanym w przypadku niepowodzenia połączenia z bazą danych. SignalR domyślnie nie ujawnia tych szczegółowych komunikatów o błędach jako środka zabezpieczeń. Aby uzyskać więcej informacji o tym, dlaczego szczegóły wyjątku są pomijane, zobacz Zagadnienia dotyczące zabezpieczeń w programie ASP.NET Core SignalR.

Jeśli do klienta należy propagować wyjątkowy warunek, użyj HubException klasy . Jeśli element HubException jest zgłaszany w metodzie centrum, SignalRwysyła cały komunikat o wyjątku do klienta, niezmodyfikowany:

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

Uwaga

SignalR wysyła Message tylko właściwość wyjątku do klienta. Ślad stosu i inne właściwości wyjątku nie są dostępne dla klienta.

Dodatkowe zasoby

Przez Rachel Appel i Kevin Griffin

Wyświetlanie lub pobieranie przykładowego kodu (jak pobrać)

Co to jest SignalR koncentrator

Interfejs SignalR API usługi Hubs umożliwia wywoływanie metod na połączonych klientach z serwera. W kodzie serwera definiuje się metody wywoływane przez klienta. W kodzie klienta definiuje się metody wywoływane z serwera. SignalR Dba o wszystko, co za kulisami sprawia, że komunikacja klient-klient-serwer i klient w czasie rzeczywistym jest możliwa.

Konfigurowanie SignalR koncentratorów

Oprogramowanie SignalR pośredniczące wymaga niektórych usług, które są konfigurowane przez wywołanie metody AddSignalR:

services.AddSignalR();

Podczas dodawania SignalR funkcji do aplikacji ASP.NET Core skonfiguruj SignalR trasy przez wywołanie MapHubStartup.Configure zwrotne metody UseEndpoints :

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

Uwaga

zestawy ASP.NET Core SignalR po stronie serwera są teraz instalowane przy użyciu zestawu .NET Core SDK. Aby uzyskać więcej informacji, zobacz SignalR zestawy w strukturze udostępnionej .

Tworzenie centrów i korzystanie z nich

Utwórz centrum, deklarując klasę dziedziczącą z Hubklasy i dodając do niej metody publiczne. Klienci mogą wywoływać metody zdefiniowane jako public:

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

Można określić typ i parametry zwracane, w tym typy złożone i tablice, tak jak w dowolnej metodzie języka C#. SignalR obsługuje serializacji i deserializacji złożonych obiektów i tablic w parametrach i zwracanych wartościach.

Uwaga

Koncentratory są przejściowe:

  • Nie przechowuj stanu we właściwości w klasie centrum. Każde wywołanie metody centrum jest wykonywane w nowym wystąpieniu centrum.
  • Nie tworzy wystąpienia koncentratora bezpośrednio za pośrednictwem wstrzykiwania zależności. Aby wysyłać komunikaty do klienta z innego miejsca w aplikacji, użyj polecenia IHubContext.
  • Użyj await funkcji podczas wywoływania metod asynchronicznych, które zależą od centrum pozostającego przy życiu. Na przykład metoda taka jak Clients.All.SendAsync(...) może zakończyć się niepowodzeniem, jeśli zostanie wywołana bez await , a metoda centrum zostanie ukończona przed zakończeniem SendAsync .

Obiekt Context

Klasa Hub ma właściwość zawierającą Context następujące właściwości z informacjami o połączeniu:

Właściwości opis
ConnectionId Pobiera unikatowy identyfikator połączenia przypisanego przez SignalR. Dla każdego połączenia istnieje jeden identyfikator połączenia.
UserIdentifier Pobiera identyfikator użytkownika. Domyślnie SignalR używa ClaimTypes.NameIdentifier elementu z skojarzonego ClaimsPrincipal z połączeniem jako identyfikatora użytkownika.
User ClaimsPrincipal Pobiera element skojarzony z bieżącym użytkownikiem.
Items Pobiera kolekcję klucz/wartość, która może służyć do udostępniania danych w zakresie tego połączenia. Dane mogą być przechowywane w tej kolekcji i będą utrwalane dla połączenia między różnymi wywołaniami metod centrum.
Features Pobiera kolekcję funkcji dostępnych w połączeniu. Na razie ta kolekcja nie jest potrzebna w większości scenariuszy, więc nie została jeszcze szczegółowo udokumentowana.
ConnectionAborted Pobiera element CancellationToken , który powiadamia o przerwaniu połączenia.

Hub.Context Zawiera również następujące metody:

Metoda opis
GetHttpContext HttpContext Zwraca wartość dla połączenia lub null jeśli połączenie nie jest skojarzone z żądaniem HTTP. W przypadku połączeń HTTP można użyć tej metody, aby uzyskać informacje, takie jak nagłówki HTTP i ciągi zapytania.
Abort Przerywa połączenie.

Obiekt Klienci

Klasa Hub ma właściwość zawierającą Clients następujące właściwości komunikacji między serwerem a klientem:

Właściwości opis
All Wywołuje metodę na wszystkich połączonych klientach
Caller Wywołuje metodę na kliencie, który wywołał metodę centrum
Others Wywołuje metodę na wszystkich połączonych klientach z wyjątkiem klienta, który wywołał metodę

Hub.Clients Zawiera również następujące metody:

Metoda opis
AllExcept Wywołuje metodę na wszystkich połączonych klientach z wyjątkiem określonych połączeń
Client Wywołuje metodę na określonym połączonym kliencie
Clients Wywołuje metodę dla określonych połączonych klientów
Group Wywołuje metodę dla wszystkich połączeń w określonej grupie
GroupExcept Wywołuje metodę dla wszystkich połączeń w określonej grupie, z wyjątkiem określonych połączeń
Groups Wywołuje metodę w wielu grupach połączeń
OthersInGroup Wywołuje metodę w grupie połączeń, z wyłączeniem klienta, który wywołał metodę centrum
User Wywołuje metodę dla wszystkich połączeń skojarzonych z określonym użytkownikiem
Users Wywołuje metodę dla wszystkich połączeń skojarzonych z określonymi użytkownikami

Każda właściwość lub metoda w poprzednich tabelach zwraca obiekt z SendAsync metodą . Metoda SendAsync umożliwia podanie nazwy i parametrów metody klienta do wywołania.

Wysyłanie komunikatów do klientów

Aby wykonywać wywołania do określonych klientów, użyj właściwości Clients obiektu. W poniższym przykładzie istnieją trzy metody koncentratora:

  • SendMessage wysyła komunikat do wszystkich połączonych klientów przy użyciu polecenia Clients.All.
  • SendMessageToCaller wysyła wiadomość z powrotem do wywołującego przy użyciu polecenia Clients.Caller.
  • SendMessageToGroup wysyła komunikat do wszystkich klientów w SignalR Users grupie.
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);
}

Silnie typizowane koncentratory

Wadą użycia SendAsync jest to, że opiera się na ciągu magicznym, aby określić metodę klienta do wywołania. Spowoduje to pozostawienie kodu otwartego na błędy środowiska uruchomieniowego, jeśli nazwa metody jest błędnie wpisać lub brakuje jej w kliencie.

Alternatywą do użycia SendAsync jest silnie typizowane za Hub pomocą Hub<T>polecenia . W poniższym przykładzie ChatHub metody klienta zostały wyodrębnione do interfejsu o nazwie IChatClient.

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

Ten interfejs może służyć do refaktoryzacji poprzedniego ChatHub przykładu:

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

Użycie Hub<IChatClient> umożliwia sprawdzanie czasu kompilacji metod klienta. Zapobiega to problemom spowodowanym używaniem ciągów magicznych, ponieważ Hub<T> może zapewnić dostęp tylko do metod zdefiniowanych w interfejsie.

Użycie silnie typizowanego Hub<T> elementu wyłącza możliwość używania elementu SendAsync. Wszystkie metody zdefiniowane w interfejsie mogą być nadal definiowane jako asynchroniczne. W rzeczywistości każda z tych metod powinna zwrócić wartość Task. Ponieważ jest to interfejs, nie używaj słowa kluczowego async . Na przykład:

public interface IClient
{
    Task ClientMethod();
}

Uwaga

Sufiks Async nie jest usuwany z nazwy metody. Jeśli metoda klienta nie jest zdefiniowana za pomocą .on('MyMethodAsync')metody , nie należy używać MyMethodAsync jej jako nazwy.

Zmienianie nazwy metody centrum

Domyślnie nazwa metody centrum serwera to nazwa metody .NET. Można jednak użyć atrybutu HubMethodName , aby zmienić to ustawienie domyślne i ręcznie określić nazwę metody. Klient powinien użyć tej nazwy zamiast nazwy metody .NET podczas wywoływania metody:

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

Obsługa zdarzeń dla połączenia

Interfejs SignalR API usługi Hubs udostępnia OnConnectedAsync metody i OnDisconnectedAsync wirtualne do zarządzania połączeniami i śledzenia ich. Zastąpij metodę wirtualną OnConnectedAsync , aby wykonywać akcje, gdy klient łączy się z centrum, na przykład dodając ją do grupy:

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

Zastąpij metodę wirtualną OnDisconnectedAsync , aby wykonywać akcje po rozłączeniu klienta. Jeśli klient rozłącza się celowo (wywołując connection.stop()na przykład exception , parametr będzie mieć nullwartość . Jeśli jednak klient zostanie rozłączony z powodu błędu (takiego jak awaria sieci), exception parametr będzie zawierać wyjątek opisujący błąd:

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

RemoveFromGroupAsync nie musi być wywoływana w elemecie OnDisconnectedAsync, jest automatycznie obsługiwana.

Ostrzeżenie

Ostrzeżenie o zabezpieczeniach: Ujawnienie ConnectionId może prowadzić do podszywania się pod złośliwy, jeśli SignalR serwer lub wersja klienta jest ASP.NET Core 2.2 lub starsze.

Obsługa błędów

Wyjątki zgłaszane w metodach centrum są wysyłane do klienta, który wywołał metodę. Na kliencie invoke JavaScript metoda zwraca kod JavaScript Promise. Gdy klient otrzymuje błąd z procedurą obsługi dołączoną do obietnicy przy użyciu metody catch, jest wywoływany i przekazywany jako obiekt JavaScript Error :

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

Jeśli centrum zgłasza wyjątek, połączenia nie są zamykane. Domyślnie SignalR zwraca ogólny komunikat o błędzie do klienta. Na przykład:

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

Nieoczekiwane wyjątki często zawierają poufne informacje, takie jak nazwa serwera bazy danych w wyjątku wyzwalanym w przypadku niepowodzenia połączenia z bazą danych. SignalR domyślnie nie ujawnia tych szczegółowych komunikatów o błędach jako środka zabezpieczeń. Aby uzyskać więcej informacji o tym, dlaczego szczegóły wyjątku są pomijane, zobacz Zagadnienia dotyczące zabezpieczeń w programie ASP.NET Core SignalR.

Jeśli masz wyjątkowy warunek, który chcesz propagować do klienta, możesz użyć HubException klasy . W przypadku zgłoszenia HubException z metody SignalRcentrum cały komunikat zostanie wysłany do klienta, niezmodyfikowany:

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

Uwaga

SignalR wysyła Message tylko właściwość wyjątku do klienta. Ślad stosu i inne właściwości wyjątku nie są dostępne dla klienta.

Dodatkowe zasoby

Przez Rachel Appel i Kevin Griffin

Wyświetlanie lub pobieranie przykładowego kodu (jak pobrać)

Co to jest SignalR koncentrator

Interfejs SignalR API usługi Hubs umożliwia wywoływanie metod na połączonych klientach z serwera. W kodzie serwera definiuje się metody wywoływane przez klienta. W kodzie klienta definiuje się metody wywoływane z serwera. SignalR Dba o wszystko, co za kulisami sprawia, że komunikacja klient-klient-serwer i klient w czasie rzeczywistym jest możliwa.

Konfigurowanie SignalR koncentratorów

Oprogramowanie SignalR pośredniczące wymaga niektórych usług, które są konfigurowane przez wywołanie metody AddSignalR:

services.AddSignalR();

Podczas dodawania SignalR funkcji do aplikacji ASP.NET Core skonfiguruj SignalR trasy przez wywołanie UseSignalR metody :Startup.Configure

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

Tworzenie centrów i korzystanie z nich

Utwórz centrum, deklarując klasę dziedziczącą z Hubklasy i dodając do niej metody publiczne. Klienci mogą wywoływać metody zdefiniowane jako public:

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

Można określić typ i parametry zwracane, w tym typy złożone i tablice, tak jak w dowolnej metodzie języka C#. SignalR obsługuje serializacji i deserializacji złożonych obiektów i tablic w parametrach i zwracanych wartościach.

Uwaga

Koncentratory są przejściowe:

  • Nie przechowuj stanu we właściwości w klasie centrum. Każde wywołanie metody centrum jest wykonywane w nowym wystąpieniu centrum.
  • Nie tworzy wystąpienia koncentratora bezpośrednio za pośrednictwem wstrzykiwania zależności. Aby wysyłać komunikaty do klienta z innego miejsca w aplikacji, użyj polecenia IHubContext.
  • Użyj await funkcji podczas wywoływania metod asynchronicznych, które zależą od centrum pozostającego przy życiu. Na przykład metoda taka jak Clients.All.SendAsync(...) może zakończyć się niepowodzeniem, jeśli zostanie wywołana bez await , a metoda centrum zostanie ukończona przed zakończeniem SendAsync .

Obiekt Context

Klasa Hub ma właściwość zawierającą Context następujące właściwości z informacjami o połączeniu:

Właściwości opis
ConnectionId Pobiera unikatowy identyfikator połączenia przypisanego przez SignalR. Dla każdego połączenia istnieje jeden identyfikator połączenia.
UserIdentifier Pobiera identyfikator użytkownika. Domyślnie SignalR używa ClaimTypes.NameIdentifier elementu z skojarzonego ClaimsPrincipal z połączeniem jako identyfikatora użytkownika.
User ClaimsPrincipal Pobiera element skojarzony z bieżącym użytkownikiem.
Items Pobiera kolekcję klucz/wartość, która może służyć do udostępniania danych w zakresie tego połączenia. Dane mogą być przechowywane w tej kolekcji i będą utrwalane dla połączenia między różnymi wywołaniami metod centrum.
Features Pobiera kolekcję funkcji dostępnych w połączeniu. Na razie ta kolekcja nie jest potrzebna w większości scenariuszy, więc nie została jeszcze szczegółowo udokumentowana.
ConnectionAborted Pobiera element CancellationToken , który powiadamia o przerwaniu połączenia.

Hub.Context Zawiera również następujące metody:

Metoda opis
GetHttpContext HttpContext Zwraca wartość dla połączenia lub null jeśli połączenie nie jest skojarzone z żądaniem HTTP. W przypadku połączeń HTTP można użyć tej metody, aby uzyskać informacje, takie jak nagłówki HTTP i ciągi zapytania.
Abort Przerywa połączenie.

Obiekt Klienci

Klasa Hub ma właściwość zawierającą Clients następujące właściwości komunikacji między serwerem a klientem:

Właściwości opis
All Wywołuje metodę na wszystkich połączonych klientach
Caller Wywołuje metodę na kliencie, który wywołał metodę centrum
Others Wywołuje metodę na wszystkich połączonych klientach z wyjątkiem klienta, który wywołał metodę

Hub.Clients Zawiera również następujące metody:

Metoda opis
AllExcept Wywołuje metodę na wszystkich połączonych klientach z wyjątkiem określonych połączeń
Client Wywołuje metodę na określonym połączonym kliencie
Clients Wywołuje metodę dla określonych połączonych klientów
Group Wywołuje metodę dla wszystkich połączeń w określonej grupie
GroupExcept Wywołuje metodę dla wszystkich połączeń w określonej grupie, z wyjątkiem określonych połączeń
Groups Wywołuje metodę w wielu grupach połączeń
OthersInGroup Wywołuje metodę w grupie połączeń, z wyłączeniem klienta, który wywołał metodę centrum
User Wywołuje metodę dla wszystkich połączeń skojarzonych z określonym użytkownikiem
Users Wywołuje metodę dla wszystkich połączeń skojarzonych z określonymi użytkownikami

Każda właściwość lub metoda w poprzednich tabelach zwraca obiekt z SendAsync metodą . Metoda SendAsync umożliwia podanie nazwy i parametrów metody klienta do wywołania.

Wysyłanie komunikatów do klientów

Aby wykonywać wywołania do określonych klientów, użyj właściwości Clients obiektu. W poniższym przykładzie istnieją trzy metody koncentratora:

  • SendMessage wysyła komunikat do wszystkich połączonych klientów przy użyciu polecenia Clients.All.
  • SendMessageToCaller wysyła wiadomość z powrotem do wywołującego przy użyciu polecenia Clients.Caller.
  • SendMessageToGroup wysyła komunikat do wszystkich klientów w SignalR Users grupie.
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);
}

Silnie typizowane koncentratory

Wadą użycia SendAsync jest to, że opiera się na ciągu magicznym, aby określić metodę klienta do wywołania. Spowoduje to pozostawienie kodu otwartego na błędy środowiska uruchomieniowego, jeśli nazwa metody jest błędnie wpisać lub brakuje jej w kliencie.

Alternatywą do użycia SendAsync jest silnie typizowane za Hub pomocą Hub<T>polecenia . W poniższym przykładzie ChatHub metody klienta zostały wyodrębnione do interfejsu o nazwie IChatClient.

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

Ten interfejs może służyć do refaktoryzacji poprzedniego ChatHub przykładu:

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

Użycie Hub<IChatClient> umożliwia sprawdzanie czasu kompilacji metod klienta. Zapobiega to problemom spowodowanym używaniem ciągów magicznych, ponieważ Hub<T> może zapewnić dostęp tylko do metod zdefiniowanych w interfejsie.

Użycie silnie typizowanego Hub<T> elementu wyłącza możliwość używania elementu SendAsync. Wszystkie metody zdefiniowane w interfejsie mogą być nadal definiowane jako asynchroniczne. W rzeczywistości każda z tych metod powinna zwrócić wartość Task. Ponieważ jest to interfejs, nie używaj słowa kluczowego async . Na przykład:

public interface IClient
{
    Task ClientMethod();
}

Uwaga

Sufiks Async nie jest usuwany z nazwy metody. Jeśli metoda klienta nie jest zdefiniowana za pomocą .on('MyMethodAsync')metody , nie należy używać MyMethodAsync jej jako nazwy.

Zmienianie nazwy metody centrum

Domyślnie nazwa metody centrum serwera to nazwa metody .NET. Można jednak użyć atrybutu HubMethodName , aby zmienić to ustawienie domyślne i ręcznie określić nazwę metody. Klient powinien użyć tej nazwy zamiast nazwy metody .NET podczas wywoływania metody:

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

Obsługa zdarzeń dla połączenia

Interfejs SignalR API usługi Hubs udostępnia OnConnectedAsync metody i OnDisconnectedAsync wirtualne do zarządzania połączeniami i śledzenia ich. Zastąpij metodę wirtualną OnConnectedAsync , aby wykonywać akcje, gdy klient łączy się z centrum, na przykład dodając ją do grupy:

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

Zastąpij metodę wirtualną OnDisconnectedAsync , aby wykonywać akcje po rozłączeniu klienta. Jeśli klient rozłącza się celowo (wywołując connection.stop()na przykład exception , parametr będzie mieć nullwartość . Jeśli jednak klient zostanie rozłączony z powodu błędu (takiego jak awaria sieci), exception parametr będzie zawierać wyjątek opisujący błąd:

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

RemoveFromGroupAsync nie musi być wywoływana w elemecie OnDisconnectedAsync, jest automatycznie obsługiwana.

Ostrzeżenie

Ostrzeżenie o zabezpieczeniach: Ujawnienie ConnectionId może prowadzić do podszywania się pod złośliwy, jeśli SignalR serwer lub wersja klienta jest ASP.NET Core 2.2 lub starsze.

Obsługa błędów

Wyjątki zgłaszane w metodach centrum są wysyłane do klienta, który wywołał metodę. Na kliencie invoke JavaScript metoda zwraca kod JavaScript Promise. Gdy klient otrzymuje błąd z procedurą obsługi dołączoną do obietnicy przy użyciu metody catch, jest wywoływany i przekazywany jako obiekt JavaScript Error :

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

Jeśli centrum zgłasza wyjątek, połączenia nie są zamykane. Domyślnie SignalR zwraca ogólny komunikat o błędzie do klienta. Na przykład:

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

Nieoczekiwane wyjątki często zawierają poufne informacje, takie jak nazwa serwera bazy danych w wyjątku wyzwalanym w przypadku niepowodzenia połączenia z bazą danych. SignalR domyślnie nie ujawnia tych szczegółowych komunikatów o błędach jako środka zabezpieczeń. Aby uzyskać więcej informacji o tym, dlaczego szczegóły wyjątku są pomijane, zobacz Zagadnienia dotyczące zabezpieczeń w programie ASP.NET Core SignalR.

Jeśli masz wyjątkowy warunek, który chcesz propagować do klienta, możesz użyć HubException klasy . W przypadku zgłoszenia HubException z metody SignalRcentrum cały komunikat zostanie wysłany do klienta, niezmodyfikowany:

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

Uwaga

SignalR wysyła Message tylko właściwość wyjątku do klienta. Ślad stosu i inne właściwości wyjątku nie są dostępne dla klienta.

Dodatkowe zasoby