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
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:
OCI_REALM_SPECIFIC_SERVICE_ENDPOINT_TEMPLATE_ENABLED
en true
. 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:
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
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
// 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.
Para obtener más información sobre los principales de instancia, consulte Llamada a servicios desde una instancia.
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.