0Pricing
C# Academy · Lekcja

Jednoargumentowe i strumieniowane RPC po stronie serwera

Implementuj wywołania jednoargumentowe oraz strumieniowanie po stronie serwera, aby przesyłać dane z serwera do klienta w czasie rzeczywistym.

Jednoargumentowe i strumieniowane RPC po stronie serwera to bezpłatna lekcja C# Academy na CoddyKit. To lekcja 2 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej C# Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs C# Academy zawiera 4 lekcji w sumie.

Typy RPC gRPC

gRPC obsługuje cztery wzorce RPC: Unary (żądanie/odpowiedź), Server Streaming (klient wysyła jedno żądanie, serwer wysyła wiele odpowiedzi), Client Streaming oraz Bidirectional Streaming. W tej lekcji omówiono dwa pierwsze.

Unary RPC: podstawowy wzorzec

Unary to najprostszy wzorzec — jedno żądanie i jedna odpowiedź. Wygląda jak zwykłe wywołanie funkcji, ale jest przesyłany przez HTTP/2 z kodowaniem Protobuf.

// .proto definition
service OrderService {
  rpc GetOrder (GetOrderRequest) returns (OrderResponse);
}

message GetOrderRequest { int32 id = 1; }
message OrderResponse   { int32 id = 1; string status = 2; double total = 3; }

Implementowanie Unary RPC

Należy przesłonić wygenerowaną metodę bazową. ServerCallContext udostępnia metadane, token anulowania, termin wykonania oraz informacje o partnerze komunikacji.

public class OrderService : OrderService.OrderServiceBase
{
    private readonly IOrderRepository _repo;
    public OrderService(IOrderRepository repo) => _repo = repo;

    public override async Task<OrderResponse> GetOrder(
        GetOrderRequest request,
        ServerCallContext context)
    {
        var order = await _repo.GetByIdAsync(request.Id, context.CancellationToken);
        if (order is null)
            throw new RpcException(new Status(StatusCode.NotFound, "Order not found"));

        return new OrderResponse
        {
            Id     = order.Id,
            Status = order.Status.ToString(),
            Total  = (double)order.Total
        };
    }
}

Wywoływanie RPC typu unary z klienta

Wygenerowany klient udostępnia zarówno metody wyglądające na synchroniczne, jak i rzeczywiście asynchroniczne. W środowisku produkcyjnym zawsze należy używać wariantu Async.

var client = new OrderService.OrderServiceClient(channel);

// Async call with cancellation
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5));
var reply = await client.GetOrderAsync(
    new GetOrderRequest { Id = 42 },
    cancellationToken: cts.Token);

Console.WriteLine($"Order {reply.Id}: {reply.Status} - ${reply.Total}");

Strumieniowanie po stronie serwera: definicja proto

Strumieniowanie po stronie serwera wymaga dodania słowa kluczowego stream przed typem odpowiedzi. Serwer wysyła wiele komunikatów w ramach tego samego połączenia, zanim zamknie strumień.

service StockService {
  // Client sends one symbol, server streams price updates
  rpc WatchStock (WatchRequest) returns (stream StockUpdate);
}

message WatchRequest  { string symbol = 1; }
message StockUpdate   { string symbol = 1; double price = 2; int64 timestamp = 3; }

Implementowanie strumieniowania po stronie serwera

Użyj IServerStreamWriter<T> do wysyłania komunikatów. Metoda zwraca Task — zapisuj do zakończenia, a następnie zwróć sterowanie.

public override async Task WatchStock(
    WatchRequest request,
    IServerStreamWriter<StockUpdate> responseStream,
    ServerCallContext context)
{
    while (!context.CancellationToken.IsCancellationRequested)
    {
        var price = await _market.GetPriceAsync(request.Symbol);

        await responseStream.WriteAsync(new StockUpdate
        {
            Symbol    = request.Symbol,
            Price     = price,
            Timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
        });

        await Task.Delay(1000, context.CancellationToken);
    }
}

Odbieranie strumienia serwera po stronie klienta

Użyj await foreach do iteracji po ResponseStream.ReadAllAsync(), aby przetwarzać każdy komunikat w miarę jego nadejścia.

using var call = client.WatchStock(
    new WatchRequest { Symbol = "MSFT" });

await foreach (var update in call.ResponseStream.ReadAllAsync())
{
    Console.WriteLine($"{update.Symbol}: ${update.Price:F2}");
}
// Continues until server closes the stream or client cancels

Anulowanie strumienia serwera

Przekaż CancellationToken podczas otwierania wywołania, aby zatrzymać strumień po stronie klienta. Serwer otrzymuje sygnał anulowania za pośrednictwem własnego tokenu.

var cts = new CancellationTokenSource();

// Cancel after 30 seconds
cts.CancelAfter(TimeSpan.FromSeconds(30));

using var call = client.WatchStock(
    new WatchRequest { Symbol = "AAPL" },
    cancellationToken: cts.Token);

try
{
    await foreach (var update in
        call.ResponseStream.ReadAllAsync(cts.Token))
    {
        Console.WriteLine($"Price: {update.Price}");
    }
}
catch (OperationCanceledException)
{
    Console.WriteLine("Stream cancelled.");
}

Metadane: nagłówki żądania i trailery

gRPC obsługuje metadane (pary klucz-wartość) wysyłane jako nagłówki przed odpowiedzią i trailery po odpowiedzi. Używaj ich do przekazywania tokenów uwierzytelniania, identyfikatorów śledzenia lub kursorów stronicowania.

// Server: send initial metadata
await context.WriteResponseHeadersAsync(new Metadata
{
    { "x-correlation-id", Guid.NewGuid().ToString() }
});

// Server: set trailing metadata
context.ResponseTrailers.Add("x-total-count", "1500");

// Client: read headers
var headers  = await call.ResponseHeadersAsync;
var trailerId = headers.GetValue("x-correlation-id");

gRPC-Web dla klientów przeglądarkowych

Przeglądarki nie mogą używać surowego gRPC (trailery HTTP/2 nie są obsługiwane). Użyj Grpc.AspNetCore.Web oraz klienta JavaScript grpc-web albo Grpc.Net.Client.Web w Blazorze.

// dotnet add package Grpc.AspNetCore.Web

app.UseGrpcWeb();
app.MapGrpcService<GreeterService>().EnableGrpcWeb();

// Blazor client:
var handler = new GrpcWebHandler(GrpcWebMode.GrpcWeb,
    new HttpClientHandler());
using var channel = GrpcChannel.ForAddress(
    "https://localhost:7042",
    new GrpcChannelOptions { HttpHandler = handler });

Praktyczny przykład: usługa strumieniowania logów

Usługa agregująca logi przesyła wpisy dziennika aplikacji do połączonych klientów monitorujących w czasie rzeczywistym, korzystając ze strumieniowania po stronie serwera.

public override async Task StreamLogs(
    LogStreamRequest request,
    IServerStreamWriter<LogEntry> responseStream,
    ServerCallContext context)
{
    await foreach (var log in _logChannel.Reader.ReadAllAsync(
        context.CancellationToken))
    {
        if (log.Level >= request.MinLevel)
        {
            await responseStream.WriteAsync(new LogEntry
            {
                Level   = log.Level.ToString(),
                Message = log.Message,
                Timestamp = Timestamp.FromDateTime(log.Timestamp)
            });
        }
    }
}

Szybkie sprawdzenie

Jakie słowo kluczowe w pliku .proto wskazuje RPC ze strumieniowaniem po stronie serwera?

Podsumowanie: RPC typu unary i strumieniowanie po stronie serwera

Najważniejsze informacje:

  • RPC typu unary: jedno żądanie, jedna odpowiedź — najczęściej stosowany wzorzec
  • Strumieniowanie po stronie serwera: jedno żądanie, wiele komunikatów odpowiedzi wysyłanych w czasie
  • Strumieniowanie po stronie serwera implementuje się, zapisując do IServerStreamWriter<T>
  • Strumienie serwera odbiera się za pomocą await foreach na ReadAllAsync()
  • Użyj CancellationToken, aby bezpiecznie zatrzymywać strumienie z dowolnej strony
  • gRPC-Web umożliwia klientom przeglądarkowym wywoływanie usług gRPC

Często zadawane pytania

Czy lekcja „Jednoargumentowe i strumieniowane RPC po stronie serwera” jest bezpłatna?

Tak — pełny tekst „Jednoargumentowe i strumieniowane RPC po stronie serwera” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu C# Academy, przejdź na CoddyKit PRO. Kurs C# Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „Jednoargumentowe i strumieniowane RPC po stronie serwera”?

Implementuj wywołania jednoargumentowe oraz strumieniowanie po stronie serwera, aby przesyłać dane z serwera do klienta w czasie rzeczywistym. Ćwiczysz C# Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć C# Academy?

Nie wymagamy żadnego doświadczenia. C# Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 2 z 4.

Ile czasu zajmuje lekcja „Jednoargumentowe i strumieniowane RPC po stronie serwera”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji C# Academy?

Tak. Każda lekcja C# Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Podstawy gRPC i Protobuf
  2. Jednoargumentowe i strumieniowane RPC po stronie serwera
  3. Strumieniowanie klienta i dwukierunkowe
  4. Limity czasu, anulowanie i interceptory
← Powrót do C# Academy