Conceptos

En este tema se explican algunos de los conceptos clave para utilizar el SDK para .NET de Oracle Cloud Infrastructure.

En este tema se explican algunos de los conceptos clave para utilizar el SDK para .NET de Oracle Cloud Infrastructure.

Solicitudes raw

Las solicitudes raw son útiles y, en algunos casos, son necesarias. Los casos de uso habituales incluyen el uso su propio cliente HTTP, realizando una solicitud con la autenticación de OCI en un punto final alternativo o realizando una solicitud a una API de OCI que no está soportada actualmente en el SDK. SDK para .NET expone la clase OciHttpClientHandler que puede utilizar para crear un manejador de cliente que firme la solicitud.

En este ejemplo de solicitud raw en GitHub se muestra cómo utilizar OciHttpClientHandler.

Definición de los puntos finales

Los puntos finales de servicio se pueden definir de varias maneras:

  • Llame a SetEndpoint(<YOUR_ENDPOINT>) en la instancia de cliente de servicio. Esto permitirá especificar un nombre de host completo (por ejemplo, https://www.example.com).
  • Llame a SetRegion(<YOUR_REGION_ID>) en la instancia de cliente de servicio. Así se selecciona el nombre de host adecuado para el servicio de la región especificada. Sin embargo, si el servicio no está soportado en la región definida, el SDK de .NET devuelve un error.
  • Llame a SetRegion(<Region>) en la instancia de cliente de servicio. Por ejemplo, SetRegion(Region.US_PHOENIX_1).
  • Transfiera la región en el archivo de configuración. Para obtener más información, consulte Archivo de configuración de SDK y CLI.

Se puede encontrar un ejemplo de la configuración del punto final en GitHub.

Tenga en cuenta que una instancia de servicio no se puede utilizar para comunicarse con diferentes regiones. Si necesita realizar solicitudes en distintas regiones, cree varias instancias de servicio.

Puntos finales dedicados

Los puntos finales dedicados son las plantillas de punto final definidas por el servicio para un dominio específico en el nivel de cliente. El SDK de .NET de OCI permite activar el uso de esta función de plantillas de punto final específicas del dominio tanto en el nivel de aplicación como en el nivel de cliente. Esta función está desactivada por defecto.
Nota

El valor definido en el nivel de cliente tiene prioridad sobre el valor definido en el nivel de aplicación.

Activación de plantillas de punto final específicas de dominio en el nivel de aplicación:

Para activar la función de plantillas de punto final específicas del dominio en el nivel de aplicación, defina la variable de entorno OCI_REALM_SPECIFIC_SERVICE_ENDPOINT_TEMPLATE_ENABLED en true.
Nota

El valor booleano no distingue entre mayúsculas y minúsculas.

Activación de plantillas de punto final específicas del dominio en el nivel de cliente:

Para activar la función de plantillas de punto final específicas del dominio en el nivel de cliente, defina el indicador en el código como se muestra a continuación:
var osClient = new ObjectStorageClient(provider, new ClientConfiguration());
osClient.UseRealmSpecificEndpointTemplate(true);

Para ver un ejemplo completo, consulte UseRealmSpecificEndpointsExample on GitHub.

Nuevo soporte de región

Si está utilizando una versión del SDK lanzado antes del anuncio de una nueva región, puede utilizar una solución alternativa para acceder a ella.

Una región es un área geográfica localizada. Para obtener más información sobre las regiones y cómo identificarlas, consulte Regiones y dominios de disponibilidad.

Un dominio es un conjunto de regiones que comparten entidades. Puede identificar el dominio consultando el nombre del dominio al final de la dirección de red. Por ejemplo, el dominio para xyz.abc.123.oraclecloud.com es oraclecloud.com.

Primero debe llamar a Region.Register() para registrar la nueva región y, a continuación, puede definir la región utilizando el archivo de configuración o llamando al método SetRegion .

Se puede encontrar un ejemplo de adición de una nueva región en GitHub.

Dominio de oraclecloud.com

Para las regiones del dominio oraclecloud.com, puede transferir nuevos nombres de región de la misma forma que pasaría los ya definidos en la enumeración de regiones para su versión de SDK.

Para definir la región:

using Oci.IdentityService;
 
var identityClient = new IdentityClient(<IAuthenticationDetailsProvider>);
identityClient.SetRegion("US_NEWYORK_1");

Otros dominios

Para las regiones de dominios que no sean oraclecloud.com, puede utilizar las siguientes soluciones alternativas para acceder a nuevas regiones con versiones anteriores del SDK.

Para definir la región:

using Oci.IdentityService;
 
var identityClient = new IdentityClient(<IAuthenticationDetailsProvider>);
identityClient.SetEndpoint("https://<your_endpoint>.com");

Carga de objetos grandes

El servicio Object Storage soporta cargas de varias partes para facilitar las cargas de objetos grandes mediante la división del objeto grande en partes. El SDK para .NET soporta operaciones de carga de varias partes raw para casos de uso avanzados, así como una clase de carga de nivel superior que utiliza las API de carga de varias partes. La gestión de cargas de varias partes proporciona enlaces a las API utilizadas para operaciones en varias partes. Las cargas de varias partes de nivel superior se implantan con UploadManager, que: dividirá un objeto grande en partes, cargará las partes en paralelo y, a continuación, volverá a combinar y confirmar las partes como un único objeto en el almacenamiento.

El ejemplo UploadObject muestra cómo utilizar UploadManager para dividir automáticamente un objeto en partes y cargarlo para simplificar la interacción con el servicio Object Storage.

Reintentos

Puede configurar el SDK para .NET para reintentar operaciones del SDK que fallan. El SDK permite especificar la estrategia que se desea utilizar para el manejo de los reintentos, incluido el número de veces que se debe realizar un reintento, la condición en la que el SDK debe reintentar una operación y cuándo dejar de reintentar una operación. Puede definir estos parámetros en el nivel de cliente y en el nivel de solicitud individual.

Estrategia de retraso

Puede definir su propia estrategia de retraso con la propiedad GetNextDelayInSeconds. El SDK para . NET proporciona dos estrategias de retraso diferentes:

  • GetFixedDelayInSeconds (seconds): todos los reintentos se retrasan en un número especificado de segundos.
  • GetExponentialDelayInSeconds: el tiempo de retraso para las llamadas de reintento posteriores aumenta en un factor exponencial de 2.

Estrategia de terminación

Puede definir una estrategia de terminación con dos propiedades:

  • TotalElapsedTimeInSecs (seconds): define la duración total en segundos durante la cual se realizan los reintentos.
  • MaxAttempts (attempts): define el número total de reintentos.

Familias de códigos de estado reintentables

Puede especificar una lista de códigos de estado para reintentar mediante la propiedad RetryableStatusCodeFamilies. Por ejemplo:
 // Retryable status code family - this will make the SDK retry for all 5xx status codes:
 RetryableStatusCodeFamilies = new List<int>(new int[] { 5 }),

Errores reintentables

Esta propiedad es una recopilación de tuplas de números enteros y cadenas que contienen códigos de estado y de error devueltos por un error de servicio para el que el SDK puede realizar reintentos. Por ejemplo:
// Retry on the following HTTP status and error codes:
RetryableErrors = new Collection<Tuple<int, string>>(new Tuple<int, string>[] {
   new Tuple<int, string>(409, "IncorrectState"),
   new Tuple<int, string>(429, "TooManyRequests")

Ejemplos de reintentos

.NET

En este ejemplo se muestra cómo configurar y utilizar reintentos con el SDK para . NET:

/*
 * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
 * This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license.
 */
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
 
using Oci.Common;
using Oci.Common.Auth;
using Oci.Common.Retry;
using Oci.Common.Waiters;
using Oci.IdentityService;
using Oci.IdentityService.Models;
using Oci.IdentityService.Requests;
using Oci.IdentityService.Responses;
 
namespace Oci.Examples
{
    public class RetryExample
    {
        private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
        const string OciConfigProfileName = "DEFAULT";
        public static async Task MainRetry()
        {
            string compartmentId = Environment.GetEnvironmentVariable("OCI_COMPARTMENT_ID");
 
            // Configuring the AuthenticationDetailsProvider. It's assumed there is a default OCI config file
            // "~/.oci/config", and a profile in that config with the name OciConfigProfileName . Make changes to the following
            // line if needed and use ConfigFileAuthenticationDetailsProvider(configurationFilePath, profile);
            var provider = new ConfigFileAuthenticationDetailsProvider(OciConfigProfileName);
            // Create a client for the service to enable using its APIs
            var client = new IdentityClient(provider, new ClientConfiguration());
            try
            {
                await ListOciRegions(client);
                await ListOciRegionSubscriptions(client, compartmentId);
            }
            catch (Exception e)
            {
                logger.Info($"Received exception due to {e.Message}");
            }
            finally
            {
                client.Dispose();
            }
        }
 
        private static async Task ListOciRegions(IdentityClient client)
        {
            // Create a retry configuration to override defaults
            RetryConfiguration retryConfiguration = new RetryConfiguration
            {
                // Enable exponential backoff
                GetNextDelayInSeconds = DelayStrategy.GetExponentialDelayInSeconds,
                //  Defines total duration in seconds for which the retry attempts.
                TotalElapsedTimeInSecs = 600,
                // Defines the total number of retry attempts.
                MaxAttempts = 4,
                // Retryable status code family - this will make the SDK retry for all 5xx status codes
                RetryableStatusCodeFamilies = new List<int>(new int[] { 5 }),
                // Retry on the following HTTP status and error codes
                RetryableErrors = new Collection<Tuple<int, string>>(new Tuple<int, string>[] {
                    new Tuple<int, string>(409, "IncorrectState"),
                    new Tuple<int, string>(429, "TooManyRequests")
                })
            };
            // List regions
            var listRegionsRequest = new ListRegionsRequest();
            ListRegionsResponse listRegionsResponse = await client.ListRegions(listRegionsRequest, retryConfiguration);
            logger.Info("List Regions");
            logger.Info("=============");
            foreach (Oci.IdentityService.Models.Region reg in listRegionsResponse.Items)
            {
                logger.Info($"{reg.Key} : {reg.Name}");
            }
        }
        private static async Task ListOciRegionSubscriptions(IdentityClient client, string compartmentId)
        {
            // List RegionSubscriptions
            ListRegionSubscriptionsRequest listRegionSubscriptionsRequest = new ListRegionSubscriptionsRequest
            {
                TenancyId = compartmentId
            };
            RetryConfiguration retryConfiguration = new RetryConfiguration
            {
                // Enable exponential backoff with Full Jitter.
                GetNextDelayInSeconds = GetJitterDelayInSeconds
            };
            ListRegionSubscriptionsResponse listRegionSubscriptionsResponse = await client.ListRegionSubscriptions(listRegionSubscriptionsRequest, retryConfiguration);
            List<RegionSubscription> regionSubscriptions = listRegionSubscriptionsResponse.Items;
            logger.Info("List RegionSubscriptions");
            logger.Info("=========================");
            foreach (RegionSubscription regionSubscription in regionSubscriptions)
            {
                logger.Info($"{regionSubscription.RegionName} : {regionSubscription.RegionKey}");
            }
        }
 
        /// <summary>
        /// Defining a custom retry strategy that mimics an exponential backoff with full jitter to reduce
        /// contention between competing calls
        /// </summary>
        private static double GetJitterDelayInSeconds(int retryAttempt)
        {
            Random random = new Random();
            return random.NextDouble() * Math.Pow(2, retryAttempt);
        }
    }
}

Respuestas paginadas

Para juegos de resultados grandes, la mayoría de OCI llama a respuestas paginadas soportadas. Las respuestas paginadas requieren que realice varias llamadas a la operación de lista, transfiriendo el valor del siguiente token de respuesta más reciente. El módulo de paginación le permite:

  • Cargar todos los resultados posibles de una llamada de lista en una llamada.
  • Cargar resultados de forma lenta mediante respuestas paginadas basadas en tokens.

Para obtener un ejemplo sobre cómo utilizar estas funciones, consulte GitHub.

Sondeo con procesos en espera

El SDK ofrece procesos en espera que permiten que el código espere hasta la llegada de un recurso específico al estado deseado. Se puede llamar a un proceso en espera en modo de bloqueo o no bloqueo (con devolución de llamada asíncrona) y este esperará hasta que se alcance el estado deseado o se exceda el tiempo de espera. Los procesos en espera sintetizan la lógica de sondeo que, de lo contrario, tendría que escribir en una llamada de método único fácil de utilizar.

Los procesos en espera se obtienen mediante el cliente de servicio (client.Waiters). Tanto Get<Resource>Request como el estado de ciclo de vida deseado se transfieren al método Waiters.For<Resource>.

Por ejemplo:

using Oci.CoreService;
 
public static Instance WaitForInstanceProvisioningToComplete(ComputeClient computeClient, String instanceId)
{
    GetInstanceRequest getInstanceRequest = new GetInstanceRequest { InstanceId = instanceId };
    GetInstanceResponse getInstanceResponse = computeClient.Waiters.ForInstance(getInstanceRequest, Instance.LifecycleStateEnum.Running).Execute();
    return getInstanceResponse.Instance;
}

Cada método waiters.for<Resource> tiene dos versiones:

Una versión utiliza los valores de sondeo por defecto. Por ejemplo:

Waiters.ForInstance(getInstanceRequest, Instance.LifecycleStateEnum.Running)

La otra versión proporciona el control total sobre el tiempo de espera y el tiempo entre intentos de sondeo. Por ejemplo:

using Oci.Common.Waiters;
 
WaiterConfiguration waiterConfiguration = new WaiterConfiguration
{
     MaxAttempts = 5,
     GetNextDelayInSeconds = DelayStrategy.GetExponentialDelayInSeconds
};
Waiters.ForInstance(getInstanceRequest, waiterConfiguration, Instance.LifecycleStateEnum.Running)

Algunas solicitudes de API devuelven identificadores de solicitud de trabajo para realizar un seguimiento del progreso de la solicitud. Los procesos en espera se pueden utilizar para esperar hasta que la solicitud de trabajo haya alcanzado el estado deseado.

Por ejemplo:


using Oci.Common.Waiters;
using Oci.ContainerengineService;
using Oci.ContainerengineService.Responses;
using Oci.ContainerengineService.Requests;
 
CreateClusterResponse clusterResponse = await containerEngineClient.CreateCluster(createClusterRequest);
GetWorkRequestResponse workRequestResponse = WaitForWorkRequestFinished(containerEngineClient, workRequestId);
private static GetWorkRequestResponse WaitForWorkRequestFinished(ContainerEngineClient containerEngineClient, string workRequestId)
{
   var waiterConfiguration = new WaiterConfiguration
   {
       MaxAttempts = 5,
       GetNextDelayInSeconds = DelayStrategy.GetExponentialDelayInSeconds
   };
   GetWorkRequestRequest getWorkRequestRequest = new GetWorkRequestRequest
   {
      WorkRequestId = workRequestId
   };
   return containerEngineClient.Waiters.ForWorkRequest(getWorkRequestRequest, waiterConfiguration, WorkRequestStatus.Succeeded).Execute();
}

Se pueden encontrar otros ejemplos sobre los procesos en espera en Github.

Manejo de excepciones

Al manejar una excepción, puede obtener más información sobre la solicitud HTTP que la ha causado, como el código de estado o el código de servicio. También puede obtener el identificador de la solicitud al manejar una excepción observando la propiedad opcRequestId del objeto de error.

Por ejemplo:


try {
  var response = await identityClient.ListAllUsersResponses(listUserReq);
} catch (OciException e) {
  logger.Info($"requestId: {e.OpcRequestId}");
  logger.Info($"StatusCode: {e.StatusCode}");
  logger.Info($"ServiceCode: {e.ServiceCode}"); 
 }

Autenticación con principales de instancia

Principales de instancia es una función del servicio de IAM que permite que las instancias sean actores autorizados (o principales) que puedan realizar acciones en los recursos de servicio. Cada instancia informática tiene su propia identidad y se autentica con los certificados que se le agregan. Estos certificados se crean, se asignan a instancias y se rotan automáticamente, de modo que usted no necesita distribuir credenciales a sus hosts y rotarlos.

Nota

Para obtener más información sobre los principales de instancia, consulte Llamada a servicios desde una instancia.
Al utilizar el SDK para .NET en una instancia de OCI, puede utilizar la clase InstancePrincipalsAuthenticationDetailsProvider como se muestra en el siguiente ejemplo. No tendrá que proporcionar los detalles de autenticación cuando utilice esta clase.
using Oci.Common.Auth;
using Oci.IdentityService;
 
// Creates an Instance Principal provider that holds authentication details of the OCI Instance
var instanceProvider = new InstancePrincipalsAuthenticationDetailsProvider();
 
// Create a client for the service to enable using its APIs
var client = new IdentityClient(instanceProvider);

En GitHub se puede encontrar un ejemplo de trabajo completo de uso de principales de instancia con el SDK para .NET de OCI.