Control de errores con gRPC
Nota:
Esta no es la versión más reciente de este artículo. Para la versión actual, consulte la versión .NET 8 de este artículo.
Advertencia
Esta versión de ASP.NET Core ya no se admite. Para obtener más información, consulte la Directiva de soporte técnico de .NET y .NET Core. Para la versión actual, consulte la versión .NET 8 de este artículo.
Importante
Esta información hace referencia a un producto en versión preliminar, el cual puede sufrir importantes modificaciones antes de que se publique la versión comercial. Microsoft no proporciona ninguna garantía, expresa o implícita, con respecto a la información proporcionada aquí.
Para la versión actual, consulte la versión .NET 8 de este artículo.
En este artículo se describe el control de errores y gRPC:
- Funcionalidades integradas de control de errores mediante códigos de estado gRPC y mensajes de error.
- Envío de información de error compleja y estructurada mediante control de errores enriquecido.
Control de errores integrado
Las llamadas gRPC comunican el éxito o el error con un código de estado. Cuando una llamada gRPC se completa correctamente, el servidor devuelve un estado OK
al cliente. Si se produce un error, gRPC devuelve:
- Un código de estado de error, como
CANCELLED
oUNAVAILABLE
. - Un mensaje de error de cadena opcional.
Los tipos que se usan habitualmente con el control de errores son:
StatusCode
: una enumeración de códigos de estado gRPC.OK
indica que se ha realizado correctamente; los demás valores indican un error.Status
: unstruct
que combina unStatusCode
y un mensaje de error de cadena opcional. El mensaje de error proporciona más detalles sobre lo que ha ocurrido.RpcException
: un tipo de excepción que tiene un valorStatus
. Esta excepción se produce en los métodos del servidor gRPC y es capturada por los clientes gRPC.
El control de errores integrado solo admite un código de estado y una descripción de cadena. Para enviar información de error compleja del servidor al cliente, use un control de errores enriquecido.
Provocar errores en el servidor
Una llamada al servidor gRPC siempre devuelve un estado. El servidor devuelve OK
automáticamente cuando un método se completa correctamente.
public class GreeterService : GreeterBase
{
public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
{
return Task.FromResult(new HelloReply { Message = $"Hello {request.Name}" });
}
public override async Task SayHelloStreaming(HelloRequest request,
IServerStreamWriter<HelloReply> responseStream, ServerCallContext context)
{
for (var i = 0; i < 5; i++)
{
await responseStream.WriteAsync(new HelloReply { Message = $"Hello {request.Name} {i}" });
await Task.Delay(TimeSpan.FromSeconds(1));
}
}
}
El código anterior:
- Implementa el método unario
SayHello
que se completa correctamente cuando devuelve un mensaje de respuesta. - Implementa el método de streaming
SayHelloStreaming
del servidor que se completa correctamente cuando finaliza el método.
Estado del error del servidor
Los métodos gRPC devuelven un código de estado de error iniciando una excepción. Cuando se produce RpcException
en el servidor, el código de estado y la descripción se devuelven al cliente:
public class GreeterService : GreeterBase
{
public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
{
if (string.IsNullOrEmpty(request.Name))
{
throw new RpcException(new Status(StatusCode.InvalidArgument, "Name is required."));
}
return Task.FromResult(new HelloReply { Message = $"Hello {request.Name}" });
}
}
Los tipos de excepción que se producen y que no son de RpcException
también hacen que la llamada falle, pero con un código de estado UNKNOWN
y un mensaje genérico Exception was thrown by handler
.
Exception was thrown by handler
se envía al cliente en lugar del mensaje de excepción para evitar exponer información potencialmente confidencial. Para ver un mensaje de error más descriptivo en un entorno de desarrollo, configure EnableDetailedErrors
.
Control de errores de cliente
Cuando un cliente gRPC realiza una llamada, el código de estado se valida automáticamente al acceder a la respuesta. Por ejemplo, esperar una llamada gRPC unaria devuelve el mensaje enviado por el servidor si la llamada tiene éxito, y devuelve RpcException
si hay un fallo. Detectar RpcException
para controlar errores en un cliente:
var client = new Greet.GreeterClient(channel);
try
{
var response = await client.SayHelloAsync(new HelloRequest { Name = "World" });
Console.WriteLine("Greeting: " + response.Message);
}
catch (RpcException ex)
{
Console.WriteLine("Status code: " + ex.Status.StatusCode);
Console.WriteLine("Message: " + ex.Status.Detail);
}
El código anterior:
- Realiza una llamada unaria gRPC al método
SayHello
. - Escribe el mensaje de respuesta en la consola si se realiza correctamente.
- Detecta
RpcException
y escribe los detalles del error en caso de error.
Escenarios de error
Los errores se representan mediante RpcException
con un código de estado de error y un mensaje de detalle opcional. RpcException
se produce en muchos escenarios:
- Error de llamada en el servidor y el servidor envió un código de estado de error. Por ejemplo, el cliente gRPC inició una llamada a la que le faltaban datos necesarios del mensaje de solicitud y el servidor devuelve un código de estado de
INVALID_ARGUMENT
. - Se produjo un error dentro del cliente al realizar la llamada a gRPC. Por ejemplo, un cliente realiza una llamada a gRPC, no se puede conectar al servidor y produce un error con un estado de
UNAVAILABLE
. - El CancellationToken pasado a la llamada gRPC se cancela. La llamada gRPC se detiene y el cliente produce un error con un estado de
CANCELLED
. - Una llamada a gRPC supera la fecha límite configurada. La llamada gRPC se detiene y el cliente produce un error con un estado de
DEADLINE_EXCEEDED
.
Control de errores enriquecido
El control de errores enriquecido permite enviar información compleja y estructurada con mensajes de error. Por ejemplo, la validación de campos de mensaje entrantes que devuelve una lista de nombres y descripciones de campos no válidos. El modelo de error google.rpc.Status
se usa a menudo para enviar información compleja sobre errores entre aplicaciones gRPC.
gRPC en .NET es compatible con un modelo de error enriquecido usando el paquete Grpc.StatusProto
. Este paquete tiene métodos para crear modelos de error enriquecidos en el servidor y para que un cliente pueda leerlos. El modelo de error enriquecido se basa en las funcionalidades de control integradas de gRPC y se pueden usar en paralelo.
Importante
Los errores se incluyen en encabezados y los encabezados totales de las respuestas suelen limitarse a 8 KB (8 192 bytes). Asegúrese de que los encabezados que contienen errores no superan los 8 KB.
Creación de errores enriquecidos en el servidor
Los errores enriquecidos se crean a partir de Google.Rpc.Status
. Este tipo es diferente de Grpc.Core.Status
.
Google.Rpc.Status
tiene campos de estado, mensaje y detalles. El campo más importante es el de detalles, que es un campo repetido de Any
valores. Los detalles son donde se agregan cargas complejas.
Aunque cualquier tipo de mensaje se puede usar como carga útil, se recomienda usar una de las cargas de error estándar:
BadRequest
PreconditionFailure
ErrorInfo
ResourceInfo
QuotaFailure
Grpc.StatusProto
incluye el método auxiliar ToRpcException
para convertir Google.Rpc.Status
en un error. Inicie el error del método de servidor gRPC:
public class GreeterService : Greeter.GreeterBase
{
public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
{
ArgumentNotNullOrEmpty(request.Name);
return Task.FromResult(new HelloReply { Message = "Hello " + request.Name });
}
public static void ArgumentNotNullOrEmpty(string value, [CallerArgumentExpression(nameof(value))] string? paramName = null)
{
if (string.IsNullOrEmpty(value))
{
var status = new Google.Rpc.Status
{
Code = (int)Code.InvalidArgument,
Message = "Bad request",
Details =
{
Any.Pack(new BadRequest
{
FieldViolations =
{
new BadRequest.Types.FieldViolation { Field = paramName, Description = "Value is null or empty" }
}
})
}
};
throw status.ToRpcException();
}
}
}
Lectura de errores enriquecidos por un cliente
Los errores ricos se leen del RpcException
capturado en el cliente. Capture la excepción y use los métodos auxiliares proporcionados por Grpc.StatusCode
para obtener su instancia de Google.Rpc.Status
:
var client = new Greet.GreeterClient(channel);
try
{
var reply = await client.SayHelloAsync(new HelloRequest { Name = name });
Console.WriteLine("Greeting: " + reply.Message);
}
catch (RpcException ex)
{
Console.WriteLine($"Server error: {ex.Status.Detail}");
var badRequest = ex.GetRpcStatus()?.GetDetail<BadRequest>();
if (badRequest != null)
{
foreach (var fieldViolation in badRequest.FieldViolations)
{
Console.WriteLine($"Field: {fieldViolation.Field}");
Console.WriteLine($"Description: {fieldViolation.Description}");
}
}
}
El código anterior:
- Realiza una llamada gRPC dentro de un try/catch que detecta
RpcException
. - Llama a
GetRpcStatus()
a para intentar obtener el modelo de error enriquecido de la excepción. - Llama a
GetDetail<BadRequest>()
para intentar obtener una carga útil deBadRequest
del error enriquecido.