Partage via


Résoudre les problèmes de gRPC sur .NET

Par James Newton-King

Remarque

Ceci n’est pas la dernière version de cet article. Pour la version actuelle, consultez la version .NET 8 de cet article.

Avertissement

Cette version d’ASP.NET Core n’est plus prise en charge. Pour plus d’informations, consultez la Stratégie de prise en charge de .NET et .NET Core. Pour la version actuelle, consultez la version .NET 8 de cet article.

Important

Ces informations portent sur la préversion du produit, qui est susceptible d’être en grande partie modifié avant sa commercialisation. Microsoft n’offre aucune garantie, expresse ou implicite, concernant les informations fournies ici.

Pour la version actuelle, consultez la version .NET 8 de cet article.

Ce document décrit les problèmes fréquemment rencontrés lors du développement d’applications gRPC sur .NET.

Incompatibilité entre la configuration SSL/TLS du client et du service

Le modèle gRPC et les exemples utilisent TLS (Transport Layer Security) pour sécuriser les services gRPC par défaut. Les clients gRPC doivent utiliser une connexion sécurisée pour appeler les services gRPC sécurisés correctement.

Vous pouvez vérifier que le service gRPC ASP.NET Core utilise TLS dans les journaux écrits au démarrage de l’application. Le service écoute sur un point de terminaison HTTPS :

info: Microsoft.Hosting.Lifetime[0]
      Now listening on: https://localhost:5001
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development

Le client .NET Core doit utiliser https dans l’adresse du serveur pour effectuer des appels avec une connexion sécurisée :

var channel = GrpcChannel.ForAddress("https://localhost:5001");
var client = new Greeter.GreeterClient(channel);

Toutes les implémentations de client gRPC prennent en charge TLS. Les clients gRPC d’autres langages nécessitent généralement le canal configuré avec SslCredentials. SslCredentials spécifie le certificat que le client utilisera, et il doit être utilisé au lieu d’informations d’identification non sécurisées. Pour obtenir des exemples de configuration des différentes implémentations de client gRPC pour utiliser TLS, consultez Authentification gRPC.

Appeler un service gRPC avec un certificat non approuvé/non valide

Le client gRPC .NET exige que le service dispose d’un certificat approuvé. Le message d’erreur suivant est retourné lors de l’appel d’un service gRPC sans certificat approuvé :

Exception non gérée. System.Net.Http.HttpRequestException : La connexion SSL n’a pas pu être établie, voir l’exception interne. ---> System.Security.Authentication.AuthenticationException : Le certificat distant n’est pas valide selon la procédure de validation.

Cette erreur peut s’afficher si vous testez votre application localement et que le certificat de développement HTTPS ASP.NET Core n’est pas approuvé. Pour obtenir des instructions afin de résoudre ce problème, consultez Faire confiance au certificat de développement ASP.NET Core HTTPS sur Windows et macOS.

Si vous appelez un service gRPC sur un autre ordinateur et que vous ne pouvez pas approuver le certificat, le client gRPC peut être configuré pour ignorer le certificat non valide. Le code suivant utilise HttpClientHandler.ServerCertificateCustomValidationCallback pour autoriser les appels sans certificat approuvé :

var handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback = 
    HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

var channel = GrpcChannel.ForAddress("https://localhost:5001",
    new GrpcChannelOptions { HttpHandler = handler });
var client = new Greeter.GreeterClient(channel);

La fabrique de client gRPC autorise les appels sans certificat approuvé. Utilise la méthode d’extension ConfigurePrimaryHttpMessageHandler pour configurer le gestionnaire sur le client :


var services = new ServiceCollection();

services
    .AddGrpcClient<Greeter.GreeterClient>(o =>
    {
        o.Address = new Uri("https://localhost:5001");
    })
    .ConfigurePrimaryHttpMessageHandler(() =>
    {
        var handler = new HttpClientHandler();
        handler.ServerCertificateCustomValidationCallback =
            HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

        return handler;
    });

Warning

Les certificats non approuvés doivent uniquement être utilisés pendant le développement d’applications. Les applications de production doivent toujours utiliser des certificats valides.

Appeler des services gRPC non sécurisés avec le client .NET Core

Le client gRPC .NET peut appeler des services gRPC non sécurisés en spécifiant http dans l’adresse du serveur. Par exemple, GrpcChannel.ForAddress("http://localhost:5000").

Il existe d’autres conditions requises pour appeler des services gRPC non sécurisés en fonction de la version .NET qu’une application utilise :

Important

Les services gRPC non sécurisés doivent être hébergés sur un port HTTP/2 uniquement. Pour plus d’informations, consultez Négociation de protocole ASP.NET Core.

Impossible de démarrer l’application ASP.NET Core gRPC sur macOS

Kestrel ne prend pas en charge HTTP/2 avec TLS sur macOS avant .NET 8. Le modèle gRPC ASP.NET Core et les exemples utilisent TLS par défaut. Le message d’erreur suivant s’affiche lorsque vous tentez de démarrer le serveur gRPC :

Impossible de lier à https://localhost:5001 sur l’interface de bouclage IPv4 : « HTTP/2 sur TLS n’est pas pris en charge sur macOS en raison d’une prise en charge d’ALPN manquante. ».

Pour contourner ce problème dans .NET 7 et versions antérieures, configurez Kestrel et le client gRPC pour utiliser HTTP/2 sans TLS. Vous ne devez effectuer cette opération que pendant le développement. Le fait de ne pas utiliser TLS entraîne l’envoi de messages gRPC sans chiffrement. Pour plus d’informations, consultez Asp.Net Core 7.0 : impossible de démarrer l’application ASP.NET Core gRPC sur MacOS.

Le code des ressources C# gRPC n’est pas généré à partir de fichiers .proto

La génération de code gRPC de clients concrets et de classes de base de service nécessite que les fichiers protobuf et les outils soient référencés à partir d’un projet. Vous devez inclure :

  • Les fichiers .proto que vous souhaitez utiliser dans le groupe d’éléments <Protobuf>. Les fichiers .proto importés doivent être référencés par le projet.
  • Une référence de package au package d’outils gRPC Grpc.Tools.

Pour plus d’informations sur la génération de ressources C# gRPC, consultez Services gRPC avec C#.

Une application web ASP.NET Core hébergeant des services gRPC a uniquement besoin de la classe de base de service générée :

<ItemGroup>
  <Protobuf Include="Protos\greet.proto" GrpcServices="Server" />
</ItemGroup>

Une application cliente gRPC effectuant des appels gRPC a uniquement besoin du client concret généré :

<ItemGroup>
  <Protobuf Include="Protos\greet.proto" GrpcServices="Client" />
</ItemGroup>

Les projets WPF ne peuvent pas générer de ressources C# gRPC à partir de fichiers .proto

Les projets WPF présentent un problème connu qui empêche la génération de code gRPC de fonctionner correctement. Tous les types gRPC générés dans un projet WPF en référençant les fichiers Grpc.Tools et .proto créent des erreurs de compilation lorsqu’ils sont utilisés :

Erreur CS0246 : Le type ou le nom de l’espace de noms « MyGrpcServices » est introuvable (une directive using ou une référence d’assembly est-elle manquante ?)

Vous pouvez contourner ce problème en procédant comme suit :

  1. Créez un projet de bibliothèque de classes .NET Core.
  2. Dans le nouveau projet, ajoutez des références pour activer la génération de code C# à partir de fichiers .proto :
  3. Dans l’application WPF, ajoutez une référence au nouveau projet.

L’application WPF peut utiliser les types générés par gRPC à partir du nouveau projet de bibliothèque de classes.

Appel de services gRPC hébergés dans un sous-répertoire

Warning

De nombreux outils gRPC tiers ne prennent pas en charge les services hébergés dans des sous-répertoires. Envisagez de trouver un moyen d’héberger gRPC en tant que répertoire racine.

Le composant de chemin d’accès de l’adresse d’un canal gRPC est ignoré lors des appels gRPC. Par exemple, GrpcChannel.ForAddress("https://localhost:5001/ignored_path") n’utilise pas ignored_path lors du routage des appels gRPC pour le service.

Le chemin d’accès à l’adresse est ignoré, car gRPC a une structure d’adresse normalisée et normative. Une adresse gRPC combine les noms de package, de service et de méthode : https://localhost:5001/PackageName.ServiceName/MethodName.

Il existe certains scénarios où une application doit inclure un chemin d’accès avec des appels gRPC. Par exemple, lorsqu’une application gRPC ASP.NET Core est hébergée dans un répertoire IIS et que le répertoire doit être inclus dans la requête. Lorsqu’un chemin d’accès est requis, il peut être ajouté à l’appel gRPC à l’aide du SubdirectoryHandler personnalisé spécifié ci-dessous :

public class SubdirectoryHandler : DelegatingHandler
{
    private readonly string _subdirectory;

    public SubdirectoryHandler(HttpMessageHandler innerHandler, string subdirectory)
        : base(innerHandler)
    {
        _subdirectory = subdirectory;
    }

    protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var old = request.RequestUri;

        var url = $"{old.Scheme}://{old.Host}:{old.Port}";
        url += $"{_subdirectory}{request.RequestUri.AbsolutePath}";
        request.RequestUri = new Uri(url, UriKind.Absolute);

        return base.SendAsync(request, cancellationToken);
    }
}

SubdirectoryHandler est utilisé lors de la création du canal gRPC.

var handler = new SubdirectoryHandler(new HttpClientHandler(), "/MyApp");

var channel = GrpcChannel.ForAddress("https://localhost:5001", new GrpcChannelOptions { HttpHandler = handler });
var client = new Greeter.GreeterClient(channel);

var reply = await client.SayHelloAsync(
                  new HelloRequest { Name = "GreeterClient" });

Le code précédent :

  • Crée un SubdirectoryHandler avec le chemin /MyApp.
  • Configure un canal pour utiliser SubdirectoryHandler.
  • Appelle le service gRPC avec SayHelloAsync. L’appel gRPC est envoyé à https://localhost:5001/MyApp/greet.Greeter/SayHello.

Vous pouvez également configurer une fabrique cliente avec SubdirectoryHandler à l’aide de AddHttpMessageHandler.

Configurer le client gRPC pour utiliser HTTP/3

Le client gRPC .NET prend en charge HTTP/3 avec .NET 6 ou version ultérieure. Si le serveur envoie un en-tête de réponse alt-svc au client qui indique que le serveur prend en charge HTTP/3, le client met automatiquement à niveau sa connexion en HTTP/3. Pour plus d’informations, consultez Utiliser HTTP/3 avec le serveur web ASP.NET Core Kestrel.

Un DelegatingHandler peut être utilisé pour forcer un client gRPC à utiliser HTTP/3. Le fait de forcer HTTP/3 évite la surcharge liée à la mise à niveau de la requête. Forcez HTTP/3 avec du code similaire à ce qui suit :

public class Http3Handler : DelegatingHandler
{
    public Http3Handler() { }
    public Http3Handler(HttpMessageHandler innerHandler) : base(innerHandler) { }

    protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    {
        request.Version = HttpVersion.Version30;
        request.VersionPolicy = HttpVersionPolicy.RequestVersionExact;

        return base.SendAsync(request, cancellationToken);
    }
}

Http3Handler est utilisé lors de la création du canal gRPC. Le code suivant crée un canal configuré pour utiliser Http3Handler.

var handler = new Http3Handler(new HttpClientHandler());

var channel = GrpcChannel.ForAddress("https://localhost:5001", new GrpcChannelOptions { HttpHandler = handler });
var client = new Greeter.GreeterClient(channel);

var reply = await client.SayHelloAsync(
                  new HelloRequest { Name = "GreeterClient" });

Vous pouvez également configurer une fabrique cliente avec Http3Handler à l’aide de AddHttpMessageHandler.

Génération de gRPC sur Alpine Linux

Le package Grpc.Tools génère des types .NET à partir de fichiers .proto à l’aide d’un binaire natif groupé appelé protoc. Des étapes supplémentaires sont nécessaires pour générer des applications gRPC sur des plateformes qui ne sont pas prises en charge par les fichiers binaires natifs dans Grpc.Tools, comme Alpine Linux.

Générer du code à l’avance

Une solution consiste à générer du code à l’avance.

  1. Déplacez les fichiers .proto et la référence de package Grpc.Tools vers un nouveau projet.
  2. Publiez le projet en tant que package NuGet et chargez-le dans un flux NuGet.
  3. Mettez à jour l’application pour référencer le package NuGet.

Avec les étapes précédentes, l’application n’a plus besoin de Grpc.Tools pour se générer, car le code est généré à l’avance.

Personnaliser les fichiers binaires natifs Grpc.Tools

Grpc.Tools prend en charge l’utilisation de fichiers binaires natifs personnalisés. Cette fonctionnalité permet aux outils gRPC de s’exécuter dans les environnements que ses fichiers binaires natifs groupés ne prennent pas en charge.

Générez ou obtenez des fichiers binaires natifs protoc et grpc_csharp_plugin, et configurez Grpc.Tools pour les utiliser. Configurez des fichiers binaires natifs en définissant les variables d’environnement suivantes :

  • PROTOBUF_PROTOC : chemin complet du compilateur de tampons de protocole
  • GRPC_PROTOC_PLUGIN : chemin complet du grpc_csharp_plugin

Pour Alpine Linux, il existe des packages fournis par la communauté pour le compilateur de tampons de protocole et les plug-ins gRPC à l’adresse https://pkgs.alpinelinux.org/.

# Build or install the binaries for your architecture.

# For Alpine Linux, the grpc-plugins package can be used.
# See https://pkgs.alpinelinux.org/package/edge/community/x86_64/grpc-plugins
apk add grpc-plugins  # Alpine Linux specific package installer

# Set environment variables for the built/installed protoc
# and grpc_csharp_plugin binaries
export PROTOBUF_PROTOC=/usr/bin/protoc
export GRPC_PROTOC_PLUGIN=/usr/bin/grpc_csharp_plugin

# When dotnet build runs, the Grpc.Tools NuGet package
# uses the binaries pointed to by the environment variables.
dotnet build

Pour plus d’informations sur l’utilisation de Grpc.Tools avec des architectures non prises en charge, consultez la documentation d’intégration de build gRPC.

délai d’expiration appel gRPC à partir de HttpClient.Timeout

HttpClient est configuré par défaut avec un délai d’expiration de 100 secondes. Si un GrpcChannel est configuré pour utiliser un HttpClient, les appel de streaming gRPC à long terme sont annulés s’ils ne sont pas exécutés dans la limite du délai d’expiration.

System.OperationCanceledException: The request was canceled due to the configured HttpClient.Timeout of 100 seconds elapsing.

Deux méthodes permettent de corriger cette erreur. La première consiste à configurer HttpClient.Timeout sur une valeur plus grande. Timeout.InfiniteTimeSpan désactive le délai d’expiration :

var handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback = 
    HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

var httpClient = new HttpClient(handler) { Timeout = Timeout.InfiniteTimeSpan };
var channel = GrpcChannel.ForAddress("https://localhost:5001",
    new GrpcChannelOptions { HttpClient = httpClient });
var client = new Greeter.GreeterClient(channel);

Vous pouvez également éviter de créer HttpClient et définir GrpcChannel.HttpHandler à la place :

var handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback = 
    HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

var channel = GrpcChannel.ForAddress("https://localhost:5001",
    new GrpcChannelOptions { HttpHandler = handler });
var client = new Greeter.GreeterClient(channel);

Ce document décrit les problèmes fréquemment rencontrés lors du développement d’applications gRPC sur .NET.

Incompatibilité entre la configuration SSL/TLS du client et du service

Le modèle gRPC et les exemples utilisent TLS (Transport Layer Security) pour sécuriser les services gRPC par défaut. Les clients gRPC doivent utiliser une connexion sécurisée pour appeler les services gRPC sécurisés correctement.

Vous pouvez vérifier que le service gRPC ASP.NET Core utilise TLS dans les journaux écrits au démarrage de l’application. Le service écoute sur un point de terminaison HTTPS :

info: Microsoft.Hosting.Lifetime[0]
      Now listening on: https://localhost:5001
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development

Le client .NET Core doit utiliser https dans l’adresse du serveur pour effectuer des appels avec une connexion sécurisée :

static async Task Main(string[] args)
{
    // The port number(5001) must match the port of the gRPC server.
    var channel = GrpcChannel.ForAddress("https://localhost:5001");
    var client = new Greet.GreeterClient(channel);
}

Toutes les implémentations de client gRPC prennent en charge TLS. Les clients gRPC d’autres langages nécessitent généralement le canal configuré avec SslCredentials. SslCredentials spécifie le certificat que le client utilisera, et il doit être utilisé au lieu d’informations d’identification non sécurisées. Pour obtenir des exemples de configuration des différentes implémentations de client gRPC pour utiliser TLS, consultez Authentification gRPC.

Appeler un service gRPC avec un certificat non approuvé/non valide

Le client gRPC .NET exige que le service dispose d’un certificat approuvé. Le message d’erreur suivant est retourné lors de l’appel d’un service gRPC sans certificat approuvé :

Exception non gérée. System.Net.Http.HttpRequestException : La connexion SSL n’a pas pu être établie, voir l’exception interne. ---> System.Security.Authentication.AuthenticationException : Le certificat distant n’est pas valide selon la procédure de validation.

Cette erreur peut s’afficher si vous testez votre application localement et que le certificat de développement HTTPS ASP.NET Core n’est pas approuvé. Pour obtenir des instructions afin de résoudre ce problème, consultez Faire confiance au certificat de développement ASP.NET Core HTTPS sur Windows et macOS.

Si vous appelez un service gRPC sur un autre ordinateur et que vous ne pouvez pas approuver le certificat, le client gRPC peut être configuré pour ignorer le certificat non valide. Le code suivant utilise HttpClientHandler.ServerCertificateCustomValidationCallback pour autoriser les appels sans certificat approuvé :

var handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback = 
    HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

var channel = GrpcChannel.ForAddress("https://localhost:5001",
    new GrpcChannelOptions { HttpHandler = handler });
var client = new Greet.GreeterClient(channel);

La fabrique de client gRPC autorise les appels sans certificat approuvé. Utilise la méthode d’extension ConfigurePrimaryHttpMessageHandler pour configurer le gestionnaire sur le client :

builder.Services
    .AddGrpcClient<Greeter.GreeterClient>(o =>
    {
        o.Address = new Uri("https://localhost:5001");
    })
    .ConfigurePrimaryHttpMessageHandler(() =>
    {
        var handler = new HttpClientHandler();
        handler.ServerCertificateCustomValidationCallback = 
            HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

        return handler;
    });

Warning

Les certificats non approuvés doivent uniquement être utilisés pendant le développement d’applications. Les applications de production doivent toujours utiliser des certificats valides.

Appeler des services gRPC non sécurisés avec le client .NET Core

Le client gRPC .NET peut appeler des services gRPC non sécurisés en spécifiant http dans l’adresse du serveur. Par exemple, GrpcChannel.ForAddress("http://localhost:5000").

Il existe d’autres conditions requises pour appeler des services gRPC non sécurisés en fonction de la version .NET qu’une application utilise :

  • .NET 5 ou version ultérieure nécessite Grpc.Net.Client version 2.32.0 ou ultérieure.

  • .NET Core 3.x nécessite une configuration supplémentaire. L’application doit définir le commutateur System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport sur true :

    // This switch must be set before creating the GrpcChannel/HttpClient.
    AppContext.SetSwitch(
        "System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);
    
    // The port number(5000) must match the port of the gRPC server.
    var channel = GrpcChannel.ForAddress("http://localhost:5000");
    var client = new Greet.GreeterClient(channel);
    

Le commutateur System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport n’est requis que pour .NET Core 3.x. Il ne fait rien dans .NET 5 et n’est pas obligatoire.

Important

Les services gRPC non sécurisés doivent être hébergés sur un port HTTP/2 uniquement. Pour plus d’informations, consultez Négociation de protocole ASP.NET Core.

Impossible de démarrer l’application ASP.NET Core gRPC sur macOS

Kestrel ne prend pas en charge HTTP/2 avec TLS sur macOS avant .NET 8. Le modèle gRPC ASP.NET Core et les exemples utilisent TLS par défaut. Le message d’erreur suivant s’affiche lorsque vous tentez de démarrer le serveur gRPC :

Impossible de lier à https://localhost:5001 sur l’interface de bouclage IPv4 : « HTTP/2 sur TLS n’est pas pris en charge sur macOS en raison d’une prise en charge d’ALPN manquante. ».

Pour contourner ce problème dans .NET 7 et versions antérieures, configurez Kestrel et le client gRPC pour utiliser HTTP/2 sans TLS. Vous ne devez effectuer cette opération que pendant le développement. Le fait de ne pas utiliser TLS entraîne l’envoi de messages gRPC sans chiffrement.

Kestrel doit configurer un point de terminaison HTTP/2 sans TLS dans Program.cs :

var builder = WebApplication.CreateBuilder(args);

builder.WebHost.ConfigureKestrel(options =>
{
    // Setup a HTTP/2 endpoint without TLS.
    options.ListenLocalhost(<5287>, o => o.Protocols =
        HttpProtocols.Http2);
});
  • Dans le code précédent, remplacez le numéro de port localhost 5287 par le numéro de port HTTP (et non HTTPS) spécifié dans Properties/launchSettings.json au sein du projet de service gRPC.

Lorsqu’un point de terminaison HTTP/2 est configuré sans TLS, le paramètre ListenOptions.Protocols du point de terminaison doit être défini sur HttpProtocols.Http2. HttpProtocols.Http1AndHttp2 ne peut pas être utilisé, car TLS est requis pour les négociations HTTP/2. Sans TLS, toutes les connexions au point de terminaison par défaut sont HTTP/1.1, et les appels gRPC échouent.

Le client gRPC doit également être configuré pour ne pas utiliser TLS. Pour plus d’informations, consultez Appeler des services gRPC non sécurisés avec le client .NET Core.

Warning

HTTP/2 sans TLS ne doit être utilisé que pendant le développement d’applications. Les applications de production doivent toujours utiliser la sécurité du transport. Pour plus d’informations, consultez Considérations sur la sécurité dans gRPC pour ASP.NET Core

Le code des ressources C# gRPC n’est pas généré à partir de fichiers .proto

La génération de code gRPC de clients concrets et de classes de base de service nécessite que les fichiers protobuf et les outils soient référencés à partir d’un projet. Vous devez inclure :

  • Les fichiers .proto que vous souhaitez utiliser dans le groupe d’éléments <Protobuf>. Les fichiers .proto importés doivent être référencés par le projet.
  • Une référence de package au package d’outils gRPC Grpc.Tools.

Pour plus d’informations sur la génération de ressources C# gRPC, consultez Services gRPC avec C#.

Une application web ASP.NET Core hébergeant des services gRPC a uniquement besoin de la classe de base de service générée :

<ItemGroup>
  <Protobuf Include="Protos\greet.proto" GrpcServices="Server" />
</ItemGroup>

Une application cliente gRPC effectuant des appels gRPC a uniquement besoin du client concret généré :

<ItemGroup>
  <Protobuf Include="Protos\greet.proto" GrpcServices="Client" />
</ItemGroup>

Les projets WPF ne peuvent pas générer de ressources C# gRPC à partir de fichiers .proto

Les projets WPF présentent un problème connu qui empêche la génération de code gRPC de fonctionner correctement. Tous les types gRPC générés dans un projet WPF en référençant les fichiers Grpc.Tools et .proto créent des erreurs de compilation lorsqu’ils sont utilisés :

Erreur CS0246 : Le type ou le nom de l’espace de noms « MyGrpcServices » est introuvable (une directive using ou une référence d’assembly est-elle manquante ?)

Vous pouvez contourner ce problème en procédant comme suit :

  1. Créez un projet de bibliothèque de classes .NET Core.
  2. Dans le nouveau projet, ajoutez des références pour activer la génération de code C# à partir de fichiers .proto :
  3. Dans l’application WPF, ajoutez une référence au nouveau projet.

L’application WPF peut utiliser les types générés par gRPC à partir du nouveau projet de bibliothèque de classes.

Appel de services gRPC hébergés dans un sous-répertoire

Warning

De nombreux outils gRPC tiers ne prennent pas en charge les services hébergés dans des sous-répertoires. Envisagez de trouver un moyen d’héberger gRPC en tant que répertoire racine.

Le composant de chemin d’accès de l’adresse d’un canal gRPC est ignoré lors des appels gRPC. Par exemple, GrpcChannel.ForAddress("https://localhost:5001/ignored_path") n’utilise pas ignored_path lors du routage des appels gRPC pour le service.

Le chemin d’accès à l’adresse est ignoré, car gRPC a une structure d’adresse normalisée et normative. Une adresse gRPC combine les noms de package, de service et de méthode : https://localhost:5001/PackageName.ServiceName/MethodName.

Il existe certains scénarios où une application doit inclure un chemin d’accès avec des appels gRPC. Par exemple, lorsqu’une application gRPC ASP.NET Core est hébergée dans un répertoire IIS et que le répertoire doit être inclus dans la requête. Lorsqu’un chemin d’accès est requis, il peut être ajouté à l’appel gRPC à l’aide du SubdirectoryHandler personnalisé spécifié ci-dessous :

/// <summary>
/// A delegating handler that adds a subdirectory to the URI of gRPC requests.
/// </summary>
public class SubdirectoryHandler : DelegatingHandler
{
    private readonly string _subdirectory;

    public SubdirectoryHandler(HttpMessageHandler innerHandler, string subdirectory)
        : base(innerHandler)
    {
        _subdirectory = subdirectory;
    }

    protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var old = request.RequestUri;

        var url = $"{old.Scheme}://{old.Host}:{old.Port}";
        url += $"{_subdirectory}{request.RequestUri.AbsolutePath}";
        request.RequestUri = new Uri(url, UriKind.Absolute);

        return base.SendAsync(request, cancellationToken);
    }
}

SubdirectoryHandler est utilisé lors de la création du canal gRPC.

var handler = new SubdirectoryHandler(new HttpClientHandler(), "/MyApp");

var channel = GrpcChannel.ForAddress("https://localhost:5001", new GrpcChannelOptions { HttpHandler = handler });
var client = new Greet.GreeterClient(channel);

var reply = await client.SayHelloAsync(new HelloRequest { Name = ".NET" });

Le code précédent :

  • Crée un SubdirectoryHandler avec le chemin /MyApp.
  • Configure un canal pour utiliser SubdirectoryHandler.
  • Appelle le service gRPC avec SayHelloAsync. L’appel gRPC est envoyé à https://localhost:5001/MyApp/greet.Greeter/SayHello.

Vous pouvez également configurer une fabrique cliente avec SubdirectoryHandler à l’aide de AddHttpMessageHandler.

Configurer le client gRPC pour utiliser HTTP/3

Le client gRPC .NET prend en charge HTTP/3 avec .NET 6 ou version ultérieure. Si le serveur envoie un en-tête de réponse alt-svc au client qui indique que le serveur prend en charge HTTP/3, le client met automatiquement à niveau sa connexion en HTTP/3. Pour plus d’informations sur l’activation de HTTP/3 sur le serveur, consultez Utiliser HTTP/3 avec le serveur web ASP.NET Core Kestrel.

La prise en charge de HTTP/3 dans .NET 8 est activée par défaut. La prise en charge de HTTP/3 dans .NET 6 et .NET 7 doit être activée via un indicateur de configuration dans le fichier projet :

<ItemGroup>
  <RuntimeHostConfigurationOption Include="System.Net.SocketsHttpHandler.Http3Support" Value="true" />
</ItemGroup>

System.Net.SocketsHttpHandler.Http3Support peut également être défini à l’aide d’AppContext.SetSwitch.

Un DelegatingHandler peut être utilisé pour forcer un client gRPC à utiliser HTTP/3. Le fait de forcer HTTP/3 évite la surcharge liée à la mise à niveau de la requête. Forcez HTTP/3 avec du code similaire à ce qui suit :

/// <summary>
/// A delegating handler that changes the request HTTP version to HTTP/3.
/// </summary>
public class Http3Handler : DelegatingHandler
{
    public Http3Handler() { }
    public Http3Handler(HttpMessageHandler innerHandler) : base(innerHandler) { }

    protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    {
        request.Version = HttpVersion.Version30;
        request.VersionPolicy = HttpVersionPolicy.RequestVersionExact;

        return base.SendAsync(request, cancellationToken);
    }
}

Http3Handler est utilisé lors de la création du canal gRPC. Le code suivant crée un canal configuré pour utiliser Http3Handler.

var handler = new Http3Handler(new HttpClientHandler());

var channel = GrpcChannel.ForAddress("https://localhost:5001", new GrpcChannelOptions { HttpHandler = handler });
var client = new Greet.GreeterClient(channel);

var reply = await client.SayHelloAsync(new HelloRequest { Name = ".NET" });

Vous pouvez également configurer une fabrique cliente avec Http3Handler à l’aide de AddHttpMessageHandler.

Génération de gRPC sur Alpine Linux

Le package Grpc.Tools génère des types .NET à partir de fichiers .proto à l’aide d’un binaire natif groupé appelé protoc. Des étapes supplémentaires sont nécessaires pour générer des applications gRPC sur des plateformes qui ne sont pas prises en charge par les fichiers binaires natifs dans Grpc.Tools, comme Alpine Linux.

Générer du code à l’avance

Une solution consiste à générer du code à l’avance.

  1. Déplacez les fichiers .proto et la référence de package Grpc.Tools vers un nouveau projet.
  2. Publiez le projet en tant que package NuGet et chargez-le dans un flux NuGet.
  3. Mettez à jour l’application pour référencer le package NuGet.

Avec les étapes précédentes, l’application n’a plus besoin de Grpc.Tools pour se générer, car le code est généré à l’avance.

Personnaliser les fichiers binaires natifs Grpc.Tools

Grpc.Tools prend en charge l’utilisation de fichiers binaires natifs personnalisés. Cette fonctionnalité permet aux outils gRPC de s’exécuter dans les environnements que ses fichiers binaires natifs groupés ne prennent pas en charge.

Générez ou obtenez des fichiers binaires natifs protoc et grpc_csharp_plugin, et configurez Grpc.Tools pour les utiliser. Configurez des fichiers binaires natifs en définissant les variables d’environnement suivantes :

  • PROTOBUF_PROTOC : chemin complet du compilateur de tampons de protocole
  • GRPC_PROTOC_PLUGIN : chemin complet du grpc_csharp_plugin

Pour Alpine Linux, il existe des packages fournis par la communauté pour le compilateur de tampons de protocole et les plug-ins gRPC à l’adresse https://pkgs.alpinelinux.org/.

# Build or install the binaries for your architecture.

# For Alpine Linux, the grpc-plugins package can be used.
#  See https://pkgs.alpinelinux.org/package/edge/community/x86_64/grpc-plugins
apk add grpc-plugins  # Alpine Linux specific package installer

# Set environment variables for the built/installed protoc
# and grpc_csharp_plugin binaries
export PROTOBUF_PROTOC=/usr/bin/protoc
export GRPC_PROTOC_PLUGIN=/usr/bin/grpc_csharp_plugin

# When dotnet build runs, the Grpc.Tools NuGet package
# uses the binaries pointed to by the environment variables.
dotnet build

Pour plus d’informations sur l’utilisation de Grpc.Tools avec des architectures non prises en charge, consultez la documentation d’intégration de build gRPC.

délai d’expiration appel gRPC à partir de HttpClient.Timeout

HttpClient est configuré par défaut avec un délai d’expiration de 100 secondes. Si un GrpcChannel est configuré pour utiliser un HttpClient, les appel de streaming gRPC à long terme sont annulés s’ils ne sont pas exécutés dans la limite du délai d’expiration.

System.OperationCanceledException: The request was canceled due to the configured HttpClient.Timeout of 100 seconds elapsing.

Deux méthodes permettent de corriger cette erreur. La première consiste à configurer HttpClient.Timeout sur une valeur plus grande. Timeout.InfiniteTimeSpan désactive le délai d’expiration :

var handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback = 
    HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

var httpClient = new HttpClient(handler) { Timeout = Timeout.InfiniteTimeSpan };
var channel = GrpcChannel.ForAddress("https://localhost:5001",
    new GrpcChannelOptions { HttpClient = httpClient });
var client = new Greeter.GreeterClient(channel);

Vous pouvez également éviter de créer HttpClient et définir GrpcChannel.HttpHandler à la place :

var handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback = 
    HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

var channel = GrpcChannel.ForAddress("https://localhost:5001",
    new GrpcChannelOptions { HttpHandler = handler });
var client = new Greeter.GreeterClient(channel);

Ce document décrit les problèmes fréquemment rencontrés lors du développement d’applications gRPC sur .NET.

Incompatibilité entre la configuration SSL/TLS du client et du service

Le modèle gRPC et les exemples utilisent TLS (Transport Layer Security) pour sécuriser les services gRPC par défaut. Les clients gRPC doivent utiliser une connexion sécurisée pour appeler les services gRPC sécurisés correctement.

Vous pouvez vérifier que le service gRPC ASP.NET Core utilise TLS dans les journaux écrits au démarrage de l’application. Le service écoute sur un point de terminaison HTTPS :

info: Microsoft.Hosting.Lifetime[0]
      Now listening on: https://localhost:5001
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development

Le client .NET Core doit utiliser https dans l’adresse du serveur pour effectuer des appels avec une connexion sécurisée :

static async Task Main(string[] args)
{
    // The port number(5001) must match the port of the gRPC server.
    var channel = GrpcChannel.ForAddress("https://localhost:5001");
    var client = new Greet.GreeterClient(channel);
}

Toutes les implémentations de client gRPC prennent en charge TLS. Les clients gRPC d’autres langages nécessitent généralement le canal configuré avec SslCredentials. SslCredentials spécifie le certificat que le client utilisera, et il doit être utilisé au lieu d’informations d’identification non sécurisées. Pour obtenir des exemples de configuration des différentes implémentations de client gRPC pour utiliser TLS, consultez Authentification gRPC.

Appeler un service gRPC avec un certificat non approuvé/non valide

Le client gRPC .NET exige que le service dispose d’un certificat approuvé. Le message d’erreur suivant est retourné lors de l’appel d’un service gRPC sans certificat approuvé :

Exception non gérée. System.Net.Http.HttpRequestException : La connexion SSL n’a pas pu être établie, voir l’exception interne. ---> System.Security.Authentication.AuthenticationException : Le certificat distant n’est pas valide selon la procédure de validation.

Cette erreur peut s’afficher si vous testez votre application localement et que le certificat de développement HTTPS ASP.NET Core n’est pas approuvé. Pour obtenir des instructions afin de résoudre ce problème, consultez Faire confiance au certificat de développement ASP.NET Core HTTPS sur Windows et macOS.

Si vous appelez un service gRPC sur un autre ordinateur et que vous ne pouvez pas approuver le certificat, le client gRPC peut être configuré pour ignorer le certificat non valide. Le code suivant utilise HttpClientHandler.ServerCertificateCustomValidationCallback pour autoriser les appels sans certificat approuvé :

var handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback = 
    HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

var channel = GrpcChannel.ForAddress("https://localhost:5001",
    new GrpcChannelOptions { HttpHandler = handler });
var client = new Greet.GreeterClient(channel);

La fabrique de client gRPC autorise les appels sans certificat approuvé. Utilise la méthode d’extension ConfigurePrimaryHttpMessageHandler pour configurer le gestionnaire sur le client :

services
    .AddGrpcClient<Greeter.GreeterClient>(o =>
    {
        o.Address = new Uri("https://localhost:5001");
    })
    .ConfigurePrimaryHttpMessageHandler(() =>
    {
        var handler = new HttpClientHandler();
        handler.ServerCertificateCustomValidationCallback = 
            HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

        return handler;
    });

Warning

Les certificats non approuvés doivent uniquement être utilisés pendant le développement d’applications. Les applications de production doivent toujours utiliser des certificats valides.

Appeler des services gRPC non sécurisés avec le client .NET Core

Le client gRPC .NET peut appeler des services gRPC non sécurisés en spécifiant http dans l’adresse du serveur. Par exemple, GrpcChannel.ForAddress("http://localhost:5000").

Il existe d’autres conditions requises pour appeler des services gRPC non sécurisés en fonction de la version .NET qu’une application utilise :

  • .NET 5 ou version ultérieure nécessite Grpc.Net.Client version 2.32.0 ou ultérieure.

  • .NET Core 3.x nécessite une configuration supplémentaire. L’application doit définir le commutateur System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport sur true :

    // This switch must be set before creating the GrpcChannel/HttpClient.
    AppContext.SetSwitch(
        "System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);
    
    // The port number(5000) must match the port of the gRPC server.
    var channel = GrpcChannel.ForAddress("http://localhost:5000");
    var client = new Greet.GreeterClient(channel);
    

Le commutateur System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport n’est requis que pour .NET Core 3.x. Il ne fait rien dans .NET 5 et n’est pas obligatoire.

Important

Les services gRPC non sécurisés doivent être hébergés sur un port HTTP/2 uniquement. Pour plus d’informations, consultez Négociation de protocole ASP.NET Core.

Impossible de démarrer l’application ASP.NET Core gRPC sur macOS

Kestrel ne prend pas en charge HTTP/2 avec TLS sur macOS avant .NET 8. Le modèle gRPC ASP.NET Core et les exemples utilisent TLS par défaut. Le message d’erreur suivant s’affiche lorsque vous tentez de démarrer le serveur gRPC :

Impossible de lier à https://localhost:5001 sur l’interface de bouclage IPv4 : « HTTP/2 sur TLS n’est pas pris en charge sur macOS en raison d’une prise en charge d’ALPN manquante. ».

Pour contourner ce problème dans .NET 7 et versions antérieures, configurez Kestrel et le client gRPC pour utiliser HTTP/2 sans TLS. Vous ne devez effectuer cette opération que pendant le développement. Le fait de ne pas utiliser TLS entraîne l’envoi de messages gRPC sans chiffrement.

Kestrel doit configurer un point de terminaison HTTP/2 sans TLS dans Program.cs :

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.ConfigureKestrel(options =>
            {
                // Setup a HTTP/2 endpoint without TLS.
                options.ListenLocalhost(5000, o => o.Protocols = 
                    HttpProtocols.Http2);
            });
            webBuilder.UseStartup<Startup>();
        });

Lorsqu’un point de terminaison HTTP/2 est configuré sans TLS, le paramètre ListenOptions.Protocols du point de terminaison doit être défini sur HttpProtocols.Http2. HttpProtocols.Http1AndHttp2 ne peut pas être utilisé, car TLS est requis pour les négociations HTTP/2. Sans TLS, toutes les connexions au point de terminaison par défaut sont HTTP/1.1, et les appels gRPC échouent.

Le client gRPC doit également être configuré pour ne pas utiliser TLS. Pour plus d’informations, consultez Appeler des services gRPC non sécurisés avec le client .NET Core.

Warning

HTTP/2 sans TLS ne doit être utilisé que pendant le développement d’applications. Les applications de production doivent toujours utiliser la sécurité du transport. Pour plus d’informations, consultez Considérations sur la sécurité dans gRPC pour ASP.NET Core

Le code des ressources C# gRPC n’est pas généré à partir de fichiers .proto

La génération de code gRPC de clients concrets et de classes de base de service nécessite que les fichiers protobuf et les outils soient référencés à partir d’un projet. Vous devez inclure :

  • Les fichiers .proto que vous souhaitez utiliser dans le groupe d’éléments <Protobuf>. Les fichiers .proto importés doivent être référencés par le projet.
  • Une référence de package au package d’outils gRPC Grpc.Tools.

Pour plus d’informations sur la génération de ressources C# gRPC, consultez Services gRPC avec C#.

Une application web ASP.NET Core hébergeant des services gRPC a uniquement besoin de la classe de base de service générée :

<ItemGroup>
  <Protobuf Include="Protos\greet.proto" GrpcServices="Server" />
</ItemGroup>

Une application cliente gRPC effectuant des appels gRPC a uniquement besoin du client concret généré :

<ItemGroup>
  <Protobuf Include="Protos\greet.proto" GrpcServices="Client" />
</ItemGroup>

Les projets WPF ne peuvent pas générer de ressources C# gRPC à partir de fichiers .proto

Les projets WPF présentent un problème connu qui empêche la génération de code gRPC de fonctionner correctement. Tous les types gRPC générés dans un projet WPF en référençant les fichiers Grpc.Tools et .proto créent des erreurs de compilation lorsqu’ils sont utilisés :

Erreur CS0246 : Le type ou le nom de l’espace de noms « MyGrpcServices » est introuvable (une directive using ou une référence d’assembly est-elle manquante ?)

Vous pouvez contourner ce problème en procédant comme suit :

  1. Créez un projet de bibliothèque de classes .NET Core.
  2. Dans le nouveau projet, ajoutez des références pour activer la génération de code C# à partir de fichiers .proto :
  3. Dans l’application WPF, ajoutez une référence au nouveau projet.

L’application WPF peut utiliser les types générés par gRPC à partir du nouveau projet de bibliothèque de classes.

Appel de services gRPC hébergés dans un sous-répertoire

Warning

De nombreux outils gRPC tiers ne prennent pas en charge les services hébergés dans des sous-répertoires. Envisagez de trouver un moyen d’héberger gRPC en tant que répertoire racine.

Le composant de chemin d’accès de l’adresse d’un canal gRPC est ignoré lors des appels gRPC. Par exemple, GrpcChannel.ForAddress("https://localhost:5001/ignored_path") n’utilise pas ignored_path lors du routage des appels gRPC pour le service.

Le chemin d’accès à l’adresse est ignoré, car gRPC a une structure d’adresse normalisée et normative. Une adresse gRPC combine les noms de package, de service et de méthode : https://localhost:5001/PackageName.ServiceName/MethodName.

Il existe certains scénarios où une application doit inclure un chemin d’accès avec des appels gRPC. Par exemple, lorsqu’une application gRPC ASP.NET Core est hébergée dans un répertoire IIS et que le répertoire doit être inclus dans la requête. Lorsqu’un chemin d’accès est requis, il peut être ajouté à l’appel gRPC à l’aide du SubdirectoryHandler personnalisé spécifié ci-dessous :

/// <summary>
/// A delegating handler that adds a subdirectory to the URI of gRPC requests.
/// </summary>
public class SubdirectoryHandler : DelegatingHandler
{
    private readonly string _subdirectory;

    public SubdirectoryHandler(HttpMessageHandler innerHandler, string subdirectory)
        : base(innerHandler)
    {
        _subdirectory = subdirectory;
    }

    protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var old = request.RequestUri;

        var url = $"{old.Scheme}://{old.Host}:{old.Port}";
        url += $"{_subdirectory}{request.RequestUri.AbsolutePath}";
        request.RequestUri = new Uri(url, UriKind.Absolute);

        return base.SendAsync(request, cancellationToken);
    }
}

SubdirectoryHandler est utilisé lors de la création du canal gRPC.

var handler = new SubdirectoryHandler(new HttpClientHandler(), "/MyApp");

var channel = GrpcChannel.ForAddress("https://localhost:5001", new GrpcChannelOptions { HttpHandler = handler });
var client = new Greet.GreeterClient(channel);

var reply = await client.SayHelloAsync(new HelloRequest { Name = ".NET" });

Le code précédent :

  • Crée un SubdirectoryHandler avec le chemin /MyApp.
  • Configure un canal pour utiliser SubdirectoryHandler.
  • Appelle le service gRPC avec SayHelloAsync. L’appel gRPC est envoyé à https://localhost:5001/MyApp/greet.Greeter/SayHello.

Vous pouvez également configurer une fabrique cliente avec SubdirectoryHandler à l’aide de AddHttpMessageHandler.

délai d’expiration appel gRPC à partir de HttpClient.Timeout

HttpClient est configuré par défaut avec un délai d’expiration de 100 secondes. Si un GrpcChannel est configuré pour utiliser un HttpClient, les appel de streaming gRPC à long terme sont annulés s’ils ne sont pas exécutés dans la limite du délai d’expiration.

System.OperationCanceledException: The request was canceled due to the configured HttpClient.Timeout of 100 seconds elapsing.

Deux méthodes permettent de corriger cette erreur. La première consiste à configurer HttpClient.Timeout sur une valeur plus grande. Timeout.InfiniteTimeSpan désactive le délai d’expiration :

var handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback = 
    HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

var httpClient = new HttpClient(handler) { Timeout = Timeout.InfiniteTimeSpan };
var channel = GrpcChannel.ForAddress("https://localhost:5001",
    new GrpcChannelOptions { HttpClient = httpClient });
var client = new Greeter.GreeterClient(channel);

Vous pouvez également éviter de créer HttpClient et définir GrpcChannel.HttpHandler à la place :

var handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback = 
    HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

var channel = GrpcChannel.ForAddress("https://localhost:5001",
    new GrpcChannelOptions { HttpHandler = handler });
var client = new Greeter.GreeterClient(channel);

Ce document décrit les problèmes fréquemment rencontrés lors du développement d’applications gRPC sur .NET.

Incompatibilité entre la configuration SSL/TLS du client et du service

Le modèle gRPC et les exemples utilisent TLS (Transport Layer Security) pour sécuriser les services gRPC par défaut. Les clients gRPC doivent utiliser une connexion sécurisée pour appeler les services gRPC sécurisés correctement.

Vous pouvez vérifier que le service gRPC ASP.NET Core utilise TLS dans les journaux écrits au démarrage de l’application. Le service écoute sur un point de terminaison HTTPS :

info: Microsoft.Hosting.Lifetime[0]
      Now listening on: https://localhost:5001
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development

Le client .NET Core doit utiliser https dans l’adresse du serveur pour effectuer des appels avec une connexion sécurisée :

static async Task Main(string[] args)
{
    // The port number(5001) must match the port of the gRPC server.
    var channel = GrpcChannel.ForAddress("https://localhost:5001");
    var client = new Greet.GreeterClient(channel);
}

Toutes les implémentations de client gRPC prennent en charge TLS. Les clients gRPC d’autres langages nécessitent généralement le canal configuré avec SslCredentials. SslCredentials spécifie le certificat que le client utilisera, et il doit être utilisé au lieu d’informations d’identification non sécurisées. Pour obtenir des exemples de configuration des différentes implémentations de client gRPC pour utiliser TLS, consultez Authentification gRPC.

Appeler un service gRPC avec un certificat non approuvé/non valide

Le client gRPC .NET exige que le service dispose d’un certificat approuvé. Le message d’erreur suivant est retourné lors de l’appel d’un service gRPC sans certificat approuvé :

Exception non gérée. System.Net.Http.HttpRequestException : La connexion SSL n’a pas pu être établie, voir l’exception interne. ---> System.Security.Authentication.AuthenticationException : Le certificat distant n’est pas valide selon la procédure de validation.

Cette erreur peut s’afficher si vous testez votre application localement et que le certificat de développement HTTPS ASP.NET Core n’est pas approuvé. Pour obtenir des instructions afin de résoudre ce problème, consultez Faire confiance au certificat de développement ASP.NET Core HTTPS sur Windows et macOS.

Si vous appelez un service gRPC sur un autre ordinateur et que vous ne pouvez pas approuver le certificat, le client gRPC peut être configuré pour ignorer le certificat non valide. Le code suivant utilise HttpClientHandler.ServerCertificateCustomValidationCallback pour autoriser les appels sans certificat approuvé :

var handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback = 
    HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

var channel = GrpcChannel.ForAddress("https://localhost:5001",
    new GrpcChannelOptions { HttpHandler = handler });
var client = new Greet.GreeterClient(channel);

La fabrique de client gRPC autorise les appels sans certificat approuvé. Utilise la méthode d’extension ConfigurePrimaryHttpMessageHandler pour configurer le gestionnaire sur le client :

services
    .AddGrpcClient<Greeter.GreeterClient>(o =>
    {
        o.Address = new Uri("https://localhost:5001");
    })
    .ConfigurePrimaryHttpMessageHandler(() =>
    {
        var handler = new HttpClientHandler();
        handler.ServerCertificateCustomValidationCallback = 
            HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

        return handler;
    });

Warning

Les certificats non approuvés doivent uniquement être utilisés pendant le développement d’applications. Les applications de production doivent toujours utiliser des certificats valides.

Appeler des services gRPC non sécurisés avec le client .NET Core

Le client gRPC .NET peut appeler des services gRPC non sécurisés en spécifiant http dans l’adresse du serveur. Par exemple, GrpcChannel.ForAddress("http://localhost:5000").

Il existe d’autres conditions requises pour appeler des services gRPC non sécurisés en fonction de la version .NET qu’une application utilise :

  • .NET 5 ou version ultérieure nécessite Grpc.Net.Client version 2.32.0 ou ultérieure.

  • .NET Core 3.x nécessite une configuration supplémentaire. L’application doit définir le commutateur System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport sur true :

    // This switch must be set before creating the GrpcChannel/HttpClient.
    AppContext.SetSwitch(
        "System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);
    
    // The port number(5000) must match the port of the gRPC server.
    var channel = GrpcChannel.ForAddress("http://localhost:5000");
    var client = new Greet.GreeterClient(channel);
    

Le commutateur System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport n’est requis que pour .NET Core 3.x. Il ne fait rien dans .NET 5 et n’est pas obligatoire.

Important

Les services gRPC non sécurisés doivent être hébergés sur un port HTTP/2 uniquement. Pour plus d’informations, consultez Négociation de protocole ASP.NET Core.

Impossible de démarrer l’application ASP.NET Core gRPC sur macOS

Kestrel ne prend pas en charge HTTP/2 avec TLS sur macOS avant .NET 8. Le modèle gRPC ASP.NET Core et les exemples utilisent TLS par défaut. Le message d’erreur suivant s’affiche lorsque vous tentez de démarrer le serveur gRPC :

Impossible de lier à https://localhost:5001 sur l’interface de bouclage IPv4 : « HTTP/2 sur TLS n’est pas pris en charge sur macOS en raison d’une prise en charge d’ALPN manquante. ».

Pour contourner ce problème dans .NET 7 et versions antérieures, configurez Kestrel et le client gRPC pour utiliser HTTP/2 sans TLS. Vous ne devez effectuer cette opération que pendant le développement. Le fait de ne pas utiliser TLS entraîne l’envoi de messages gRPC sans chiffrement.

Kestrel doit configurer un point de terminaison HTTP/2 sans TLS dans Program.cs :

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.ConfigureKestrel(options =>
            {
                // Setup a HTTP/2 endpoint without TLS.
                options.ListenLocalhost(5000, o => o.Protocols = 
                    HttpProtocols.Http2);
            });
            webBuilder.UseStartup<Startup>();
        });

Lorsqu’un point de terminaison HTTP/2 est configuré sans TLS, le paramètre ListenOptions.Protocols du point de terminaison doit être défini sur HttpProtocols.Http2. HttpProtocols.Http1AndHttp2 ne peut pas être utilisé, car TLS est requis pour les négociations HTTP/2. Sans TLS, toutes les connexions au point de terminaison par défaut sont HTTP/1.1, et les appels gRPC échouent.

Le client gRPC doit également être configuré pour ne pas utiliser TLS. Pour plus d’informations, consultez Appeler des services gRPC non sécurisés avec le client .NET Core.

Warning

HTTP/2 sans TLS ne doit être utilisé que pendant le développement d’applications. Les applications de production doivent toujours utiliser la sécurité du transport. Pour plus d’informations, consultez Considérations sur la sécurité dans gRPC pour ASP.NET Core

Le code des ressources C# gRPC n’est pas généré à partir de fichiers .proto

La génération de code gRPC de clients concrets et de classes de base de service nécessite que les fichiers protobuf et les outils soient référencés à partir d’un projet. Vous devez inclure :

  • Les fichiers .proto que vous souhaitez utiliser dans le groupe d’éléments <Protobuf>. Les fichiers .proto importés doivent être référencés par le projet.
  • Une référence de package au package d’outils gRPC Grpc.Tools.

Pour plus d’informations sur la génération de ressources C# gRPC, consultez Services gRPC avec C#.

Une application web ASP.NET Core hébergeant des services gRPC a uniquement besoin de la classe de base de service générée :

<ItemGroup>
  <Protobuf Include="Protos\greet.proto" GrpcServices="Server" />
</ItemGroup>

Une application cliente gRPC effectuant des appels gRPC a uniquement besoin du client concret généré :

<ItemGroup>
  <Protobuf Include="Protos\greet.proto" GrpcServices="Client" />
</ItemGroup>

Les projets WPF ne peuvent pas générer de ressources C# gRPC à partir de fichiers .proto

Les projets WPF présentent un problème connu qui empêche la génération de code gRPC de fonctionner correctement. Tous les types gRPC générés dans un projet WPF en référençant les fichiers Grpc.Tools et .proto créent des erreurs de compilation lorsqu’ils sont utilisés :

Erreur CS0246 : Le type ou le nom de l’espace de noms « MyGrpcServices » est introuvable (une directive using ou une référence d’assembly est-elle manquante ?)

Vous pouvez contourner ce problème en procédant comme suit :

  1. Créez un projet de bibliothèque de classes .NET Core.
  2. Dans le nouveau projet, ajoutez des références pour activer la génération de code C# à partir de fichiers .proto :
  3. Dans l’application WPF, ajoutez une référence au nouveau projet.

L’application WPF peut utiliser les types générés par gRPC à partir du nouveau projet de bibliothèque de classes.

Appel de services gRPC hébergés dans un sous-répertoire

Warning

De nombreux outils gRPC tiers ne prennent pas en charge les services hébergés dans des sous-répertoires. Envisagez de trouver un moyen d’héberger gRPC en tant que répertoire racine.

Le composant de chemin d’accès de l’adresse d’un canal gRPC est ignoré lors des appels gRPC. Par exemple, GrpcChannel.ForAddress("https://localhost:5001/ignored_path") n’utilise pas ignored_path lors du routage des appels gRPC pour le service.

Le chemin d’accès à l’adresse est ignoré, car gRPC a une structure d’adresse normalisée et normative. Une adresse gRPC combine les noms de package, de service et de méthode : https://localhost:5001/PackageName.ServiceName/MethodName.

Il existe certains scénarios où une application doit inclure un chemin d’accès avec des appels gRPC. Par exemple, lorsqu’une application gRPC ASP.NET Core est hébergée dans un répertoire IIS et que le répertoire doit être inclus dans la requête. Lorsqu’un chemin d’accès est requis, il peut être ajouté à l’appel gRPC à l’aide du SubdirectoryHandler personnalisé spécifié ci-dessous :

/// <summary>
/// A delegating handler that adds a subdirectory to the URI of gRPC requests.
/// </summary>
public class SubdirectoryHandler : DelegatingHandler
{
    private readonly string _subdirectory;

    public SubdirectoryHandler(HttpMessageHandler innerHandler, string subdirectory)
        : base(innerHandler)
    {
        _subdirectory = subdirectory;
    }

    protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var old = request.RequestUri;

        var url = $"{old.Scheme}://{old.Host}:{old.Port}";
        url += $"{_subdirectory}{request.RequestUri.AbsolutePath}";
        request.RequestUri = new Uri(url, UriKind.Absolute);

        return base.SendAsync(request, cancellationToken);
    }
}

SubdirectoryHandler est utilisé lors de la création du canal gRPC.

var handler = new SubdirectoryHandler(new HttpClientHandler(), "/MyApp");

var channel = GrpcChannel.ForAddress("https://localhost:5001", new GrpcChannelOptions { HttpHandler = handler });
var client = new Greet.GreeterClient(channel);

var reply = await client.SayHelloAsync(new HelloRequest { Name = ".NET" });

Le code précédent :

  • Crée un SubdirectoryHandler avec le chemin /MyApp.
  • Configure un canal pour utiliser SubdirectoryHandler.
  • Appelle le service gRPC avec SayHelloAsync. L’appel gRPC est envoyé à https://localhost:5001/MyApp/greet.Greeter/SayHello.

Vous pouvez également configurer une fabrique cliente avec SubdirectoryHandler à l’aide de AddHttpMessageHandler.

délai d’expiration appel gRPC à partir de HttpClient.Timeout

HttpClient est configuré par défaut avec un délai d’expiration de 100 secondes. Si un GrpcChannel est configuré pour utiliser un HttpClient, les appel de streaming gRPC à long terme sont annulés s’ils ne sont pas exécutés dans la limite du délai d’expiration.

System.OperationCanceledException: The request was canceled due to the configured HttpClient.Timeout of 100 seconds elapsing.

Deux méthodes permettent de corriger cette erreur. La première consiste à configurer HttpClient.Timeout sur une valeur plus grande. Timeout.InfiniteTimeSpan désactive le délai d’expiration :

var handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback = 
    HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

var httpClient = new HttpClient(handler) { Timeout = Timeout.InfiniteTimeSpan };
var channel = GrpcChannel.ForAddress("https://localhost:5001",
    new GrpcChannelOptions { HttpClient = httpClient });
var client = new Greeter.GreeterClient(channel);

Vous pouvez également éviter de créer HttpClient et définir GrpcChannel.HttpHandler à la place :

var handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback = 
    HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

var channel = GrpcChannel.ForAddress("https://localhost:5001",
    new GrpcChannelOptions { HttpHandler = handler });
var client = new Greeter.GreeterClient(channel);