Udostępnij za pośrednictwem


Tworzenie odpornych aplikacji HTTP: kluczowe wzorce programistyczne

Tworzenie niezawodnych aplikacji HTTP, które mogą odzyskiwać dane po błędach przejściowych, jest typowym wymaganiem. W tym artykule założono, że znasz już artykuł Introduction to resilient app development (Wprowadzenie do odpornego programowania aplikacji), ponieważ ten artykuł rozszerza podstawowe pojęcia, które zostały przekazane. Aby ułatwić tworzenie odpornych aplikacji HTTP, pakiet NuGet Microsoft.Extensions.Http.Resilience zapewnia mechanizmy odporności specjalnie dla elementu HttpClient. Ten pakiet NuGet opiera się na Microsoft.Extensions.Resilience bibliotece i polly, która jest popularnym projektem open source. Aby uzyskać więcej informacji, zobacz Polly.

Rozpocznij

Aby użyć wzorców odporności w aplikacjach HTTP, zainstaluj pakiet NuGet Microsoft.Extensions.Http.Resilience .

dotnet add package Microsoft.Extensions.Http.Resilience --version 8.0.0

Aby uzyskać więcej informacji, zobacz dotnet package add or Manage package dependencies in .NET applications (Dodawanie pakietów dotnet lub zarządzanie zależnościami pakietów w aplikacjach platformy .NET).

Dodawanie odporności do klienta HTTP

Aby zwiększyć odporność do HttpClient, należy utworzyć łańcuch wywołań dla typu IHttpClientBuilder zwracanego przez wywołanie dowolnej z dostępnych metod AddHttpClient. Aby uzyskać więcej informacji, zobacz IHttpClientFactory with .NET (IHttpClientFactory z platformą .NET).

Dostępnych jest kilka rozszerzeń skoncentrowanych na odporności. Niektóre z nich są standardowe, dlatego stosują różne najlepsze rozwiązania branżowe, a inne są bardziej dostosowywane. Podczas dodawania odporności należy dodać tylko jednego obsługującego odporność i unikać nawarstwiania obsługujących. Jeśli musisz dodać wiele procedur obsługi odporności, rozważ użycie AddResilienceHandler metody rozszerzenia, która umożliwia dostosowanie strategii odporności.

Ważne

Wszystkie przykłady w tym artykule opierają się na interfejsie API AddHttpClient z biblioteki Microsoft.Extensions.Http , która zwraca instancję IHttpClientBuilder. Wystąpienie IHttpClientBuilder służy do konfigurowania HttpClient i dodawania mechanizmu odporności.

Dodawanie standardowego mechanizmu obsługi odpornościowej

Standardowy program obsługi odporności stosuje wiele strategii odpornościowych nałożonych na siebie, z domyślnymi opcjami do wysyłania żądań i obsługi wszelkich błędów przejściowych. Standardowy handler odporności dodaje się przez wywołanie AddStandardResilienceHandler metody rozszerzenia na wystąpieniu IHttpClientBuilder.

var services = new ServiceCollection();

var httpClientBuilder = services.AddHttpClient<ExampleClient>(
    configureClient: static client =>
    {
        client.BaseAddress = new("https://jsonplaceholder.typicode.com");
    });

Poprzedzający kod:

  • Tworzy instancję ServiceCollection.
  • Dodaje element HttpClient typu ExampleClient do kontenera usługi.
  • Konfiguruje HttpClient do korzystania z "https://jsonplaceholder.typicode.com" jako adresu podstawowego.
  • Tworzy element httpClientBuilder używany w innych przykładach w tym artykule.

Bardziej rzeczywisty przykład polegałby na hostingu, takim jak opisany w artykule .NET Generic Host. Korzystając z pakietu NuGet Microsoft.Extensions.Hosting, rozważmy następujący zaktualizowany przykład:

using Http.Resilience.Example;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);

IHttpClientBuilder httpClientBuilder = builder.Services.AddHttpClient<ExampleClient>(
    configureClient: static client =>
    {
        client.BaseAddress = new("https://jsonplaceholder.typicode.com");
    });

Kod ten jest podobny do ręcznego podejścia ServiceCollection tworzenia, ale zamiast tego opiera się na Host.CreateApplicationBuilder() do budowy hosta, który udostępnia usługi.

Element ExampleClient jest zdefiniowany w następujący sposób:

using System.Net.Http.Json;

namespace Http.Resilience.Example;

/// <summary>
/// An example client service, that relies on the <see cref="HttpClient"/> instance.
/// </summary>
/// <param name="client">The given <see cref="HttpClient"/> instance.</param>
internal sealed class ExampleClient(HttpClient client)
{
    /// <summary>
    /// Returns an <see cref="IAsyncEnumerable{T}"/> of <see cref="Comment"/>s.
    /// </summary>
    public IAsyncEnumerable<Comment?> GetCommentsAsync()
    {
        return client.GetFromJsonAsAsyncEnumerable<Comment>("/comments");
    }
}

Poprzedzający kod:

  • Definiuje typ ExampleClient, który ma konstruktor akceptujący HttpClient.
  • Uwidacznia metodę GetCommentsAsync , która wysyła żądanie GET do punktu końcowego /comments i zwraca odpowiedź.

Typ jest definiowany Comment w następujący sposób:

namespace Http.Resilience.Example;

public record class Comment(
    int PostId, int Id, string Name, string Email, string Body);

Biorąc pod uwagę, że utworzono IHttpClientBuilder (httpClientBuilder), a teraz rozumiesz implementację ExampleClient i odpowiedni model Comment, rozważmy następujący przykład:

httpClientBuilder.AddStandardResilienceHandler();

Poprzedni kod dodaje standardowy mechanizm zapewniający odporność do elementu HttpClient. Jak w przypadku większości interfejsów API dotyczących odporności, istnieją mechanizmy przeciążenia, które umożliwiają dostosowanie domyślnych opcji i zastosowanych strategii zwiększania odporności.

Usuń standardowe mechanizmy odporności

Istnieje metoda RemoveAllResilienceHandlers, która usuwa wszystkie wcześniej zarejestrowane procedury obsługi odporności. Jest to przydatne, gdy musisz wyczyścić istniejące mechanizmy odporności, aby dodać własny niestandardowy mechanizm. W poniższym przykładzie pokazano, jak skonfigurować niestandardową HttpClient przy użyciu metody AddHttpClient, usunąć wszystkie wstępnie zdefiniowane strategie odporności i zastąpić je nowymi procedurami obsługi. Takie podejście umożliwia wyczyszczenie istniejących konfiguracji i zdefiniowanie nowych zgodnie z określonymi wymaganiami.

// By default, we want all HttpClient instances to include the StandardResilienceHandler.
services.ConfigureHttpClientDefaults(builder => builder.AddStandardResilienceHandler());
// For a named HttpClient "custom" we want to remove the StandardResilienceHandler and add the StandardHedgingHandler instead.
services.AddHttpClient("custom")
    .RemoveAllResilienceHandlers()
    .AddStandardHedgingHandler();

Poprzedzający kod:

  • Tworzy instancję ServiceCollection.
  • Dodaje standardowy mechanizm obsługi odporności do wszystkich wystąpień HttpClient.
  • Dla "niestandardowego" HttpClient:
    • Usuwa wszystkie wstępnie zdefiniowane mechanizmy odporności, które zostały wcześniej zarejestrowane. Jest to przydatne, gdy chcesz zacząć od czystego stanu, aby dodać własne strategie niestandardowe.
    • Dodaje StandardHedgingHandler do HttpClient. Możesz zastąpić AddStandardHedgingHandler() dowolną strategią, która odpowiada potrzebom aplikacji, takimi jak mechanizmy ponawiania prób, wyłączniki lub inne techniki odporności.

Domyślne ustawienia standardowej obsługi odporności

Domyślna konfiguracja zawiera pięć strategii odporności w następującej kolejności (od najbardziej zewnętrznej do najbardziej wewnętrznej):

Zamówienie Strategia opis Domyślne
1 Ogranicznik szybkości System ograniczający limituje maksymalną liczbę współbieżnych żądań wysyłanych do zależności. Kolejka: 0
Pozwolenie: 1_000
2 Łączny limit czasu Łączny przepływ limitu czasu żądania stosuje ogólny limit czasu do wykonania, zapewniając, że żądanie, w tym ponawiane próby, nie przekracza skonfigurowanego limitu. Łączny limit czasu: 30s
3 Ponów próbę Mechanizm ponawiania ponawia żądanie w przypadku, gdy zależność jest wolna lub zwraca błąd przejściowy. Maksymalna liczba ponownych prób: 3
Wycofanie: Exponential
Użyj roztrzasku: true
Opóźnienie:2s
4 Wyłącznik obwodu Wyłącznik blokuje wykonywanie, jeśli wykryto zbyt wiele bezpośrednich awarii lub przekroczenia limitu czasu. Współczynnik awarii: 10%
Minimalna przepływność: 100
Czas trwania próbkowania: 30s
Czas trwania przerwy: 5s
5 Przekroczenie czasu próby Mechanizm limitu czasu dla próby ogranicza czas trwania każdej próby żądania i zgłasza wyjątek, jeśli czas ten zostanie przekroczony. Limit czasu próby: 10s

Ponawianie prób i wyłączniki awaryjne

Strategie ponawiania i wyłącznika obsługują zarówno zestaw określonych kodów stanu HTTP, jak i wyjątków. Rozważ następujące kody stanu HTTP:

  • HTTP 500 lub nowszy (błędy serwera)
  • HTTP 408 (przekroczenie limitu czasu żądania)
  • HTTP 429 (zbyt wiele żądań)

Ponadto te strategie obsługują następujące wyjątki:

  • HttpRequestException
  • TimeoutRejectedException

Wyłącz ponawianie prób dla danej listy metod HTTP

Domyślnie program obsługi odporności standardowej jest skonfigurowany tak, aby ponawiać próby dla wszystkich metod HTTP. W przypadku niektórych aplikacji takie zachowanie może być niepożądane, a nawet szkodliwe. Jeśli na przykład żądanie POST wstawia nowy rekord do bazy danych, wykonanie ponownych prób dla takiego żądania może prowadzić do duplikowania danych. Jeśli musisz wyłączyć ponawianie prób dla danej listy metod HTTP, możesz użyć metody DisableFor(HttpRetryStrategyOptions, HttpMethod[]):

httpClientBuilder.AddStandardResilienceHandler(options =>
{
    options.Retry.DisableFor(HttpMethod.Post, HttpMethod.Delete);
});

Alternatywnie można użyć metody DisableForUnsafeHttpMethods(HttpRetryStrategyOptions), która wyłącza ponawianie prób dla żądań POST, PATCH, PUT, DELETEi CONNECT. Zgodnie z RFCmetody te są uważane za niebezpieczne; co oznacza, że ich semantyka nie jest przeznaczona wyłącznie do odczytu:

httpClientBuilder.AddStandardResilienceHandler(options =>
{
    options.Retry.DisableForUnsafeHttpMethods();
});

Dodaj standardową procedurę obsługi zabezpieczania

Standardowy moduł obsługi hedgingu opakowuje wykonanie żądania za pomocą standardowego mechanizmu zabezpieczającego. Równoległe zabezpieczenie ponawia powolne żądania.

Aby użyć standardowego mechanizmu obsługi hedgingu, wywołaj metodę rozszerzającą AddStandardHedgingHandler. W poniższym przykładzie skonfigurowaliśmy element ExampleClient tak, aby używał standardowej procedury obsługi hedgingowej.

httpClientBuilder.AddStandardHedgingHandler();

Kod powyżej dodaje standardowy mechanizm obsługi hedgingu do elementu HttpClient.

Domyślne ustawienia standardowego mechanizmu zabezpieczającego

Standardowe zabezpieczenie wykorzystuje pulę przełączników, aby zapewnić, że punkty dostępu w złej kondycji nie są objęte zabezpieczeniem. Domyślnie wybór z puli jest oparty na autorytecie URL (schemat + host + port).

Napiwek

Zaleca się skonfigurowanie sposobu wybierania strategii przez wywołanie StandardHedgingHandlerBuilderExtensions.SelectPipelineByAuthority lub StandardHedgingHandlerBuilderExtensions.SelectPipelineBy w przypadku bardziej zaawansowanych scenariuszy.

Kod powyżej dodaje standardowy mechanizm obsługi hedgingu do elementu IHttpClientBuilder. Domyślna konfiguracja zawiera pięć strategii odporności w następującej kolejności (od najbardziej zewnętrznej do najbardziej wewnętrznej):

Zamówienie Strategia opis Domyślne
1 Całkowity czas oczekiwania na odpowiedź żądania Łączny potok limitu czasu żądania stosuje ogólne ograniczenie czasowe do wykonania, zapewniając, że żądanie, w tym próby wyprzedzania, nie przekracza skonfigurowanego limitu. Łączny limit czasu: 30s
2 Zabezpieczenia Strategia zabezpieczania wykonuje żądania do wielu punktów końcowych, jeśli zależny system jest powolny lub zwraca błąd przejściowy. Routing to opcja, domyślnie po prostu dostosowuje adres URL dostarczony przez oryginalny HttpRequestMessage element. Minimalna liczba prób: 1
Maksymalna liczba prób: 10
Opóźnienie: 2s
3 Ogranicznik szybkości (na punkt końcowy) System ograniczający limituje maksymalną liczbę współbieżnych żądań wysyłanych do zależności. Kolejka: 0
Pozwolenie: 1_000
4 Wyłącznik (dla punktu końcowego) Wyłącznik blokuje wykonywanie, jeśli wykryto zbyt wiele bezpośrednich awarii lub przekroczenia limitu czasu. Współczynnik awarii: 10%
Minimalna przepływność: 100
Czas trwania próbkowania: 30s
Czas trwania przerwy: 5s
5 Limit czasu próby (na punkt końcowy) Mechanizm limitu czasu dla próby ogranicza czas trwania każdej próby żądania i zgłasza wyjątek, jeśli czas ten zostanie przekroczony. Limit czasu: 10s

Dostosowywanie wyboru trasy mechanizmu hedgingowego

W przypadku korzystania ze standardowego mechanizmu wyznaczania granic można dostosować sposób wybierania punktów końcowych żądań, wywołując różne rozszerzenia dla typu IRoutingStrategyBuilder. Może to być przydatne w przypadku scenariuszy, takich jak testowanie A/B, w których chcesz kierować procent żądań do innego punktu końcowego:

httpClientBuilder.AddStandardHedgingHandler(static (IRoutingStrategyBuilder builder) =>
{
    // Hedging allows sending multiple concurrent requests
    builder.ConfigureOrderedGroups(static options =>
    {
        options.Groups.Add(new UriEndpointGroup()
        {
            Endpoints =
            {
                // Imagine a scenario where 3% of the requests are 
                // sent to the experimental endpoint.
                new() { Uri = new("https://example.net/api/experimental"), Weight = 3 },
                new() { Uri = new("https://example.net/api/stable"), Weight = 97 }
            }
        });
    });
});

Poprzedzający kod:

  • Dodaje obsługę hedgingową do elementu IHttpClientBuilder.
  • Konfiguruje IRoutingStrategyBuilder, aby używał metody ConfigureOrderedGroups do konfigurowania uporządkowanych grup.
  • Dodaje element EndpointGroup do orderedGroup obiektu , który kieruje 3% żądań do https://example.net/api/experimental punktu końcowego i 97% żądań do punktu końcowego https://example.net/api/stable .
  • Konfiguruje IRoutingStrategyBuilder, aby użyć metody ConfigureWeightedGroups do konfiguracji.

Aby skonfigurować grupę ważoną, wywołaj metodę ConfigureWeightedGroups dla IRoutingStrategyBuilder typu . Poniższy przykład konfiguruje IRoutingStrategyBuilder do użycia metody ConfigureWeightedGroups w celu konfiguracji grup ważonych.

httpClientBuilder.AddStandardHedgingHandler(static (IRoutingStrategyBuilder builder) =>
{
    // Hedging allows sending multiple concurrent requests
    builder.ConfigureWeightedGroups(static options =>
    {
        options.SelectionMode = WeightedGroupSelectionMode.EveryAttempt;

        options.Groups.Add(new WeightedUriEndpointGroup()
        {
            Endpoints =
            {
                // Imagine A/B testing
                new() { Uri = new("https://example.net/api/a"), Weight = 33 },
                new() { Uri = new("https://example.net/api/b"), Weight = 33 },
                new() { Uri = new("https://example.net/api/c"), Weight = 33 }
            }
        });
    });
});

Poprzedzający kod:

  • Dodaje obsługę hedgingową do elementu IHttpClientBuilder.
  • Konfiguruje IRoutingStrategyBuilder do używania metody ConfigureWeightedGroups do konfigurowania grup ważonych.
  • Ustawia wartość SelectionMode na WeightedGroupSelectionMode.EveryAttempt.
  • Dodaje WeightedEndpointGroup do weightedGroup , który kieruje 33% żądań do punktu końcowego https://example.net/api/a, 33% żądań do punktu końcowego https://example.net/api/b i 33% żądań do punktu końcowego https://example.net/api/c.

Napiwek

Maksymalna liczba prób zabezpieczenia bezpośrednio koreluje z liczbą skonfigurowanych grup. Jeśli na przykład masz dwie grupy, maksymalna liczba prób wynosi dwa.

Aby uzyskać więcej informacji, zobacz Polly docs: Strategia zabezpieczenia odporności.

Często konfiguruje się uporządkowaną grupę lub grupę ważoną, ale ważne jest skonfigurowanie obu tych grup. Użycie uporządkowanych i ważonych grup jest przydatne w scenariuszach, w których chcesz wysłać procent żądań do innego punktu końcowego, na przykład w przypadku testowania A/B.

Dodawanie niestandardowych mechanizmów odporności

Aby mieć większą kontrolę, możesz dostosować procedury obsługi odporności przy użyciu interfejsu AddResilienceHandler API. Ta metoda przyjmuje delegata, który konfiguruje instancję ResiliencePipelineBuilder<HttpResponseMessage> używaną do tworzenia strategii odpornościowej.

Aby skonfigurować nazwaną procedurę obsługi odporności, wywołaj metodę rozszerzenia AddResilienceHandler z nazwą procedury obsługi. W poniższym przykładzie skonfigurowano procedurę obsługi odporności o nazwie "CustomPipeline".

httpClientBuilder.AddResilienceHandler(
    "CustomPipeline",
    static builder =>
{
    // See: https://www.pollydocs.org/strategies/retry.html
    builder.AddRetry(new HttpRetryStrategyOptions
    {
        // Customize and configure the retry logic.
        BackoffType = DelayBackoffType.Exponential,
        MaxRetryAttempts = 5,
        UseJitter = true
    });

    // See: https://www.pollydocs.org/strategies/circuit-breaker.html
    builder.AddCircuitBreaker(new HttpCircuitBreakerStrategyOptions
    {
        // Customize and configure the circuit breaker logic.
        SamplingDuration = TimeSpan.FromSeconds(10),
        FailureRatio = 0.2,
        MinimumThroughput = 3,
        ShouldHandle = static args =>
        {
            return ValueTask.FromResult(args is
            {
                Outcome.Result.StatusCode:
                    HttpStatusCode.RequestTimeout or
                        HttpStatusCode.TooManyRequests
            });
        }
    });

    // See: https://www.pollydocs.org/strategies/timeout.html
    builder.AddTimeout(TimeSpan.FromSeconds(5));
});

Poprzedzający kod:

  • Dodaje procedurę obsługi odporności o nazwie "CustomPipeline" jako pipelineName do kontenera usług.
  • Dodaje strategię ponawiania prób z wykładniczym wycofywaniem, pięcioma ponownymi próbami i preferencjami trząsania do konstruktora odporności.
  • Dodaje strategię wyłącznika z czasem próbkowania wynoszącym 10 sekund, stosunkiem awarii wynoszącym 0,2 (20%), minimalną przepływnością wynoszącą trzy oraz predykatem, który obsługuje kody stanu HTTP RequestTimeout i TooManyRequests do konstruktora odporności.
  • Dodaje strategię limitu czasu z czasem 5 sekund do narzędzia do budowania odporności.

Dla każdej strategii odporności jest dostępnych wiele opcji. Aby uzyskać więcej informacji, zobacz dokumentację usługi Polly: Strategies. Aby uzyskać więcej informacji na temat konfigurowania ShouldHandle delegatów, zobacz dokumentacja Polly: fault handling w reaktywnych strategiach.

Ostrzeżenie

Jeśli używasz strategii ponawiania prób i limitu czasu i chcesz skonfigurować delegata ShouldHandle w strategii ponawiania prób, upewnij się, że powinna obsługiwać wyjątek limitu czasu usługi Polly. Polly zgłasza element TimeoutRejectedException (który dziedziczy z Exception), a nie standard TimeoutException.

Dynamiczne ponowne ładowanie

Usługa Polly obsługuje dynamiczne ponowne ładowanie skonfigurowanych strategii odporności. Oznacza to, że można zmienić konfigurację strategii odpornościowych w czasie działania. Aby włączyć dynamiczne ponowne ładowanie, użyj odpowiedniego przeciążenia AddResilienceHandler, które uwidacznia ResilienceHandlerContext. Biorąc pod uwagę kontekst, wywołaj EnableReloads odpowiednie opcje strategii odporności:

httpClientBuilder.AddResilienceHandler(
    "AdvancedPipeline",
    static (ResiliencePipelineBuilder<HttpResponseMessage> builder,
        ResilienceHandlerContext context) =>
    {
        // Enable reloads whenever the named options change
        context.EnableReloads<HttpRetryStrategyOptions>("RetryOptions");

        // Retrieve the named options
        var retryOptions =
            context.GetOptions<HttpRetryStrategyOptions>("RetryOptions");

        // Add retries using the resolved options
        builder.AddRetry(retryOptions);
    });

Poprzedzający kod:

  • Dodaje procedurę obsługi odporności o nazwie "AdvancedPipeline" jako pipelineName do kontenera usług.
  • Włącza ponowne ładowanie pipeline'u "AdvancedPipeline" za każdym razem, gdy zmieniają się nazwane opcje RetryStrategyOptions.
  • Pobiera nazwane opcje z IOptionsMonitor<TOptions> usługi.
  • Dodaje strategię ponawiania wraz z pobranymi opcjami do mechanizmu odpornościowego.

Aby uzyskać więcej informacji, zobacz dokumentację Polly: zaawansowane wstrzykiwanie zależności.

Ten przykład opiera się na sekcji opcji, która może ulec zmianie, takiej jak plik appsettings.json . Rozważ następujący plik appsettings.json :

{
    "RetryOptions": {
        "Retry": {
            "BackoffType": "Linear",
            "UseJitter": false,
            "MaxRetryAttempts": 7
        }
    }
}

Teraz wyobraź sobie, że te opcje zostały powiązane z konfiguracją aplikacji, wiążąc element z HttpRetryStrategyOptions sekcją "RetryOptions" :

var section = builder.Configuration.GetSection("RetryOptions");

builder.Services.Configure<HttpStandardResilienceOptions>(section);

Aby uzyskać więcej informacji, zobacz Wzorzec opcji na platformie .NET.

Przykładowe użycie

Aplikacja opiera się na iniekcji zależności, aby rozwiązać ExampleClient i odpowiadający mu HttpClient. Kod kompiluje element IServiceProvider i rozpoznaje element ExampleClient z niego.

IHost host = builder.Build();

ExampleClient client = host.Services.GetRequiredService<ExampleClient>();

await foreach (Comment? comment in client.GetCommentsAsync())
{
    Console.WriteLine(comment);
}

Poprzedzający kod:

Wyobraź sobie sytuację, w której sieć ulegnie awarii lub serwer przestaje odpowiadać. Na poniższym diagramie pokazano, jak strategie odporności będą obsługiwać sytuację, biorąc pod uwagę metodę ExampleClient i GetCommentsAsync :

Przykładowy przepływ HTTP GET z potokiem odpornościowym.

Powyższy diagram przedstawia:

  • Obiekt ExampleClient wysyła żądanie HTTP GET do punktu końcowego /comments .
  • Wartość HttpResponseMessage jest oceniana:
    • Jeśli odpowiedź zakończy się pomyślnie (HTTP 200), zostanie zwrócona odpowiedź.
    • Jeśli odpowiedź nie powiedzie się (HTTP kod inny niż 200), potok odporności wykorzystuje skonfigurowane strategie odporności.

Chociaż jest to prosty przykład, pokazuje, jak strategie odporności mogą służyć do obsługi błędów przejściowych. Aby uzyskać więcej informacji, zobacz Dokumentacja usługi Polly: Strategie.

Znane problemy

W poniższych sekcjach opisano różne znane problemy.

Zgodność z pakietem Grpc.Net.ClientFactory

Jeśli używasz Grpc.Net.ClientFactory wersji 2.63.0 lub starszej, włączenie standardowych mechanizmów odporności czy zabezpieczania dla klienta gRPC może spowodować wyjątek w czasie wykonywania. W szczególności rozważmy następujący przykład kodu:

services
    .AddGrpcClient<Greeter.GreeterClient>()
    .AddStandardResilienceHandler();

Powyższy kod powoduje następujący wyjątek:

System.InvalidOperationException: The ConfigureHttpClient method is not supported when creating gRPC clients. Unable to create client with name 'GreeterClient'.

Aby rozwiązać ten problem, zalecamy uaktualnienie do Grpc.Net.ClientFactory wersji lub nowszej 2.64.0 .

Istnieje kontrola czasu budowania, która sprawdza, czy używasz wersji Grpc.Net.ClientFactory2.63.0 lub starszej, i jeśli tak, generuje ostrzeżenie kompilacji. Ostrzeżenie można pominąć, ustawiając następującą właściwość w pliku projektu:

<PropertyGroup>
  <SuppressCheckGrpcNetClientFactoryVersion>true</SuppressCheckGrpcNetClientFactoryVersion>
</PropertyGroup>

Zgodność z usługą .NET Application Insights

Jeśli używasz usługi .NET Application Insights w wersji 2.22.0 lub starszej , włączenie funkcji odporności w aplikacji może spowodować brak wszystkich danych telemetrycznych usługi Application Insights. Problem występuje, gdy funkcje odporności są rejestrowane przed usługami Application Insights. Rozważmy następujący przykład powodujący problem:

// At first, we register resilience functionality.
services.AddHttpClient().AddStandardResilienceHandler();

// And then we register Application Insights. As a result, Application Insights doesn't work.
services.AddApplicationInsightsTelemetry();

Problem można rozwiązać, aktualizując usługę .NET Application Insights do wersji 2.23.0 lub nowszej. Jeśli nie możesz go zaktualizować, zarejestrowanie usług Application Insights przed funkcjonalnością odpornościową, jak pokazano poniżej, rozwiąże problem.

// We register Application Insights first, and now it will be working correctly.
services.AddApplicationInsightsTelemetry();
services.AddHttpClient().AddStandardResilienceHandler();