

La AWS SDK para .NET V3 ha entrado en modo de mantenimiento.

Le recomendamos que migre a la [AWS SDK para .NET V4](https://docs.aws.amazon.com/sdk-for-net/v4/developer-guide/welcome.html). Para obtener información y detalles adicionales sobre cómo migrar, consulta nuestro [anuncio sobre el modo de mantenimiento](https://aws.amazon.com/blogs/developer/aws-sdk-for-net-v3-maintenance-mode-announcement/).

Las traducciones son generadas a través de traducción automática. En caso de conflicto entre la traducción y la version original de inglés, prevalecerá la version en inglés.

# Trabaje con AWS los servicios del AWS SDK para .NET
<a name="working-with-aws-services"></a>

Las siguientes secciones contienen ejemplos, tutoriales, tareas y guías que muestran cómo utilizarlos AWS SDK para .NET para trabajar con AWS los servicios. Estos ejemplos y tutoriales se basan en una API que el AWS SDK para .NET proporciona. Para ver qué clases y métodos están disponibles en la API, consulte la [Referencia de API de AWS SDK para .NET](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/).

Si es la primera vez que lo conoces AWS SDK para .NET, quizás quieras consultar primero el [Recorrido rápido](quick-start.md) tema. que sirve de introducción a SDK.

Puedes encontrar más ejemplos de código en el repositorio de [ejemplos de AWS código y en el repositorio](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/dotnetv3) [awslabs](https://github.com/awslabs/aws-sdk-net-samples) de. GitHub

Antes de comenzar, asegúrese de que ha [configurado el entorno y el proyecto](net-dg-config.md). Revise también la información disponible en [Características de SDK](net-dg-sdk-features.md).

**Topics**
+ [Ejemplos de código con orientaciones](tutorials-examples.md)
+ [AWS Lambda](aws-lambda.md)
+ [Bibliotecas y marcos de trabajo de alto nivel](high-level-libraries.md)
+ [Otros servicios y configuraciones](other-apis-intro.md)

# Ejemplos de código con orientación para AWS SDK para .NET
<a name="tutorials-examples"></a>

Las siguientes secciones contienen ejemplos de código y proporcionan orientación sobre esos ejemplos. Pueden ayudarlo a aprender a usarlo AWS SDK para .NET para trabajar con AWS los servicios.

Si eres nuevo en el tema AWS SDK para .NET, quizás quieras consultar primero el [Recorrido rápido](quick-start.md) tema. que sirve de introducción a SDK.

Antes de comenzar, asegúrese de que ha [configurado el entorno y el proyecto](net-dg-config.md). Revise también la información disponible en [Características de SDK](net-dg-sdk-features.md).

**Topics**
+ [CloudFormation](cloudformation-apis-intro.md)
+ [Amazon Cognito](cognito-apis-intro.md)
+ [DynamoDB](dynamodb-intro.md)
+ [Amazon EC2](ec2-apis-intro.md)
+ [IAM](iam-apis-intro.md)
+ [Amazon S3](s3-apis-intro.md)
+ [Amazon SNS](sns-apis-intro.md)
+ [Amazon SQS](sqs-apis-intro.md)

# Acceder CloudFormation con el AWS SDK para .NET
<a name="cloudformation-apis-intro"></a>

El AWS SDK para .NET soporte [AWS CloudFormation](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/), que crea y aprovisiona los despliegues de AWS infraestructura de forma predecible y repetida.

## APIs
<a name="w2aac19c15c11b5"></a>

Los servicios APIs para AWS SDK para .NET los clientes. CloudFormation Le APIs permiten trabajar con CloudFormation funciones como plantillas y pilas. Esta sección contiene una pequeña cantidad de ejemplos que le muestran los patrones que puede seguir al trabajar con ellos APIs. Para ver el conjunto completo de APIs, consulta la [referencia de la AWS SDK para .NET API](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/) (y desplázate hasta «Amazon. CloudFormation«).

 AWS CloudFormation APIs Son proporcionados por [AWSSDK. CloudFormation](https://www.nuget.org/packages/AWSSDK.CloudFormation/)paquete.

## Requisitos previos
<a name="w2aac19c15c11b7"></a>

Antes de comenzar, asegúrese de que ha [configurado el entorno y el proyecto](net-dg-config.md). Revise también la información en [Características de SDK](net-dg-sdk-features.md).

## Temas
<a name="w2aac19c15c11b9"></a>

**Topics**
+ [

## APIs
](#w2aac19c15c11b5)
+ [

## Requisitos previos
](#w2aac19c15c11b7)
+ [

## Temas
](#w2aac19c15c11b9)
+ [Listar AWS recursos](cfn-list-resources.md)

# Listar AWS los recursos utilizando AWS CloudFormation
<a name="cfn-list-resources"></a>

En este ejemplo, se muestra cómo utilizarlos AWS SDK para .NET para enumerar los recursos en CloudFormation pilas. En el ejemplo se utiliza la API de bajo nivel. La aplicación no toma argumentos, sino que simplemente recopila información de todas las pilas a las que se puede acceder con las credenciales del usuario y muestra información sobre esas pilas.

## Referencias de SDK
<a name="w2aac19c15c11c13b5b1"></a>

NuGet paquetes:
+ [AWSSDK.CloudFormation](https://www.nuget.org/packages/AWSSDK.CloudFormation/)

Elementos de programación:
+ [Espacio de nombres Amazon. CloudFormation](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/CloudFormation/NCloudFormation.html)

  Clase [AmazonCloudFormationClient](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/CloudFormation/TCloudFormationClient.html)
+ [Espacio de nombres Amazon. CloudFormation](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/CloudFormation/NCloudFormationModel.html).Modelo

  [Clase. ICloud FormationPaginatorFactory DescribeStacks](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/CloudFormation/MICloudFormationPaginatorFactoryDescribeStacksDescribeStacksRequest.html)

  Clase [DescribeStackResourcesRequest](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/CloudFormation/TDescribeStackResourcesRequest.html)

  Clase [DescribeStackResourcesResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/CloudFormation/TDescribeStackResourcesResponse.html)

  Clase [Stack](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/CloudFormation/TStack.html)

  Clase [StackResource](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/CloudFormation/TStackResource.html)

  Clase [Tag](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/CloudFormation/TTag.html)

```
using Amazon.CloudFormation;
using Amazon.CloudFormation.Model;
using Amazon.Runtime;

namespace CloudFormationActions;

public static class HelloCloudFormation
{
    public static IAmazonCloudFormation _amazonCloudFormation;

    static async Task Main(string[] args)
    {
        // Create the CloudFormation client
        _amazonCloudFormation = new AmazonCloudFormationClient();
        Console.WriteLine($"\nIn Region: {_amazonCloudFormation.Config.RegionEndpoint}");

        // List the resources for each stack
        await ListResources();
    }

    /// <summary>
    /// Method to list stack resources and other information.
    /// </summary>
    /// <returns>True if successful.</returns>
    public static async Task<bool> ListResources()
    {
        try
        {
            Console.WriteLine("Getting CloudFormation stack information...");

            // Get all stacks using the stack paginator.
            var paginatorForDescribeStacks =
                _amazonCloudFormation.Paginators.DescribeStacks(
                    new DescribeStacksRequest());
            await foreach (Stack stack in paginatorForDescribeStacks.Stacks)
            {
                // Basic information for each stack
                Console.WriteLine("\n------------------------------------------------");
                Console.WriteLine($"\nStack: {stack.StackName}");
                Console.WriteLine($"  Status: {stack.StackStatus.Value}");
                Console.WriteLine($"  Created: {stack.CreationTime}");

                // The tags of each stack (etc.)
                if (stack.Tags.Count > 0)
                {
                    Console.WriteLine("  Tags:");
                    foreach (Tag tag in stack.Tags)
                        Console.WriteLine($"    {tag.Key}, {tag.Value}");
                }

                // The resources of each stack
                DescribeStackResourcesResponse responseDescribeResources =
                    await _amazonCloudFormation.DescribeStackResourcesAsync(
                        new DescribeStackResourcesRequest
                        {
                            StackName = stack.StackName
                        });
                if (responseDescribeResources.StackResources.Count > 0)
                {
                    Console.WriteLine("  Resources:");
                    foreach (StackResource resource in responseDescribeResources
                                 .StackResources)
                        Console.WriteLine(
                            $"    {resource.LogicalResourceId}: {resource.ResourceStatus}");
                }
            }

            Console.WriteLine("\n------------------------------------------------");
            return true;
        }
        catch (AmazonCloudFormationException ex)
        {
            Console.WriteLine("Unable to get stack information:\n" + ex.Message);
            return false;
        }
        catch (AmazonServiceException ex)
        {
            if (ex.Message.Contains("Unable to get IAM security credentials"))
            {
                Console.WriteLine(ex.Message);
                Console.WriteLine("If you are usnig SSO, be sure to install" +
                                  " the AWSSDK.SSO and AWSSDK.SSOOIDC packages.");
            }
            else
            {
                Console.WriteLine(ex.Message);
                Console.WriteLine(ex.StackTrace);
            }

            return false;
        }
        catch (ArgumentNullException ex)
        {
            if (ex.Message.Contains("Options property cannot be empty: ClientName"))
            {
                Console.WriteLine(ex.Message);
                Console.WriteLine("If you are using SSO, have you logged in?");
            }
            else
            {
                Console.WriteLine(ex.Message);
                Console.WriteLine(ex.StackTrace);
            }

            return false;
        }
    }
```

# Autenticación de usuarios con Amazon Cognito
<a name="cognito-apis-intro"></a>

**nota**  
La información de este tema es específica de los proyectos basados en .NET Framework y en la AWS SDK para .NET versión 3.3 y anteriores.

Con Amazon Cognito Identity, puede crear identidades únicas para sus usuarios y autenticarlos para un acceso seguro a sus AWS recursos, como Amazon S3 o Amazon DynamoDB. Amazon Cognito Identity es compatible con proveedores de identidades públicos como Amazon, Facebook, Twitter/Digits, Google o cualquier proveedor compatible con OpenID Connect, así como con identidades sin autenticar. Cognito también admite [identidades autenticadas por el desarrollador](https://aws.amazon.com/blogs/mobile/amazon-cognito-announcing-developer-authenticated-identities/), que le permiten registrar y autenticar usuarios mediante su propio proceso de autenticación backend, sin dejar de usar Amazon Cognito Sync para sincronizar los datos de los usuarios y obtener acceso a los recursos de AWS .

Para obtener más información sobre [Amazon Cognito](https://aws.amazon.com/cognito/), consulte la [Guía para desarrolladores de Amazon Cognito](https://docs.aws.amazon.com/cognito/latest/developerguide/).

En los siguientes ejemplos de código se muestra cómo utilizar Amazon Cognito Identity fácilmente. En el ejemplo del tema [Proveedor de credenciales](cognito-creds-provider.md) se muestra cómo crear y autenticar identidades de usuario. El [CognitoAuthentication biblioteca de extensiones](cognito-authentication-extension.md) ejemplo muestra cómo utilizar la biblioteca de CognitoAuthentication extensiones para autenticar grupos de usuarios de Amazon Cognito.

**Topics**
+ [Proveedor de credenciales](cognito-creds-provider.md)
+ [CognitoAuthentication biblioteca de extensiones](cognito-authentication-extension.md)

# Proveedor de credenciales de Amazon Cognito
<a name="cognito-creds-provider"></a>

**nota**  
La información de este tema es específica de los proyectos basados en .NET Framework y en la AWS SDK para .NET versión 3.3 y anteriores.

 `Amazon.CognitoIdentity.CognitoAWSCredentials`, que se encuentra en [AWSSDK. CognitoIdentity](https://www.nuget.org/packages/AWSSDK.CognitoIdentity/) NuGetpackage, es un objeto de credenciales que utiliza Amazon Cognito y AWS Security Token Service (AWS STS) para recuperar credenciales y realizar AWS llamadas.

El primer paso en la configuración de `CognitoAWSCredentials` es crear un “grupo de identidades”. Un grupo de identidades es un almacén de información de identidades de usuarios que es específico de una cuenta determinada. La información se puede recuperar en plataformas, dispositivos y sistemas operativos cliente, de modo que si un usuario comienza a usar la aplicación en un teléfono y más tarde pasa a una tablet, la información de la aplicación persistente seguirá estando disponible para ese usuario. Puede crear un nuevo grupo de identidades desde la consola de Amazon Cognito. Si usa la consola, esta también le proporcionará los demás datos que se requieren:
+ Su número de cuenta: un número de 12 dígitos, por ejemplo, 123456789012, exclusivo de su cuenta.
+ El ARN de la función sin autenticación: la función que asumirán los usuarios que no se hayan autenticado. Por ejemplo, esta función puede proporcionar permisos de solo lectura respecto a los datos.
+ El ARN de la función con autenticación: la función que asumirán los usuarios que se hayan autenticado. Esta función puede proporcionar permisos más extensos respecto a los datos.

## Configurar Cognito AWSCredentials
<a name="set-up-cognitoawscredentials"></a>

En el siguiente ejemplo de código se muestra cómo configurar `CognitoAWSCredentials`, que puede usar a continuación para realizar una llamada a Amazon S3 como usuario sin autenticar. Esto permite realizar llamadas exigiendo tan solo una cantidad mínima de datos para autenticar el usuario. Los permisos de los usuarios se controlan mediante la función, lo que le permite configurar el acceso de acuerdo con sus necesidades.

```
CognitoAWSCredentials credentials = new CognitoAWSCredentials(
    accountId,        // Account number
    identityPoolId,   // Identity pool ID
    unAuthRoleArn,    // Role for unauthenticated users
    null,             // Role for authenticated users, not set
    region);
using (var s3Client = new AmazonS3Client(credentials))
{
    s3Client.ListBuckets();
}
```

## AWS Utilícelo como usuario no autenticado
<a name="use-aws-as-an-unauthenticated-user"></a>

El siguiente ejemplo de código muestra cómo puedes empezar a usarlo AWS como usuario no autenticado, luego autenticarte a través de Facebook y actualizar las credenciales para usar las credenciales de Facebook. Con este enfoque, puede conceder capacidades diferentes a los usuarios autenticados a través de la función con que se autentiquen. Por ejemplo, podría tener una aplicación de teléfono que permita a los usuarios ver contenido de forma anónima, pero que les permita publicarlo si inician sesión a través de uno o varios de los proveedores configurados.

```
CognitoAWSCredentials credentials = new CognitoAWSCredentials(
    accountId, identityPoolId,
    unAuthRoleArn,    // Role for unauthenticated users
    authRoleArn,      // Role for authenticated users
    region);
using (var s3Client = new AmazonS3Client(credentials))
{
    // Initial use will be unauthenticated
    s3Client.ListBuckets();

    // Authenticate user through Facebook
    string facebookToken = GetFacebookAuthToken();

    // Add Facebook login to credentials. This clears the current AWS credentials
    // and retrieves new AWS credentials using the authenticated role.
    credentials.AddLogin("graph.facebook.com", facebookAccessToken);

    // This call is performed with the authenticated role and credentials
    s3Client.ListBuckets();
}
```

El objeto `CognitoAWSCredentials` proporciona más funcionalidad si cabe cuando se usa con el cliente `AmazonCognitoSyncClient` que forma parte de AWS SDK para .NET. Si usa tanto `AmazonCognitoSyncClient` como `CognitoAWSCredentials`, no es preciso especificar las propiedades `IdentityPoolId` e `IdentityId` al realizar llamadas con `AmazonCognitoSyncClient`. Estas propiedades se rellenan automáticamente desde `CognitoAWSCredentials`. Esto se ilustra en el siguiente ejemplo de código, además de un evento que le envía una notificación siempre que la propiedad `IdentityId` de `CognitoAWSCredentials` cambia. La propiedad `IdentityId` puede cambiar en algunos casos; por ejemplo, cuando un usuario sin autenticar pasa a estar autenticado.

```
CognitoAWSCredentials credentials = GetCognitoAWSCredentials();

// Log identity changes
credentials.IdentityChangedEvent += (sender, args) =>
{
    Console.WriteLine("Identity changed: [{0}] => [{1}]", args.OldIdentityId, args.NewIdentityId);
};

using (var syncClient = new AmazonCognitoSyncClient(credentials))
{
    var result = syncClient.ListRecords(new ListRecordsRequest
    {
        DatasetName = datasetName
        // No need to specify these properties
        //IdentityId = "...",
        //IdentityPoolId = "..."        
    });
}
```

# Ejemplos de bibliotecas CognitoAuthentication de extensiones de Amazon
<a name="cognito-authentication-extension"></a>

**nota**  
La información de este tema es específica de los proyectos basados en .NET Framework y en la AWS SDK para .NET versión 3.3 y anteriores.

La biblioteca CognitoAuthentication de extensiones, que se encuentra en [Amazon.Extensions. CognitoAuthentication](https://www.nuget.org/packages/Amazon.Extensions.CognitoAuthentication/) NuGet paquete, simplifica el proceso de autenticación de los grupos de usuarios de Amazon Cognito para los desarrolladores de .NET Core y Xamarin. La biblioteca se basa en la API de proveedor de identidades de Amazon Cognito para crear y enviar llamadas de API de autenticación de usuarios.

## Uso de la biblioteca de extensiones CognitoAuthentication
<a name="using-the-cognitoauthentication-extension-library"></a>

Amazon Cognito tiene algunos valores de `AuthFlow` y `ChallengeName` integrados de flujo de autenticación estándar que validan el nombre de usuario y la contraseña mediante el protocolo Secure Remote Password (SRP). Para obtener más información acerca del flujo de autenticación, consulte [Flujo de autenticación de los grupos de usuarios](https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-authentication-flow.html) de Amazon Cognito.

En los siguientes ejemplos se requieren estas instrucciones `using`:

```
// Required for all examples
using System;
using Amazon;
using Amazon.CognitoIdentity;
using Amazon.CognitoIdentityProvider;
using Amazon.Extensions.CognitoAuthentication;
using Amazon.Runtime;
// Required for the GetS3BucketsAsync example
using Amazon.S3;
using Amazon.S3.Model;
```

### Uso de la autenticación básica
<a name="use-basic-authentication"></a>

Cree una [AmazonCognitoIdentityProviderClient](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/CognitoIdentityProvider/TCognitoIdentityProviderClient.html)con [Anonymous AWSCredentials](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/Runtime/TAnonymousAWSCredentials.html), que no requiere solicitudes firmadas. No es preciso proporcionar una región; el código subyacente llama a `FallbackRegionFactory.GetRegionEndpoint()` si no se proporciona una región. Cree objetos `CognitoUserPool` y `CognitoUser`. Llame al método `StartWithSrpAuthAsync` mediante una solicitud `InitiateSrpAuthRequest` que contenga la contraseña del usuario.

```
public static async void GetCredsAsync()
{
    AmazonCognitoIdentityProviderClient provider =
        new AmazonCognitoIdentityProviderClient(new Amazon.Runtime.AnonymousAWSCredentials());
    CognitoUserPool userPool = new CognitoUserPool("poolID", "clientID", provider);
    CognitoUser user = new CognitoUser("username", "clientID", userPool, provider);
    InitiateSrpAuthRequest authRequest = new InitiateSrpAuthRequest()
    {
        Password = "userPassword"
    };

    AuthFlowResponse authResponse = await user.StartWithSrpAuthAsync(authRequest).ConfigureAwait(false);
    accessToken = authResponse.AuthenticationResult.AccessToken;

}
```

### Autenticación con desafíos
<a name="authenticate-with-challenges"></a>

Continuar con el flujo de autenticación con desafíos, como la Autenticación Multi-Factor (MFA), también es más sencillo. NewPasswordRequired Los únicos requisitos son los CognitoAuthentication objetos, la contraseña del usuario para el SRP y la información necesaria para el siguiente desafío, que se obtiene tras solicitar al usuario que la introduzca. El siguiente código muestra una forma de comprobar el tipo de desafío y obtener las respuestas adecuadas para el MFA y NewPasswordRequired los desafíos durante el flujo de autenticación.

Realice una solicitud de autenticación básica como antes y ejecute `await` para esperar a la respuesta `AuthFlowResponse`. Cuando haya recibido la respuesta, ejecute un bucle para el objeto `AuthenticationResult` devuelto. Si el tipo de `ChallengeName` es `NEW_PASSWORD_REQUIRED`, llame al método `RespondToNewPasswordRequiredAsync`.

```
public static async void GetCredsChallengesAsync()
{
    AmazonCognitoIdentityProviderClient provider = 
        new AmazonCognitoIdentityProviderClient(new Amazon.Runtime.AnonymousAWSCredentials());
    CognitoUserPool userPool = new CognitoUserPool("poolID", "clientID", provider);
    CognitoUser user = new CognitoUser("username", "clientID", userPool, provider);
    InitiateSrpAuthRequest authRequest = new InitiateSrpAuthRequest(){
        Password = "userPassword"
    };

    AuthFlowResponse authResponse = await user.StartWithSrpAuthAsync(authRequest).ConfigureAwait(false);

    while (authResponse.AuthenticationResult == null)
    {
        if (authResponse.ChallengeName == ChallengeNameType.NEW_PASSWORD_REQUIRED)
        {
            Console.WriteLine("Enter your desired new password:");
            string newPassword = Console.ReadLine();

            authResponse = await user.RespondToNewPasswordRequiredAsync(new RespondToNewPasswordRequiredRequest()
            {
                SessionID = authResponse.SessionID,
                NewPassword = newPassword
            });
            accessToken = authResponse.AuthenticationResult.AccessToken;
        }
        else if (authResponse.ChallengeName == ChallengeNameType.SMS_MFA)
        {
            Console.WriteLine("Enter the MFA Code sent to your device:");
            string mfaCode = Console.ReadLine();

            AuthFlowResponse mfaResponse = await user.RespondToSmsMfaAuthAsync(new RespondToSmsMfaRequest()
            {
                SessionID = authResponse.SessionID,
                MfaCode = mfaCode

            }).ConfigureAwait(false);
            accessToken = authResponse.AuthenticationResult.AccessToken;
        }
        else
        {
            Console.WriteLine("Unrecognized authentication challenge.");
            accessToken = "";
            break;
        }
    }

    if (authResponse.AuthenticationResult != null)
    {
        Console.WriteLine("User successfully authenticated.");
    }
    else
    {
        Console.WriteLine("Error in authentication process.");
    }
 
}
```

### Utilice AWS los recursos después de la autenticación
<a name="use-aws-resources-after-authentication"></a>

Una vez que un usuario se autentica mediante la CognitoAuthentication biblioteca, el siguiente paso es permitir que el usuario acceda a los AWS recursos adecuados. Para ello, debe crear un grupo de identidades a través de la consola de identidades federadas de Amazon Cognito. Al especificar el grupo de usuarios de Amazon Cognito que creó como proveedor mediante su poolID y clientID correspondientes, puede permitir que los usuarios del grupo de usuarios de Amazon Cognito tengan acceso a los recursos de AWS conectados a su cuenta. También puede especificar diferentes funciones para que los usuarios, tanto autenticados como sin autenticar, obtengan acceso a los diferentes recursos. Puede cambiar estas reglas en la consola de IAM, donde puede agregar o eliminar permisos en el campo **Acción** de la política conectada al rol. A continuación, con el grupo de identidades, el grupo de usuarios y la información de usuario de Amazon Cognito adecuados, puede realizar llamadas a distintos AWS recursos. En el siguiente ejemplo se muestra un usuario autenticado con SRP que obtiene acceso a distintos buckets de Amazon S3 permitidos por el rol del grupo de identidades asociado.

```
public async void GetS3BucketsAsync()
{
    var provider = new AmazonCognitoIdentityProviderClient(new AnonymousAWSCredentials());
    CognitoUserPool userPool = new CognitoUserPool("poolID", "clientID", provider);
    CognitoUser user = new CognitoUser("username", "clientID", userPool, provider);

    string password = "userPassword";

    AuthFlowResponse context = await user.StartWithSrpAuthAsync(new InitiateSrpAuthRequest()
    {
        Password = password
    }).ConfigureAwait(false);

    CognitoAWSCredentials credentials =
        user.GetCognitoAWSCredentials("identityPoolID", RegionEndpoint.< YourIdentityPoolRegion >);

    using (var client = new AmazonS3Client(credentials))
    {
        ListBucketsResponse response =
            await client.ListBucketsAsync(new ListBucketsRequest()).ConfigureAwait(false);

        foreach (S3Bucket bucket in response.Buckets)
        {
            Console.WriteLine(bucket.BucketName);
        }
    }
}
```

## Más opciones de autenticación
<a name="more-authentication-options"></a>

Además de SRP y MFA NewPasswordRequired, CognitoAuthentication la biblioteca de extensiones ofrece un flujo de autenticación más sencillo para:
+ Custom: inicio con una llamada a `StartWithCustomAuthAsync(InitiateCustomAuthRequest customRequest)` 
+ RefreshToken - Inicie con una llamada a `StartWithRefreshTokenAuthAsync(InitiateRefreshTokenAuthRequest refreshTokenRequest)` 
+ RefreshTokenSRP: inicie con una llamada a `StartWithRefreshTokenAuthAsync(InitiateRefreshTokenAuthRequest refreshTokenRequest)` 
+ AdminNoSRP: inicie con una llamada a `StartWithAdminNoSrpAuthAsync(InitiateAdminNoSrpAuthRequest adminAuthRequest)` 

Llame al método apropiado según el flujo que desee. A continuación, siga pidiendo al usuario que responda a los desafíos a medida que se presenten en los objetos `AuthFlowResponse` de cada llamada al método. También llame al método de respuesta adecuado; por ejemplo, `RespondToSmsMfaAuthAsync` para los desafíos de MFA y `RespondToCustomAuthAsync` para los desafíos personalizados.

# Uso de bases de datos NoSQL de Amazon DynamoDB
<a name="dynamodb-intro"></a>

**nota**  
Los modelos de programación de estos temas están presentes tanto en .NET Framework como en .NET (Core), pero las convenciones de llamada difieren entre sincrónicas y asincrónicas.

 AWS SDK para .NET Es compatible con Amazon DynamoDB, que es un servicio rápido de base de datos NoSQL ofrecido por. AWS SDK proporciona tres modelos de programación para comunicarse con DynamoDB: el modelo *de bajo nivel*, el modelo de *documento* y el modelo de *persistencia de objetos*.

La siguiente información presenta estos modelos y sus modelos APIs, proporciona ejemplos de cómo y cuándo utilizarlos y proporciona enlaces a recursos de programación adicionales de DynamoDB en. AWS SDK para .NET

## Modelo de bajo nivel
<a name="dynamodb-intro-apis-low-level"></a>

El modelo de programación de bajo nivel incluye llamadas directas al servicio DynamoDB. Puede acceder a este modelo a través del espacio de nombres [DBv2Amazon.Dynamo](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/DynamoDBv2/NDynamoDBv2.html).

De los tres modelos, el de bajo nivel requiere que escriba la mayor parte del código. Por ejemplo, debe convertir los tipos de datos de .NET en sus equivalentes en DynamoDB. Sin embargo, este modelo le ofrece acceso a la mayoría de las características.

En el siguiente ejemplo se muestra cómo usar el modelo de bajo nivel para crear una tabla, modificarla e insertar elementos en ella en DynamoDB.

### Creación de una tabla
<a name="dynamodb-intro-apis-low-level-create-table"></a>

En el siguiente ejemplo, puede crear una tabla mediante el método `CreateTable` de la clase `AmazonDynamoDBClient`. El método `CreateTable` usa una instancia de la clase `CreateTableRequest` que contiene características como los nombres de atributos de elemento obligatorios, la definición de clave principal y la capacidad de desempeño. El método `CreateTable` devuelve una instancia de la clase `CreateTableResponse`.

```
// using Amazon.DynamoDBv2;
// using Amazon.DynamoDBv2.Model;

var client = new AmazonDynamoDBClient();

Console.WriteLine("Getting list of tables");
List<string> currentTables = client.ListTables().TableNames;
Console.WriteLine("Number of tables: " + currentTables.Count);
if (!currentTables.Contains("AnimalsInventory"))
{
    var request = new CreateTableRequest
    {
        TableName = "AnimalsInventory",
        AttributeDefinitions = new List<AttributeDefinition>
      {
        new AttributeDefinition
        {
          AttributeName = "Id",
          // "S" = string, "N" = number, and so on.
          AttributeType = "N"
        },
        new AttributeDefinition
        {
          AttributeName = "Type",
          AttributeType = "S"
        }
      },
        KeySchema = new List<KeySchemaElement>
      {
        new KeySchemaElement
        {
          AttributeName = "Id",
          // "HASH" = hash key, "RANGE" = range key.
          KeyType = "HASH"
        },
        new KeySchemaElement
        {
          AttributeName = "Type",
          KeyType = "RANGE"
        },
      },
        ProvisionedThroughput = new ProvisionedThroughput
        {
            ReadCapacityUnits = 10,
            WriteCapacityUnits = 5
        },
    };

    var response = client.CreateTable(request);

    Console.WriteLine("Table created with request ID: " +
      response.ResponseMetadata.RequestId);
}
```

### Verificación de la preparación de una tabla para su modificación
<a name="dynamodb-intro-apis-low-level-verify-table"></a>

Antes de poder cambiar o modificar una tabla, esta debe estar lista para ello. En el siguiente ejemplo se muestra cómo usar el modelo de bajo nivel para verificar que una tabla de DynamoDB está lista. En este ejemplo, se hace referencia a la tabla de destino que se comprobará a través del método `DescribeTable` de la clase `AmazonDynamoDBClient`. Cada cinco segundos, el código comprueba el valor de la propiedad `TableStatus` de la tabla. Cuando el estado se establezca en `ACTIVE`, la tabla estará lista para modificarse.

```
// using Amazon.DynamoDBv2;
// using Amazon.DynamoDBv2.Model;

var client = new AmazonDynamoDBClient();      
var status = "";

do
{
  // Wait 5 seconds before checking (again).
  System.Threading.Thread.Sleep(TimeSpan.FromSeconds(5));
        
  try
  {
    var response = client.DescribeTable(new DescribeTableRequest
    {
      TableName = "AnimalsInventory"
    });

    Console.WriteLine("Table = {0}, Status = {1}",
      response.Table.TableName,
      response.Table.TableStatus);

    status = response.Table.TableStatus;
  }
  catch (ResourceNotFoundException)
  {
    // DescribeTable is eventually consistent. So you might
    //   get resource not found. 
  }

} while (status != TableStatus.ACTIVE);
```

### Inserción de un elemento en una tabla
<a name="dynamodb-intro-apis-low-level-insert-item"></a>

En el siguiente ejemplo se usa el modelo de bajo nivel para insertar dos elementos en una tabla de DynamoDB. Cada elemento se inserta a través del método `PutItem` de la clase `AmazonDynamoDBClient`, mediante una instancia de la clase `PutItemRequest`. Cada una de las dos instancias de la clase `PutItemRequest` toma el nombre de la tabla en la que se insertarán los elementos, con una serie de valores de atributos de elemento.

```
// using Amazon.DynamoDBv2;
// using Amazon.DynamoDBv2.Model;

var client = new AmazonDynamoDBClient();

var request1 = new PutItemRequest
{
  TableName = "AnimalsInventory",
  Item = new Dictionary<string, AttributeValue>
  {
    { "Id", new AttributeValue { N = "1" }},
    { "Type", new AttributeValue { S = "Dog" }},
    { "Name", new AttributeValue { S = "Fido" }}
  }
};

var request2 = new PutItemRequest
{
  TableName = "AnimalsInventory",
  Item = new Dictionary<string, AttributeValue>
  {
    { "Id", new AttributeValue { N = "2" }},
    { "Type", new AttributeValue { S = "Cat" }},
    { "Name", new AttributeValue { S = "Patches" }}
  }
};
        
client.PutItem(request1);
client.PutItem(request2);
```

## Modelo de documento
<a name="dynamodb-intro-apis-document"></a>

El modelo de programación del documento proporciona una forma más sencilla de trabajar con datos en DynamoDB. Este modelo está destinado de manera específica al acceso a tablas y elementos de las tablas. [Puede acceder a este modelo a través de Amazon.Dynamo. DBv2 DocumentModel](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/DynamoDBv2/NDynamoDBv2DocumentModel.html)espacio de nombres.

En comparación con el modelo de programación de bajo nivel, es más sencillo escribir el código del modelo de documento en los datos de DynamoDB. Por ejemplo, no debe convertir tantos tipos de datos de .NET en sus equivalentes en DynamoDB. Sin embargo, este modelo no proporciona acceso a tantas características como el modelo de programación de bajo nivel. Por ejemplo, puede usar este modelo para crear, recuperar, actualizar y eliminar elementos de las tablas. No obstante, para crear las tablas, debe usar el modelo de bajo nivel. En comparación con el modelo de persistencia de objetos, este modelo requiere que escriba más código para almacenar, cargar y consultar objetos de .NET.

Para obtener más información sobre el modelo de programación de documentos de DynamoDB, consulte [.NET: modelo de documento](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DotNetSDKMidLevel.html) en la [Guía para desarrolladores de Amazon DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/).

En las siguientes secciones se proporciona información sobre cómo crear una representación de la tabla de DynamoDB deseada, así como ejemplos sobre cómo utilizar el modelo de documento para insertar elementos en tablas y obtener elementos de tablas.

### Creación de una representación de la tabla
<a name="dynamodb-intro-apis-document-table"></a>

Para llevar a cabo operaciones de datos con el modelo de documento, primero hay que crear una instancia de la clase `Table` que representa una tabla específica. Principalmente, hay dos formas de hacer esto.

**LoadTable method**

El primer mecanismo consiste en utilizar uno de los métodos `LoadTable` estáticos de la clase [https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/DynamoDBv2/TTable.html](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/DynamoDBv2/TTable.html), similar al ejemplo siguiente:

```
var client = new AmazonDynamoDBClient();
Table table = Table.LoadTable(client, "Reply");
```

**nota**  
Aunque este mecanismo funciona, hay veces que, bajo determinadas condiciones, puede provocar más latencias o interbloqueos debido a comportamientos de inicio en frío y de grupo de subprocesos. Para obtener más información sobre estos comportamientos, consulte la entrada de blog [Improved DynamoDB Initialization Patterns for AWS SDK para .NET](https://aws.amazon.com/blogs/developer/improved-dynamodb-initialization-patterns-for-the-aws-sdk-for-net/).

**TableBuilder**

En la [versión 3.7.203 del [https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/DynamoDBv2/TTableBuilder.html](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/DynamoDBv2/TTableBuilder.html)paquete .Dynamo se introdujo un mecanismo alternativo, la](https://www.nuget.org/packages/AWSSDK.DynamoDBv2/3.7.203) clase. AWSSDK DBv2 NuGet Este mecanismo aborda los comportamientos mencionados anteriormente, ya que elimina ciertas llamadas a método implícitas, en concreto, el método `DescribeTable`. Este mecanismo se utiliza de forma similar a la del siguiente ejemplo:

```
var client = new AmazonDynamoDBClient();
var table = new TableBuilder(client, "Reply")
    .AddHashKey("Id", DynamoDBEntryType.String)
    .AddRangeKey("ReplyDateTime", DynamoDBEntryType.String)
    .AddGlobalSecondaryIndex("PostedBy-Message-index", "Author", DynamoDBEntryType.String, "Message", DynamoDBEntryType.String)
    .Build();
```

Para obtener más información sobre este mecanismo alternativo, consulte la entrada de blog [Patrones de inicialización de DynamoDB mejorados para AWS SDK para .NET](https://aws.amazon.com/blogs/developer/improved-dynamodb-initialization-patterns-for-the-aws-sdk-for-net/).

### Inserción de un elemento en una tabla
<a name="dynamodb-intro-apis-document-insert-item"></a>

En el siguiente ejemplo se inserta una respuesta en la tabla Reply a través del método `PutItemAsync` de la clase `Table`. El método `PutItemAsync` toma una instancia de la clase `Document`; la clase `Document` es sencillamente una colección de atributos inicializados.

```
using Amazon.DynamoDBv2;
using Amazon.DynamoDBv2.DocumentModel;

// Create a representation of the "Reply" table
//  by using one of the mechanisms described previously.

// Then, add a reply to the table.
var newReply = new Document();
newReply["Id"] = Guid.NewGuid().ToString();
newReply["ReplyDateTime"] = DateTime.UtcNow;
newReply["PostedBy"] = "Author1";
newReply["Message"] = "Thank you!";

await table.PutItemAsync(newReply);
```

### Obtención de un elemento de una tabla
<a name="dynamodb-intro-apis-document-get-item"></a>

En el siguiente ejemplo se recupera una respuesta a través del método `GetItemAsync` de la clase `Table`. Para determinar la respuesta que se va a obtener, el `GetItemAsync` método utiliza la clave hash-and-range principal de la respuesta de destino.

```
using Amazon.DynamoDBv2;
using Amazon.DynamoDBv2.DocumentModel;

// Create a representation of the "Reply" table
//  by using one of the mechanisms described previously.

// Then, get a reply from the table
//  where "guid" is the hash key and "datetime" is the range key.
var reply = await table.GetItemAsync(guid, datetime);
Console.WriteLine("Id = " + reply["Id"]);
Console.WriteLine("ReplyDateTime = " + reply["ReplyDateTime"]);
Console.WriteLine("PostedBy = " + reply["PostedBy"]);
Console.WriteLine("Message = " + reply["Message"]);
```

En el ejemplo anterior, los valores de la tabla se convierten de forma implícita en cadenas para el método `WriteLine`. Puede realizar conversiones explícitas mediante los diversos métodos “As[type]” de la clase `DynamoDBEntry`. Por ejemplo, puede convertir el valor de atributo de `Id` de forma explícita a partir de un tipo de datos `Primitive` en un GUID a través del método `AsGuid()`:

```
var guid = reply["Id"].AsGuid();
```

## Modelo de persistencia de objetos
<a name="dynamodb-intro-apis-object-persistence"></a>

El modelo de programación de persistencia de objetos está diseñado de forma específica para almacenar, cargar y consultar objetos de .NET en DynamoDB. Puede acceder a este modelo a través de [DBv2Amazon.Dynamo. DataModel](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/DynamoDBv2/NDynamoDBv2DataModel.html)espacio de nombres.

De los tres modelos, lo más sencillo es escribir el código del modelo de persistencia de objetos siempre que almacene, cargue o consulte los datos de DynamoDB. Por ejemplo, puede trabajar directamente con los tipos de datos de DynamoDB. Sin embargo, este modelo proporciona acceso únicamente a las operaciones que almacenan, cargan y consultan objetos de .NET en DynamoDB. Por ejemplo, puede usar este modelo para crear, recuperar, actualizar y eliminar elementos de las tablas. Sin embargo, primero debe crear sus tablas con el modelo de bajo nivel y, a continuación, utilizar este modelo para asignar las clases de .NET a las tablas.

Para obtener más información sobre el modelo de programación de persistencia de objetos de DynamoDB, consulte [.NET: modelo de persistencia de objetos](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DotNetSDKHighLevel.html) en la [Guía para desarrolladores de Amazon DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/).

En los siguientes ejemplos se muestra cómo definir una clase de .NET que representa un elemento de DynamoDB, cómo usar una instancia de la clase de .NET para insertar un elemento de DynamoDB y cómo usar una instancia de la clase de .NET para obtener un elemento de DynamoDB de una tabla.

### Definición de una clase de .NET que representa un elemento en una tabla
<a name="dynamodb-intro-apis-object-persistence-net-class-item"></a>

En el siguiente ejemplo de definición de clase, el `DynamoDBTable` atributo especifica el nombre de la tabla, mientras que los `DynamoDBRangeKey` atributos `DynamoDBHashKey` y modelan la clave hash-and-range principal de la tabla. El atributo `DynamoDBGlobalSecondaryIndexHashKey` se define de forma que se pueda crear una consulta para obtener respuestas de un autor específico.

```
using Amazon.DynamoDBv2;
using Amazon.DynamoDBv2.DataModel;

[DynamoDBTable("Reply")]
public class Reply
{
    [DynamoDBHashKey]
    public string Id { get; set; }

    [DynamoDBRangeKey(StoreAsEpoch = false)]
    public DateTime ReplyDateTime { get; set; }

    [DynamoDBGlobalSecondaryIndexHashKey("PostedBy-Message-Index",
        AttributeName ="PostedBy")]
    public string Author { get; set; }

    [DynamoDBGlobalSecondaryIndexRangeKey("PostedBy-Message-Index")]
    public string Message { get; set; }
}
```

### Creación de un contexto para el modelo de persistencia de objetos
<a name="dynamodb-intro-apis-object-persistence-context"></a>

Para utilizar el modelo de programación de persistencia de objetos de DynamoDB, debe crear un contexto que ofrezca una conexión a DynamoDB y que permita obtener acceso a las tablas, realizar diversas operaciones y ejecutar consultas.

**Contexto básico**

En el siguiente ejemplo de código se muestra cómo crear el contexto más básico.

```
using Amazon.DynamoDBv2;
using Amazon.DynamoDBv2.DataModel;

var client = new AmazonDynamoDBClient();
var context = new DynamoDBContext(client);
```

**Contexto con DisableFetchingTableMetadata propiedad**

En el siguiente ejemplo se muestra cómo se podría establecer también la propiedad `DisableFetchingTableMetadata` de la clase `DynamoDBContextConfig` para evitar llamadas implícitas al método `DescribeTable`.

```
using Amazon.DynamoDBv2;
using Amazon.DynamoDBv2.DataModel;

var client = new AmazonDynamoDBClient();
var context = new DynamoDBContext(client, new DynamoDBContextConfig
{
    DisableFetchingTableMetadata = true
});
```

Si la propiedad `DisableFetchingTableMetadata` está establecida en `false` (valor predeterminado), como se muestra en el primer ejemplo, puede omitir de la clase `Reply` los atributos que describan la estructura de clave e índice de los elementos de la tabla. En su lugar, estos atributos se deducirán mediante una llamada implícita al método `DescribeTable`. Si `DisableFetchingTableMetadata` se establece en `true`, como se muestra en el segundo ejemplo, los métodos del modelo de persistencia de objetos (como `SaveAsync` y `QueryAsync`) se basan completamente en los atributos definidos en la clase `Reply`. En tal caso, no se realiza ninguna llamada al método `DescribeTable`.

**nota**  
Bajo determinadas condiciones, las llamadas al método `DescribeTable` pueden provocar más latencias o interbloqueos debido a comportamientos de inicio en frío y de grupo de subprocesos. Por este motivo, a veces resulta beneficioso evitar las llamadas a ese método.  
Para obtener más información sobre estos comportamientos, consulte la entrada de blog [Patrones de inicialización de DynamoDB mejorados para AWS SDK para .NET](https://aws.amazon.com/blogs/developer/improved-dynamodb-initialization-patterns-for-the-aws-sdk-for-net/).

### Uso de una instancia de la clase de .NET para insertar un elemento en una tabla
<a name="dynamodb-intro-apis-object-persistence-net-insert-item"></a>

En este ejemplo, se inserta un elemento a través del método `SaveAsync` de la clase `DynamoDBContext`, que toma una instancia inicializada de la clase de .NET que representa el elemento

```
using Amazon.DynamoDBv2;
using Amazon.DynamoDBv2.DataModel;

// Create an appropriate context for the object persistence programming model,
//  examples of which have been described earlier.

// Create an object that represents the new item.
var reply = new Reply()
{
    Id = Guid.NewGuid().ToString(),
    ReplyDateTime = DateTime.UtcNow,
    Author = "Author1",
    Message = "Thank you!"
};

// Insert the item into the table.
await context.SaveAsync<Reply>(reply, new DynamoDBOperationConfig
{
    IndexName = "PostedBy-Message-index"
});
```

### Uso de una instancia de una clase de .NET para obtener elementos de una tabla
<a name="dynamodb-intro-apis-object-persistence-net-get-item"></a>

En este ejemplo, se crea una consulta para encontrar todos los registros de “Author1” mediante el método `QueryAsync` de la clase `DynamoDBContext`. Después, los elementos se recuperan mediante el método `GetNextSetAsync` de la consulta.

```
using Amazon.DynamoDBv2;
using Amazon.DynamoDBv2.DataModel;

// Create an appropriate context for the object persistence programming model,
//  examples of which have been described earlier.

// Construct a query that finds all replies by a specific author.
var query = context.QueryAsync<Reply>("Author1", new DynamoDBOperationConfig
{
    IndexName = "PostedBy-Message-index"
});

// Display the result.
var set = await query.GetNextSetAsync();
foreach (var item in set)
{
    Console.WriteLine("Id = " + item.Id);
    Console.WriteLine("ReplyDateTime = " + item.ReplyDateTime);
    Console.WriteLine("PostedBy = " + item.Author);
    Console.WriteLine("Message = " + item.Message);
}
```

### Información adicional sobre el modelo de persistencia de objetos
<a name="dynamodb-intro-apis-object-persistence-more-into"></a>

Los ejemplos y las explicaciones que se muestran arriba incluyen a veces una propiedad de la clase `DynamoDBContext` llamada `DisableFetchingTableMetadata`. Esta propiedad, que se introdujo en la [versión 3.7.203 del DBv2 NuGet paquete AWSSDK .Dynamo](https://www.nuget.org/packages/AWSSDK.DynamoDBv2/3.7.203), permite evitar determinadas condiciones que podrían provocar una latencia adicional o puntos muertos debido a los comportamientos de arranque en frío y de agrupación de subprocesos. Para obtener más información, consulte la entrada de blog [Patrones de inicialización de DynamoDB mejorados para AWS SDK para .NET](https://aws.amazon.com/blogs/developer/improved-dynamodb-initialization-patterns-for-the-aws-sdk-for-net/).

Aquí tiene más información sobre esta propiedad.
+ Esta propiedad se puede establecer globalmente en los archivos `app.config` o `web.config` si utiliza .NET Framework.
+ Esta propiedad se puede establecer globalmente con la clase [https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/Amazon/TAWSConfigsDynamoDB.html](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/Amazon/TAWSConfigsDynamoDB.html), como se muestra en el siguiente ejemplo.

  ```
  // Set the DisableFetchingTableMetadata property globally
  // before constructing any context objects.
  AWSConfigsDynamoDB.Context.DisableFetchingTableMetadata = true;
  
  var client = new AmazonDynamoDBClient();
  var context = new DynamoDBContext(client);
  ```
+ En algunos casos, no se pueden agregar atributos de DynamoDB a una clase de .NET; por ejemplo, si la clase está definida en una dependencia. En estos casos, se puede seguir sacando partido de la propiedad `DisableFetchingTableMetadata`. Para ello, utilice la clase [https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/DynamoDBv2/TTableBuilder.html](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/DynamoDBv2/TTableBuilder.html) además de la propiedad `DisableFetchingTableMetadata`. [La `TableBuilder` clase también se introdujo en la versión 3.7.203 del paquete .Dynamo. AWSSDK DBv2 NuGet ](https://www.nuget.org/packages/AWSSDK.DynamoDBv2/3.7.203)

  ```
  // Set the DisableFetchingTableMetadata property globally
  // before constructing any context objects.
  AWSConfigsDynamoDB.Context.DisableFetchingTableMetadata = true;
  
  var client = new AmazonDynamoDBClient();
  var context = new DynamoDBContext(client);
  
  var table = new TableBuilder(client, "Reply")
      .AddHashKey("Id", DynamoDBEntryType.String)
      .AddRangeKey("ReplyDateTime", DynamoDBEntryType.String)
      .AddGlobalSecondaryIndex("PostedBy-Message-index", "Author", DynamoDBEntryType.String,
          "Message", DynamoDBEntryType.String)
      .Build();
  
  // This registers the "Reply" table we constructed via the builder.
  context.RegisterTableDefinition(table);
  
  // Now operations like this will work,
  // even if the Reply class was not annotated with this index.
  var query = context.QueryAsync<Reply>("Author1", new DynamoDBOperationConfig()
  {
      IndexName = "PostedBy-Message-index"
  });
  ```

## Más información
<a name="dynamodb-intro-more-info"></a>

 **Uso del AWS SDK para .NET programa DynamoDB, información y ejemplos**
+  [DynamoDB APIs](http://blogs.aws.amazon.com/net/post/Tx17SQHVEMW8MXC/DynamoDB-APIs) 
+  [Puesta en marcha de la serie DynamoDB](http://blogs.aws.amazon.com/net/post/Tx2XQOCY08QMTKO/DynamoDB-Series-Kickoff) 
+  [Serie DynamoDB: modelo de documento](http://blogs.aws.amazon.com/net/post/Tx2R0WG46GQI1JI/DynamoDB-Series-Document-Model) 
+  [Serie DynamoDB: esquemas de conversión](http://blogs.aws.amazon.com/net/post/Tx2TCOGWG7ARUH5/DynamoDB-Series-Conversion-Schemas) 
+  [Serie DynamoDB: modelo de persistencia de objetos](http://blogs.aws.amazon.com/net/post/Tx20L86FLMBW51P/DynamoDB-Series-Object-Persistence-Model) 
+  [Serie de DynamoDB: expresiones](http://blogs.aws.amazon.com/net/post/TxZQM7VA9AUZ9L/DynamoDB-Series-Expressions) 
+  [Uso de expresiones con Amazon DynamoDB y AWS SDK para .NET](dynamodb-expressions.md) 
+  [Compatibilidad con JSON en Amazon DynamoDB](dynamodb-json.md) 

 **Información y ejemplos del modelo de bajo nivel** 
+  [Trabajar con tablas mediante la API de bajo nivel AWS SDK para .NET](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/LowLevelDotNetWorkingWithTables.html) 
+  [Trabajar con elementos mediante la API de AWS SDK para .NET bajo nivel](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/LowLevelDotNetItemCRUD.html) 
+  [Consulta de tablas mediante la API de bajo nivel AWS SDK para .NET](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/LowLevelDotNetQuerying.html) 
+  [Escaneo de tablas mediante la API de bajo nivel AWS SDK para .NET](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/LowLevelDotNetScanning.html) 
+  [Trabajar con índices secundarios locales mediante la API de bajo nivel AWS SDK para .NET](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/LSILowLevelDotNet.html) 
+  [Trabajar con índices secundarios globales mediante la API de bajo nivel AWS SDK para .NET](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GSILowLevelDotNet.html) 

 **Información y ejemplos del modelo de documento** 
+  [Tipos de datos de DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DataModel.html#DataModel.DataTypes) 
+  [Dinamo DBEntry](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/TDynamoDBv2DocumentModelDynamoDBEntry.html) 
+  [.NET: modelo de documento](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DotNetSDKMidLevel.html) 

 **Información y ejemplos del modelo de persistencia de objetos** 
+  [.NET: modelo de persistencia de objetos](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DotNetSDKHighLevel.html) 

 **Otra información útil** 
+ Consulte [Integración de AWS con .NET Aspire](aspire-integrations.md) para obtener información sobre el desarrollo con Amazon DynamoDB local a través de .NET Aspire.

**Topics**
+ [

## Modelo de bajo nivel
](#dynamodb-intro-apis-low-level)
+ [

## Modelo de documento
](#dynamodb-intro-apis-document)
+ [

## Modelo de persistencia de objetos
](#dynamodb-intro-apis-object-persistence)
+ [

## Más información
](#dynamodb-intro-more-info)
+ [Uso de expresiones](dynamodb-expressions.md)
+ [Compatibilidad con JSON](dynamodb-json.md)

# Uso de expresiones con Amazon DynamoDB y AWS SDK para .NET
<a name="dynamodb-expressions"></a>

**nota**  
La información de este tema es específica de los proyectos basados en .NET Framework y en la AWS SDK para .NET versión 3.3 y anteriores.

Los siguientes ejemplos de código muestran cómo utilizar el AWS SDK para .NET para programar DynamoDB con expresiones. Las *expresiones* se utilizan para indicar los atributos que se desea leer de un elemento en una tabla de DynamoDB. Además, se pueden utilizar al escribir un elemento para indicar las condiciones que se deben cumplir (lo que recibe el nombre también de *actualización condicional*) y la manera en que se deben actualizar los atributos. Algunos ejemplos de actualización sustituyen el atributo por un valor nuevo o añaden datos nuevos a una lista o mapa. Para obtener más información acerca del uso de expresiones, consulte el tema sobre [cómo leer y escribir elementos mediante expresiones](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.html).

**Topics**
+ [

## Datos de ejemplo
](#dynamodb-expressions-sample-data)
+ [

## Obtención de un elemento individual utilizando expresiones y la clave principal del elemento
](#dynamodb-expressions-get-item)
+ [

## Obtención de varios elementos utilizando expresiones y la clave principal de la tabla
](#dynamodb-expressions-query)
+ [

## Obtención de varios elementos utilizando expresiones y otros atributos del elemento
](#dynamodb-expressions-scan)
+ [

## Imprimir un elemento
](#dynamodb-expressions-print-item)
+ [

## Crear o reemplazar un elemento utilizando expresiones
](#dynamodb-expressions-put-item)
+ [

## Actualizar un elemento utilizando expresiones
](#dynamodb-expressions-update-item)
+ [

## Eliminación de un elemento utilizando expresiones
](#dynamodb-expressions-delete-item)
+ [

## Más información
](#dynamodb-expressions-resources)

## Datos de ejemplo
<a name="dynamodb-expressions-sample-data"></a>

Los ejemplos de código de este tema hacen referencia a los dos elementos de ejemplo siguientes de una tabla de DynamoDB llamada `ProductCatalog`. Estos elementos describen información sobre entradas de producto en un catálogo ficticio de una tienda de bicicletas. Estos elementos se basan en el ejemplo proporcionado en [Case Study: A ProductCatalog ](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.CaseStudy.html) Item. Los descriptores de tipos de datos como `BOOL`, `L`, `M`, `N`, `NS`, `S` y `SS` equivalen a los del [formato de datos JSON](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DataFormat.html).

```
{
  "Id": {
    "N": "205"
  },
  "Title": {
    "S": "20-Bicycle 205"
  },
  "Description": {
    "S": "205 description"
  },
  "BicycleType": {
    "S": "Hybrid"
  },
  "Brand": {
    "S": "Brand-Company C"
  },
  "Price": {
    "N": "500"
  },
  "Gender": {
    "S": "B"
  },
  "Color": {
    "SS": [
      "Red",
      "Black"
    ]
  },
  "ProductCategory": {
    "S": "Bike"
  },
  "InStock": {
    "BOOL": true
  },
  "QuantityOnHand": {
    "N": "1"
  },
  "RelatedItems": {
    "NS": [
      "341",
      "472",
      "649"
    ]
  },
  "Pictures": {
    "L": [
      {
        "M": {
          "FrontView": {
            "S": "http://example/products/205_front.jpg"
          }
        }
      },
      {
        "M": {
          "RearView": {
            "S": "http://example/products/205_rear.jpg"
          }
        }
      },
      {
        "M": {
          "SideView": {
            "S": "http://example/products/205_left_side.jpg"
          }
        }
      }
    ]
  },
  "ProductReviews": {
    "M": {
      "FiveStar": {
        "SS": [
          "Excellent! Can't recommend it highly enough! Buy it!",
          "Do yourself a favor and buy this."
        ]
      },
      "OneStar": {
        "SS": [
          "Terrible product! Do not buy this."
        ]
      }
    }
  }
},
{
  "Id": {
    "N": "301"
  },
  "Title": {
    "S": "18-Bicycle 301"
  },
  "Description": {
    "S": "301 description"
  },
  "BicycleType": {
    "S": "Road"
  },
  "Brand": {
    "S": "Brand-Company C"
  },
  "Price": {
    "N": "185"
  },
  "Gender": {
    "S": "F"
  },
  "Color": {
    "SS": [
      "Blue",
      "Silver"
    ]
  },
  "ProductCategory": {
    "S": "Bike"
  },
  "InStock": {
    "BOOL": true
  },
  "QuantityOnHand": {
    "N": "3"
  },
  "RelatedItems": {
    "NS": [
      "801",
      "822",
      "979"
    ]
  },
  "Pictures": {
    "L": [
      {
        "M": {
          "FrontView": {
            "S": "http://example/products/301_front.jpg"
          }
        }
      },
      {
        "M": {
          "RearView": {
            "S": "http://example/products/301_rear.jpg"
          }
        }
      },
      {
        "M": {
          "SideView": {
            "S": "http://example/products/301_left_side.jpg"
          }
        }
      }
    ]
  },
  "ProductReviews": {
    "M": {
      "FiveStar": {
        "SS": [
          "My daughter really enjoyed this bike!"
        ]
      },
      "ThreeStar": {
        "SS": [
          "This bike was okay, but I would have preferred it in my color.",
	      "Fun to ride."
        ]
      }
    }
  }
}
```

## Obtención de un elemento individual utilizando expresiones y la clave principal del elemento
<a name="dynamodb-expressions-get-item"></a>

En el siguiente ejemplo se muestra el método `Amazon.DynamoDBv2.AmazonDynamoDBClient.GetItem` y un conjunto de expresiones para obtener y luego imprimir el elemento que tenga un `Id` `205`. Solo se devuelven los siguientes atributos del elemento: `Id`, `Title`, `Description`, `Color`, `RelatedItems`, `Pictures` y `ProductReviews`.

```
// using Amazon.DynamoDBv2;
// using Amazon.DynamoDBv2.Model;

var client = new AmazonDynamoDBClient();
var request = new GetItemRequest
{
  TableName = "ProductCatalog",
  ProjectionExpression = "Id, Title, Description, Color, #ri, Pictures, #pr",
  ExpressionAttributeNames = new Dictionary<string, string>
  {
    { "#pr", "ProductReviews" },
    { "#ri", "RelatedItems" }
  },
  Key = new Dictionary<string, AttributeValue>
  {
    { "Id", new AttributeValue { N = "205" } }
  },
};
var response = client.GetItem(request);

// PrintItem() is a custom function.
PrintItem(response.Item);
```

En el ejemplo anterior, la propiedad `ProjectionExpression` especifica los atributos que se deben devolver. La propiedad `ExpressionAttributeNames` especifica el marcador de posición `#pr` para que represente el atributo `ProductReviews` y el marcador de posición `#ri` para que represente el atributo `RelatedItems`. La llamada a `PrintItem` hace referencia a una función personalizada, tal como se describe en [Imprimir un elemento](#dynamodb-expressions-print-item).

## Obtención de varios elementos utilizando expresiones y la clave principal de la tabla
<a name="dynamodb-expressions-query"></a>

En el siguiente ejemplo se muestra el método `Amazon.DynamoDBv2.AmazonDynamoDBClient.Query` y un conjunto de expresiones para obtener y luego imprimir el elemento que tenga un `Id` `301`, pero únicamente si el valor de `Price` es mayor que `150`. Solo se devuelven los siguientes atributos del elemento: `Id`, `Title` y todos los atributos de `ThreeStar` en `ProductReviews`.

```
// using Amazon.DynamoDBv2;
// using Amazon.DynamoDBv2.Model;

var client = new AmazonDynamoDBClient();
var request = new QueryRequest
{
  TableName = "ProductCatalog",
  KeyConditions = new Dictionary<string,Condition>
  {
    { "Id", new Condition()
      {
        ComparisonOperator = ComparisonOperator.EQ,
        AttributeValueList = new List<AttributeValue>
        {
          new AttributeValue { N = "301" }
        }
      }
    }
  },
  ProjectionExpression = "Id, Title, #pr.ThreeStar",
  ExpressionAttributeNames = new Dictionary<string, string>
  {
    { "#pr", "ProductReviews" },
    { "#p", "Price" }
  },
  ExpressionAttributeValues = new Dictionary<string,AttributeValue>
  {
    { ":val", new AttributeValue { N = "150" } }
  },
  FilterExpression = "#p > :val"
};
var response = client.Query(request);

foreach (var item in response.Items)
{
  // Write out the first page of an item's attribute keys and values.
  // PrintItem() is a custom function.
  PrintItem(item);
  Console.WriteLine("=====");
}
```

En el ejemplo anterior, la propiedad `ProjectionExpression` especifica los atributos que se deben devolver. La propiedad `ExpressionAttributeNames` especifica el marcador de posición `#pr` para que represente el atributo `ProductReviews` y el marcador de posición `#p` para que represente el atributo `Price`. `#pr.ThreeStar` especifica que solo se devuelva el atributo `ThreeStar`. La propiedad `ExpressionAttributeValues` especifica el marcador de posición `:val` para que represente el valor `150`. La propiedad `FilterExpression` especifica que `#p` (`Price`) debe ser mayor que `:val` (`150`). La llamada a `PrintItem` hace referencia a una función personalizada, tal como se describe en [Imprimir un elemento](#dynamodb-expressions-print-item).

## Obtención de varios elementos utilizando expresiones y otros atributos del elemento
<a name="dynamodb-expressions-scan"></a>

En el siguiente ejemplo se muestra el método `Amazon.DynamoDBv2.AmazonDynamoDBClient.Scan` y un conjunto de expresiones para obtener y luego imprimir todos los elementos que tengan un elemento `ProductCategory` `Bike`. Solo se devuelven los siguientes atributos del elemento: `Id`, `Title` y todos los atributos de `ProductReviews`.

```
// using Amazon.DynamoDBv2;
// using Amazon.DynamoDBv2.Model;

var client = new AmazonDynamoDBClient();
var request = new ScanRequest
{
  TableName = "ProductCatalog",
  ProjectionExpression = "Id, Title, #pr",
  ExpressionAttributeValues = new Dictionary<string,AttributeValue>
  {
    { ":catg", new AttributeValue { S = "Bike" } }
  },
  ExpressionAttributeNames = new Dictionary<string, string>
  {
    { "#pr", "ProductReviews" },
    { "#pc", "ProductCategory" }
  },
  FilterExpression = "#pc = :catg",  
};
var response = client.Scan(request);

foreach (var item in response.Items)
{
  // Write out the first page/scan of an item's attribute keys and values.
  // PrintItem() is a custom function.
  PrintItem(item);
  Console.WriteLine("=====");
}
```

En el ejemplo anterior, la propiedad `ProjectionExpression` especifica los atributos que se deben devolver. La propiedad `ExpressionAttributeNames` especifica el marcador de posición `#pr` para que represente el atributo `ProductReviews` y el marcador de posición `#pc` para que represente el atributo `ProductCategory`. La propiedad `ExpressionAttributeValues` especifica el marcador de posición `:catg` para que represente el valor `Bike`. La propiedad `FilterExpression` especifica que `#pc` (`ProductCategory`) debe ser igual que `:catg` (`Bike`). La llamada a `PrintItem` hace referencia a una función personalizada, tal como se describe en [Imprimir un elemento](#dynamodb-expressions-print-item).

## Imprimir un elemento
<a name="dynamodb-expressions-print-item"></a>

El siguiente ejemplo muestra cómo imprimir los atributos y valores de un elemento. Este ejemplo se utiliza en los ejemplos anteriores que muestran cómo [Obtener un elemento individual utilizando expresiones y la clave principal del elemento](#dynamodb-expressions-get-item), [Obtener varios elementos utilizando expresiones y la clave principal de la tabla](#dynamodb-expressions-query) y [Obtener varios elementos utilizando expresiones y otros atributos del elemento](#dynamodb-expressions-scan).

```
// using Amazon.DynamoDBv2.Model;

// Writes out an item's attribute keys and values.
public static void PrintItem(Dictionary<string, AttributeValue> attrs)
{
  foreach (KeyValuePair<string, AttributeValue> kvp in attrs)
  {
    Console.Write(kvp.Key + " = ");
    PrintValue(kvp.Value);
  }
}

// Writes out just an attribute's value.
public static void PrintValue(AttributeValue value)
{
  // Binary attribute value.
  if (value.B != null)
  {
    Console.Write("Binary data");
  }
  // Binary set attribute value.
  else if (value.BS.Count > 0)
  {
    foreach (var bValue in value.BS)
    {
      Console.Write("\n  Binary data");
    }
  }
  // List attribute value.
  else if (value.L.Count > 0)
  {
    foreach (AttributeValue attr in value.L)
    {
      PrintValue(attr);
    }
  }
  // Map attribute value.
  else if (value.M.Count > 0)
  {
    Console.Write("\n");
    PrintItem(value.M);
  }
  // Number attribute value.
  else if (value.N != null)
  {
    Console.Write(value.N);
  }
  // Number set attribute value.
  else if (value.NS.Count > 0)
  {
    Console.Write("{0}", string.Join("\n", value.NS.ToArray()));
  }
  // Null attribute value.
  else if (value.NULL)
  {
    Console.Write("Null");
  }
  // String attribute value.
  else if (value.S != null)
  {
    Console.Write(value.S);
  }
  // String set attribute value.
  else if (value.SS.Count > 0)
  {
    Console.Write("{0}", string.Join("\n", value.SS.ToArray()));
  }
  // Otherwise, boolean value.
  else
  {
    Console.Write(value.BOOL);
  }
 
  Console.Write("\n");
}
```

En el ejemplo anterior, cada valor de atributo tiene varias data-type-specific propiedades que se pueden evaluar para determinar el formato correcto para imprimir el atributo. Estas propiedades incluyen `B`, `BOOL`, `BS`, `L`, `M`, `N`, `NS`, `NULL`, `S` y `SS`, que corresponden a aquellas propiedades con el [formato de datos JSON](DataFormat.html). Para propiedades como `B`, `N`, `NULL` y `S`, si la propiedad correspondiente no es `null`, entonces el atributo será del tipo de datos no `null` correspondiente. En el caso de propiedades como `BS` `L``M`,`NS`,, y`SS`, si `Count` es mayor que cero, el atributo es del tipo de non-zero-value datos correspondiente. Si todas las data-type-specific propiedades del atributo son cero `null` o son `Count` iguales a cero, el atributo corresponde al tipo de `BOOL` datos.

## Crear o reemplazar un elemento utilizando expresiones
<a name="dynamodb-expressions-put-item"></a>

En el siguiente ejemplo se muestra el método `Amazon.DynamoDBv2.AmazonDynamoDBClient.PutItem` y un conjunto de expresiones para actualizar el elemento que tenga un `Title` `18-Bicycle 301`. Si el elemento no existe todavía, se añade uno nuevo.

```
// using Amazon.DynamoDBv2;
// using Amazon.DynamoDBv2.Model;

var client = new AmazonDynamoDBClient();
var request = new PutItemRequest
{
  TableName = "ProductCatalog",
  ExpressionAttributeNames = new Dictionary<string, string>
  {
    { "#title", "Title" }
  },
  ExpressionAttributeValues = new Dictionary<string, AttributeValue>
  {
    { ":product", new AttributeValue { S = "18-Bicycle 301" } }
  },
  ConditionExpression = "#title = :product", 
  // CreateItemData() is a custom function.
  Item = CreateItemData()
};
client.PutItem(request);
```

En el ejemplo anterior, la propiedad `ExpressionAttributeNames` especifica el marcador de posición `#title` para que represente el atributo `Title`. La propiedad `ExpressionAttributeValues` especifica el marcador de posición `:product` para que represente el valor `18-Bicycle 301`. La propiedad `ConditionExpression` especifica que `#title` (`Title`) debe ser igual que `:product` (`18-Bicycle 301`). La llamada a `CreateItemData` hace referencia a la siguiente función personalizada:

```
// using Amazon.DynamoDBv2.Model;

// Provides a sample item that can be added to a table.
public static Dictionary<string, AttributeValue> CreateItemData()
{
  var itemData = new Dictionary<string, AttributeValue>
  {
    { "Id", new AttributeValue { N = "301" } },
    { "Title", new AttributeValue { S = "18\" Girl's Bike" } },
    { "BicycleType", new AttributeValue { S = "Road" } },
    { "Brand" , new AttributeValue { S = "Brand-Company C" } },
    { "Color", new AttributeValue { SS = new List<string>{ "Blue", "Silver" } } },
    { "Description", new AttributeValue { S = "301 description" } },
    { "Gender", new AttributeValue { S = "F" } },
    { "InStock", new AttributeValue { BOOL = true } },
    { "Pictures", new AttributeValue { L = new List<AttributeValue>{ 
      { new AttributeValue { M = new Dictionary<string,AttributeValue>{
        { "FrontView", new AttributeValue { S = "http://example/products/301_front.jpg" } } } } },
      { new AttributeValue { M = new Dictionary<string,AttributeValue>{
        { "RearView", new AttributeValue {S = "http://example/products/301_rear.jpg" } } } } },
      { new AttributeValue { M = new Dictionary<string,AttributeValue>{
        { "SideView", new AttributeValue { S = "http://example/products/301_left_side.jpg" } } } } }
    } } },
    { "Price", new AttributeValue { N = "185" } },
    { "ProductCategory", new AttributeValue { S = "Bike" } },
    { "ProductReviews", new AttributeValue { M = new Dictionary<string,AttributeValue>{
      { "FiveStar", new AttributeValue { SS = new List<string>{
        "My daughter really enjoyed this bike!" } } },
      { "OneStar", new AttributeValue { SS = new List<string>{
        "Fun to ride.",
        "This bike was okay, but I would have preferred it in my color." } } }
    } } },
    { "QuantityOnHand", new AttributeValue { N = "3" } },
    { "RelatedItems", new AttributeValue { NS = new List<string>{ "979", "822", "801" } } }
  };

  return itemData;
}
```

En el ejemplo anterior, se devuelve un elemento de ejemplo con datos de muestra al intermediario. Se crean una serie de atributos y valores correspondientes utilizando tipos de datos como `BOOL`, `L`, `M`, `N`, `NS`, `S` y `SS`, que equivalen a los del [formato de datos JSON](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DataFormat.html).

## Actualizar un elemento utilizando expresiones
<a name="dynamodb-expressions-update-item"></a>

El siguiente ejemplo muestra el método `Amazon.DynamoDBv2.AmazonDynamoDBClient.UpdateItem` y un conjunto de expresiones para cambiar el `Title` a `18" Girl's Bike` para el elemento con un `Id` `301`.

```
// using Amazon.DynamoDBv2;
// using Amazon.DynamoDBv2.Model;

var client = new AmazonDynamoDBClient();
var request = new UpdateItemRequest
{
  TableName = "ProductCatalog",
  Key = new Dictionary<string,AttributeValue>
  {
     { "Id", new AttributeValue { N = "301" } }
  },
  ExpressionAttributeNames = new Dictionary<string, string>
  {
    { "#title", "Title" }
  },
  ExpressionAttributeValues = new Dictionary<string, AttributeValue>
  {
    { ":newproduct", new AttributeValue { S = "18\" Girl's Bike" } }
  },
  UpdateExpression = "SET #title = :newproduct"
};
client.UpdateItem(request);
```

En el ejemplo anterior, la propiedad `ExpressionAttributeNames` especifica el marcador de posición `#title` para que represente el atributo `Title`. La propiedad `ExpressionAttributeValues` especifica el marcador de posición `:newproduct` para que represente el valor `18" Girl's Bike`. La propiedad `UpdateExpression` especifica que se cambie `#title` (`Title`) por `:newproduct` (`18" Girl's Bike`).

## Eliminación de un elemento utilizando expresiones
<a name="dynamodb-expressions-delete-item"></a>

El siguiente ejemplo muestra el método `Amazon.DynamoDBv2.AmazonDynamoDBClient.DeleteItem` y un conjunto de expresiones para eliminar el elemento con un `Id` `301` pero solo si el `Title` del elemento es `18-Bicycle 301`.

```
// using Amazon.DynamoDBv2;
// using Amazon.DynamoDBv2.Model;

var client = new AmazonDynamoDBClient();
var request = new DeleteItemRequest
{
  TableName = "ProductCatalog",
  Key = new Dictionary<string,AttributeValue>
  {
     { "Id", new AttributeValue { N = "301" } }
  },
  ExpressionAttributeNames = new Dictionary<string, string>
  {
    { "#title", "Title" }
  },
  ExpressionAttributeValues = new Dictionary<string, AttributeValue>
  {
    { ":product", new AttributeValue { S = "18-Bicycle 301" } }
  },
  ConditionExpression = "#title = :product"
};
client.DeleteItem(request);
```

En el ejemplo anterior, la propiedad `ExpressionAttributeNames` especifica el marcador de posición `#title` para que represente el atributo `Title`. La propiedad `ExpressionAttributeValues` especifica el marcador de posición `:product` para que represente el valor `18-Bicycle 301`. La propiedad `ConditionExpression` especifica que `#title` (`Title`) debe ser igual que `:product` (`18-Bicycle 301`).

## Más información
<a name="dynamodb-expressions-resources"></a>

Para obtener más información y ejemplos de código, consulte:
+  [Serie de DynamoDB: expresiones](http://blogs.aws.amazon.com/net/post/TxZQM7VA9AUZ9L/DynamoDB-Series-Expressions) 
+  [Acceso a atributos de elemento con expresiones de proyección](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.AccessingItemAttributes.html) 
+  [Uso de marcadores de posición para nombres y valores de atributo](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ExpressionPlaceholders.html) 
+  [Especificación de condiciones con expresiones de condición](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.SpecifyingConditions.html) 
+  [Modificación de elementos y atributos con expresiones de actualización](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.Modifying.html) 
+  [Trabajar con elementos mediante la API AWS SDK para .NET de bajo nivel](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/LowLevelDotNetItemCRUD.html) 
+  [Consulta de tablas mediante la API de bajo nivel AWS SDK para .NET](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/LowLevelDotNetQuerying.html) 
+  [Escaneo de tablas mediante la API de bajo nivel AWS SDK para .NET](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/LowLevelDotNetScanning.html) 
+  [Trabajar con índices secundarios locales mediante la API de bajo nivel AWS SDK para .NET](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/LSILowLevelDotNet.html) 
+  [Trabajar con índices secundarios globales mediante la API de bajo nivel AWS SDK para .NET](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GSILowLevelDotNet.html) 

# Compatibilidad con JSON en Amazon DynamoDB
<a name="dynamodb-json"></a>

**nota**  
La información de este tema es específica de los proyectos basados en .NET Framework y en la AWS SDK para .NET versión 3.3 y anteriores.

 AWS SDK para .NET Admite datos JSON cuando se trabaja con Amazon DynamoDB. Esto permite obtener datos con formato JSON de forma más sencilla a partir de tablas de DynamoDB e insertar documentos JSON en ellas.

**Topics**
+ [

## Obtención de datos de una tabla de DynamoDB en formato JSON
](#dynamodb-json-get-table-data)
+ [

## Inserción de datos con formato JSON en una tabla de DynamoDB
](#dynamodb-json-insert-table-data)
+ [

## Conversiones de tipos de datos de DynamoDB en JSON
](#dynamodb-json-datatypes)
+ [

## Más información
](#dynamodb-json-more-info)

## Obtención de datos de una tabla de DynamoDB en formato JSON
<a name="dynamodb-json-get-table-data"></a>

En el siguiente ejemplo se muestra cómo obtener datos de una tabla de DynamoDB en formato JSON:

```
// using Amazon.DynamoDBv2;
// using Amazon.DynamoDBv2.DocumentModel;

var client = new AmazonDynamoDBClient();
var table = Table.LoadTable(client, "AnimalsInventory");
var item = table.GetItem(3, "Horse");

var jsonText = item.ToJson();
Console.Write(jsonText);
      
// Output:
//   {"Name":"Shadow","Type":"Horse","Id":3}

var jsonPrettyText = item.ToJsonPretty();
Console.WriteLine(jsonPrettyText);
      
// Output:
//   {
//     "Name" : "Shadow",
//     "Type" : "Horse",
//     "Id"   : 3
//   }
```

En el ejemplo anterior, el método `ToJson` de la clase `Document` convierte un elemento de la tabla en una cadena con formato JSON. El elemento se recupera a través del método `GetItem` de la clase `Table`. Para determinar el elemento que se va a obtener, en este ejemplo, el `GetItem` método utiliza la clave hash-and-range principal del elemento de destino. Para determinar la tabla de la que se va a obtener el elemento, el método `LoadTable` de la clase `Table` usa una instancia de la clase `AmazonDynamoDBClient` y el nombre de la tabla de destino en DynamoDB.

## Inserción de datos con formato JSON en una tabla de DynamoDB
<a name="dynamodb-json-insert-table-data"></a>

En el siguiente ejemplo se muestra cómo usar formato JSON para insertar un elemento en una tabla de DynamoDB:

```
// using Amazon.DynamoDBv2;
// using Amazon.DynamoDBv2.DocumentModel;

var client = new AmazonDynamoDBClient();
var table = Table.LoadTable(client, "AnimalsInventory");
var jsonText = "{\"Id\":6,\"Type\":\"Bird\",\"Name\":\"Tweety\"}";
var item = Document.FromJson(jsonText);

table.PutItem(item);
```

En el ejemplo anterior, el método `FromJson` de la clase `Document` convierte una cadena con formato JSON en un elemento. El elemento se inserta en la tabla a través del método `PutItem` de la clase `Table`, que usa la instancia de la clase `Document` que contiene el elemento. Para determinar la tabla en la que se va a insertar el elemento, se llama al método `LoadTable` de la clase `Table`, especificando una instancia de la clase `AmazonDynamoDBClient` y el nombre de la tabla de destino en DynamoDB.

## Conversiones de tipos de datos de DynamoDB en JSON
<a name="dynamodb-json-datatypes"></a>

Si llama al método `ToJson` de la clase `Document` y, después, en los datos JSON resultantes, llama al método `FromJson` para convertir de nuevo los datos JSON en una instancia de una clase `Document`, algunos tipos de datos de DynamoDB no se convertirán del modo esperado. En concreto:
+ Los conjuntos de DynamoDB (los tipos `SS`, `NS` y `BS`) se convertirán en matrices JSON.
+ Los conjuntos y escalares binarios de DynamoDB (los tipos `B` y `BS`) se convertirán en cadenas o listas de cadenas JSON codificadas en base64.

  En este escenario, debe llamar al método `DecodeBase64Attributes` de la clase `Document` para reemplazar los datos JSON codificados en base64 con la representación binaria correcta. En el siguiente ejemplo se reemplaza un atributo de elemento escalar binario codificado en base64 en una instancia de una clase `Document`, denominada `Picture`, con la representación binaria correcta. En este ejemplo también se hace lo mismo para un atributo de elemento del conjunto binario codificado en base64 en la misma instancia de la clase `Document`, denominada `RelatedPictures`:

  ```
  item.DecodeBase64Attributes("Picture", "RelatedPictures");
  ```

## Más información
<a name="dynamodb-json-more-info"></a>

Para obtener más información y ejemplos de programación de JSON con DynamoDB con AWS SDK para .NET, consulte:
+  [Compatibilidad de JSON de DynamoDB](https://aws.amazon.com/blogs/developer/dynamodb-json-support/) 
+  [Actualización de Amazon DynamoDB: JSON, capa gratuita ampliada, escalado flexible y elementos más grandes](https://aws.amazon.com/blogs/aws/dynamodb-update-json-and-more/) 

# Uso de Amazon EC2
<a name="ec2-apis-intro"></a>

 AWS SDK para .NET Es compatible con [Amazon EC2](https://docs.aws.amazon.com/ec2/), que es un servicio web que proporciona una capacidad informática de tamaño variable. Esta capacidad informática sirve para crear y alojar sus sistemas de software.

## APIs
<a name="w2aac19c15c17b5"></a>

 AWS SDK para .NET Proporciona API para los clientes de Amazon EC2. Estas API permiten trabajar con características de EC2, como grupos de seguridad y pares de claves. También permiten controlar instancias de Amazon EC2. Esta sección contiene una pequeña cantidad de ejemplos que muestran los patrones que puede seguir al trabajar con ellos APIs. Para ver el conjunto completo de ellos APIs, consulta la [referencia de la AWS SDK para .NET API](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/) (y desplázate hasta «Amazon.ec2").

Los Amazon EC2 APIs se proporcionan en el paquete [AWSSDK NuGet .EC2](https://www.nuget.org/packages/AWSSDK.EC2).

## Requisitos previos
<a name="w2aac19c15c17b7"></a>

Antes de comenzar, asegúrese de que ha [configurado el entorno y el proyecto](net-dg-config.md). Revise también la información en [Características de SDK](net-dg-sdk-features.md).

## Acerca de los ejemplos
<a name="ec2-apis-intro-about"></a>

En los ejemplos de esta sección se muestra cómo usar clientes de Amazon EC2 y cómo administrar instancias de Amazon EC2.

En el [tutorial de instancias de spot de EC2](how-to-spot-instances.md) se muestra cómo solicitar instancias de spot de Amazon EC2. Las instancias de spot permiten acceder a la capacidad de EC2 sin utilizar por un precio inferior al precio bajo demanda.

**Topics**
+ [

## APIs
](#w2aac19c15c17b5)
+ [

## Requisitos previos
](#w2aac19c15c17b7)
+ [

## Acerca de los ejemplos
](#ec2-apis-intro-about)
+ [Grupos de seguridad](security-groups.md)
+ [Pares de claves](key-pairs.md)
+ [Regiones y zonas de disponibilidad](using-regions-and-availability-zones.md)
+ [instancias de EC2](how-to-ec2.md)
+ [Tutorial de instancias de spot](how-to-spot-instances.md)

# Uso de grupos de seguridad en Amazon EC2
<a name="security-groups"></a>

En Amazon EC2, un *grupo de seguridad* funciona como un firewall virtual que controla el tráfico de red de una o varias instancias EC2. De forma predeterminada, EC2 asocia las instancias con un grupo de seguridad que no permite el tráfico entrante. Puede crear un grupo de seguridad que permita a sus instancias EC2 aceptar un tráfico determinado. Por ejemplo, si necesita conectarse a una instancia EC2 Windows, debe configurar el grupo de seguridad para permitir el tráfico RDP.

Para obtener más información sobre los grupos de seguridad, consulte [Grupos de seguridad de Amazon EC2](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-security-groups.html) en la [Guía del usuario de Amazon EC2](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/).

**aviso**  
EC2-Classic se retirará el 15 de agosto de 2022. Le recomendamos que migre de EC2-Classic a una VPC. Para obtener más información, consulte la entrada del blog [EC2-Classic Networking is Retiring – Here's How to Prepare](https://aws.amazon.com/blogs/aws/ec2-classic-is-retiring-heres-how-to-prepare/).

Para obtener información sobre los requisitos APIs y requisitos previos, consulte la sección principal ([Uso de Amazon EC2](ec2-apis-intro.md)).

**Topics**
+ [

# Enumeración de grupos de seguridad
](enumerate-security-groups.md)
+ [

# Creación de grupos de seguridad
](creating-security-group.md)
+ [

# Actualización de grupos de seguridad
](authorize-ingress.md)

# Enumeración de grupos de seguridad
<a name="enumerate-security-groups"></a>

En este ejemplo, se muestra cómo utilizar el para AWS SDK para .NET enumerar los grupos de seguridad. Si proporciona un ID de [Amazon Virtual Private Cloud](https://docs.aws.amazon.com/vpc/latest/userguide/), la aplicación enumera los grupos de seguridad de esa VPC concreta. De lo contrario, la aplicación simplemente muestra una lista de todos los grupos de seguridad disponibles.

En las siguientes secciones se proporcionan fragmentos de código de este ejemplo. Tras ello, se muestra el [código completo del ejemplo](#enum-sec-groups-complete-code), que se puede compilar y ejecutar tal cual.

**Topics**
+ [

## Enumeración de grupos de seguridad
](#enum-sec-groups-enum)
+ [

## Código completo
](#enum-sec-groups-complete-code)
+ [

## Consideraciones adicionales
](#enum-sec-groups-additional)

## Enumeración de grupos de seguridad
<a name="enum-sec-groups-enum"></a>

El siguiente fragmento de código enumera los grupos de seguridad. Enumera todos los grupos, o bien los grupos de una VPC concreta, si se indica alguna.

El ejemplo que aparece [al final de este tema](#enum-sec-groups-complete-code) muestra este fragmento de código en uso.

```
    //
    // Method to enumerate the security groups
    private static async Task EnumerateGroups(IAmazonEC2 ec2Client, string vpcID)
    {
      // A request object, in case we need it.
      var request = new DescribeSecurityGroupsRequest();

      // Put together the properties, if needed
      if(!string.IsNullOrEmpty(vpcID))
      {
        // We have a VPC ID. Find the security groups for just that VPC.
        Console.WriteLine($"\nGetting security groups for VPC {vpcID}...\n");
        request.Filters.Add(new Filter
        {
          Name = "vpc-id",
          Values = new List<string>() { vpcID }
        });
      }

      // Get the list of security groups
      DescribeSecurityGroupsResponse response =
        await ec2Client.DescribeSecurityGroupsAsync(request);

      // Display the list of security groups.
      foreach (SecurityGroup item in response.SecurityGroups)
      {
        Console.WriteLine("Security group: " + item.GroupId);
        Console.WriteLine("\tGroupId: " + item.GroupId);
        Console.WriteLine("\tGroupName: " + item.GroupName);
        Console.WriteLine("\tVpcId: " + item.VpcId);
        Console.WriteLine();
      }
    }
```

## Código completo
<a name="enum-sec-groups-complete-code"></a>

En esta sección se muestran las referencias relevantes y el código completo de este ejemplo.

### Referencias de SDK
<a name="w2aac19c15c17c13c13c15b5b1"></a>

NuGet paquetes:
+ [AWSSDK.EC2](https://www.nuget.org/packages/AWSSDK.EC2)

Elementos de programación:
+ Espacio de nombres [Amazon.EC2](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/NEC2.html)

  [EC2Cliente Class Amazon](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TEC2Client.html)
+ Espacio de nombres [Amazon.EC2.Model](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/NEC2Model.html)

  Clase [DescribeSecurityGroupsRequest](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TDescribeSecurityGroupsRequest.html)

  Clase [DescribeSecurityGroupsResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TDescribeSecurityGroupsResponse.html)

  Clase [Filter](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TFilter.html)

  Clase [SecurityGroup](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TSecurityGroup.html)

### El código
<a name="w2aac19c15c17c13c13c15b7b1"></a>

```
using System;
using System.Threading.Tasks;
using System.Collections.Generic;
using Amazon.EC2;
using Amazon.EC2.Model;

namespace EC2EnumerateSecGroups
{
  class Program
  {
    static async Task Main(string[] args)
    {
      // Parse the command line
       string vpcID = string.Empty;
      if(args.Length == 0)
      {
        Console.WriteLine("\nEC2EnumerateSecGroups [vpc_id]");
        Console.WriteLine("  vpc_id - The ID of the VPC for which you want to see security groups.");
        Console.WriteLine("\nSince you specified no arguments, showing all available security groups.");
      }
      else
      {
        vpcID = args[0];
      }

      if(vpcID.StartsWith("vpc-") || string.IsNullOrEmpty(vpcID))
      {
        // Create an EC2 client object
        var ec2Client = new AmazonEC2Client();

        // Enumerate the security groups
        await EnumerateGroups(ec2Client, vpcID);
      }
      else
      {
        Console.WriteLine("Could not find a valid VPC ID in the command-line arguments:");
        Console.WriteLine($"{args[0]}");
      }
    }


    //
    // Method to enumerate the security groups
    private static async Task EnumerateGroups(IAmazonEC2 ec2Client, string vpcID)
    {
      // A request object, in case we need it.
      var request = new DescribeSecurityGroupsRequest();

      // Put together the properties, if needed
      if(!string.IsNullOrEmpty(vpcID))
      {
        // We have a VPC ID. Find the security groups for just that VPC.
        Console.WriteLine($"\nGetting security groups for VPC {vpcID}...\n");
        request.Filters.Add(new Filter
        {
          Name = "vpc-id",
          Values = new List<string>() { vpcID }
        });
      }

      // Get the list of security groups
      DescribeSecurityGroupsResponse response =
        await ec2Client.DescribeSecurityGroupsAsync(request);

      // Display the list of security groups.
      foreach (SecurityGroup item in response.SecurityGroups)
      {
        Console.WriteLine("Security group: " + item.GroupId);
        Console.WriteLine("\tGroupId: " + item.GroupId);
        Console.WriteLine("\tGroupName: " + item.GroupName);
        Console.WriteLine("\tVpcId: " + item.VpcId);
        Console.WriteLine();
      }
    }
  }
}
```

## Consideraciones adicionales
<a name="enum-sec-groups-additional"></a>
+ Observe que, en el caso de la VPC, el filtro se crea con la parte `Name` del par nombre-valor establecida en “vpc-id”. Este nombre proviene de la descripción de la `Filters` propiedad de la [DescribeSecurityGroupsRequest](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TDescribeSecurityGroupsRequest.html)clase.
+ Para obtener la lista completa de sus grupos de seguridad, también puede [ DescribeSecurityGroupsAsync utilizarlos sin parámetros](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/MEC2DescribeSecurityGroupsAsyncCancellationToken.html).
+ Para comprobar los resultados, puede consultar la lista de grupos de seguridad en la [consola de Amazon EC2](https://console.aws.amazon.com/ec2/v2/home#SecurityGroups).

# Creación de grupos de seguridad
<a name="creating-security-group"></a>

En este ejemplo, se muestra cómo utilizar el AWS SDK para .NET para crear un grupo de seguridad. Puede proporcionar el ID de una VPC existente para crear un grupo de seguridad para EC2 en una VPC. Si no proporciona ese identificador, el nuevo grupo de seguridad será para EC2-Classic si su AWS cuenta lo admite.

Si no proporciona un ID de VPC y su AWS cuenta no es compatible con EC2-Classic, el nuevo grupo de seguridad pertenecerá a la VPC predeterminada de su cuenta.

**aviso**  
EC2-Classic se retirará el 15 de agosto de 2022. Le recomendamos que migre de EC2-Classic a una VPC. Para obtener más información, consulte la entrada del blog [EC2-Classic Networking se retira: cómo prepararse](https://aws.amazon.com/blogs/aws/ec2-classic-is-retiring-heres-how-to-prepare/).

En las siguientes secciones se proporcionan fragmentos de código de este ejemplo. Tras ello, se muestra el [código completo del ejemplo](#create-sec-groups-complete-code), que se puede compilar y ejecutar tal cual.

**Topics**
+ [

## Búsqueda de grupos de seguridad existentes
](#create-sec-groups-find)
+ [

## Creación de un grupo de seguridad
](#create-sec-groups-enum)
+ [

## Código completo
](#create-sec-groups-complete-code)

## Búsqueda de grupos de seguridad existentes
<a name="create-sec-groups-find"></a>

El siguiente fragmento de código busca los grupos de seguridad existentes en la VPC indicada con el nombre especificado.

El ejemplo que aparece [al final de este tema](#create-sec-groups-complete-code) muestra este fragmento de código en uso.

```
    //
    // Method to determine if a security group with the specified name
    // already exists in the VPC
    private static async Task<List<SecurityGroup>> FindSecurityGroups(
      IAmazonEC2 ec2Client, string groupName, string vpcID)
    {
      var request = new DescribeSecurityGroupsRequest();
      request.Filters.Add(new Filter{
        Name = "group-name",
        Values = new List<string>() { groupName }
      });
      if(!string.IsNullOrEmpty(vpcID))
        request.Filters.Add(new Filter{
          Name = "vpc-id",
          Values = new List<string>() { vpcID }
        });

      var response = await ec2Client.DescribeSecurityGroupsAsync(request);
      return response.SecurityGroups;
    }
```

## Creación de un grupo de seguridad
<a name="create-sec-groups-enum"></a>

El siguiente fragmento de código crea un grupo de seguridad nuevo si no existe uno con ese nombre en la VPC indicada. Si no se proporciona ninguna VPC y hay uno o más grupos con ese nombre, el fragmento de código simplemente devuelve la lista de grupos.

El ejemplo que aparece [al final de este tema](#create-sec-groups-complete-code) muestra este fragmento de código en uso.

```
    //
    // Method to create a new security group (either EC2-Classic or EC2-VPC)
    // If vpcID is empty, the security group will be for EC2-Classic
    private static async Task<List<SecurityGroup>> CreateSecurityGroup(
      IAmazonEC2 ec2Client, string groupName, string vpcID)
    {
      // See if one or more security groups with that name
      // already exist in the given VPC. If so, return the list of them.
      var securityGroups = await FindSecurityGroups(ec2Client, groupName, vpcID);
      if (securityGroups.Count > 0)
      {
        Console.WriteLine(
          $"\nOne or more security groups with name {groupName} already exist.\n");
        return securityGroups;
      }

      // If the security group doesn't already exists, create it.
      var createRequest = new CreateSecurityGroupRequest{
        GroupName = groupName
      };
      if(string.IsNullOrEmpty(vpcID))
      {
        createRequest.Description = "My .NET example security group for EC2-Classic";
      }
      else
      {
        createRequest.VpcId = vpcID;
        createRequest.Description = "My .NET example security group for EC2-VPC";
      }
      CreateSecurityGroupResponse createResponse =
        await ec2Client.CreateSecurityGroupAsync(createRequest);

      // Return the new security group
      DescribeSecurityGroupsResponse describeResponse =
        await ec2Client.DescribeSecurityGroupsAsync(new DescribeSecurityGroupsRequest{
          GroupIds = new List<string>() { createResponse.GroupId }
        });
      return describeResponse.SecurityGroups;
    }
```

## Código completo
<a name="create-sec-groups-complete-code"></a>

En esta sección se muestran las referencias relevantes y el código completo de este ejemplo.

### Referencias de SDK
<a name="w2aac19c15c17c13c15c23b5b1"></a>

NuGet paquetes:
+ [AWSSDK.EC2](https://www.nuget.org/packages/AWSSDK.EC2)

Elementos de programación:
+ Espacio de nombres [Amazon.EC2](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/NEC2.html)

  [EC2Cliente Class Amazon](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TEC2Client.html)
+ Espacio de nombres [Amazon.EC2.Model](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/NEC2Model.html)

  Clase [CreateSecurityGroupRequest](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TCreateSecurityGroupRequest.html)

  Clase [CreateSecurityGroupResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TCreateSecurityGroupResponse.html)

  Clase [DescribeSecurityGroupsRequest](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TDescribeSecurityGroupsRequest.html)

  Clase [DescribeSecurityGroupsResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TDescribeSecurityGroupsResponse.html)

  Clase [Filter](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TFilter.html)

  Clase [SecurityGroup](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TSecurityGroup.html)

### El código
<a name="w2aac19c15c17c13c15c23b7b1"></a>

```
using System;
using System.Threading.Tasks;
using System.Collections.Generic;
using Amazon.EC2;
using Amazon.EC2.Model;

namespace EC2CreateSecGroup
{
  // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  // Class to create a security group
  class Program
  {
    private const int MaxArgs = 2;

    static async Task Main(string[] args)
    {
      // Parse the command line and show help if necessary
      var parsedArgs = CommandLine.Parse(args);
      if(parsedArgs.Count == 0)
      {
        PrintHelp();
        return;
      }
      if(parsedArgs.Count > MaxArgs)
        CommandLine.ErrorExit("\nThe number of command-line arguments is incorrect." +
          "\nRun the command with no arguments to see help.");

      // Get the application arguments from the parsed list
      var groupName = CommandLine.GetArgument(parsedArgs, null, "-g", "--group-name");
      var vpcID = CommandLine.GetArgument(parsedArgs, null, "-v", "--vpc-id");
      if(string.IsNullOrEmpty(groupName))
        CommandLine.ErrorExit("\nYou must supply a name for the new group." +
          "\nRun the command with no arguments to see help.");
      if(!string.IsNullOrEmpty(vpcID) && !vpcID.StartsWith("vpc-"))
        CommandLine.ErrorExit($"\nNot a valid VPC ID: {vpcID}");

      // groupName has a value and vpcID either has a value or is null (which is fine)
      // Create the new security group and display information about it
      var securityGroups =
        await CreateSecurityGroup(new AmazonEC2Client(), groupName, vpcID);
      Console.WriteLine("Information about the security group(s):");
      foreach(var group in securityGroups)
      {
        Console.WriteLine($"\nGroupName: {group.GroupName}");
        Console.WriteLine($"GroupId: {group.GroupId}");
        Console.WriteLine($"Description: {group.Description}");
        Console.WriteLine($"VpcId (if any): {group.VpcId}");
      }
    }


    //
    // Method to create a new security group (either EC2-Classic or EC2-VPC)
    // If vpcID is empty, the security group will be for EC2-Classic
    private static async Task<List<SecurityGroup>> CreateSecurityGroup(
      IAmazonEC2 ec2Client, string groupName, string vpcID)
    {
      // See if one or more security groups with that name
      // already exist in the given VPC. If so, return the list of them.
      var securityGroups = await FindSecurityGroups(ec2Client, groupName, vpcID);
      if (securityGroups.Count > 0)
      {
        Console.WriteLine(
          $"\nOne or more security groups with name {groupName} already exist.\n");
        return securityGroups;
      }

      // If the security group doesn't already exists, create it.
      var createRequest = new CreateSecurityGroupRequest{
        GroupName = groupName
      };
      if(string.IsNullOrEmpty(vpcID))
      {
        createRequest.Description = "Security group for .NET code example (no VPC specified)";
      }
      else
      {
        createRequest.VpcId = vpcID;
        createRequest.Description = "Security group for .NET code example (VPC: " + vpcID + ")";
      }
      CreateSecurityGroupResponse createResponse =
        await ec2Client.CreateSecurityGroupAsync(createRequest);

      // Return the new security group
      DescribeSecurityGroupsResponse describeResponse =
        await ec2Client.DescribeSecurityGroupsAsync(new DescribeSecurityGroupsRequest{
          GroupIds = new List<string>() { createResponse.GroupId }
        });
      return describeResponse.SecurityGroups;
    }


    //
    // Method to determine if a security group with the specified name
    // already exists in the VPC
    private static async Task<List<SecurityGroup>> FindSecurityGroups(
      IAmazonEC2 ec2Client, string groupName, string vpcID)
    {
      var request = new DescribeSecurityGroupsRequest();
      request.Filters.Add(new Filter{
        Name = "group-name",
        Values = new List<string>() { groupName }
      });
      if(!string.IsNullOrEmpty(vpcID))
        request.Filters.Add(new Filter{
          Name = "vpc-id",
          Values = new List<string>() { vpcID }
        });

      var response = await ec2Client.DescribeSecurityGroupsAsync(request);
      return response.SecurityGroups;
    }


    //
    // Command-line help
    private static void PrintHelp()
    {
      Console.WriteLine(
        "\nUsage: EC2CreateSecGroup -g <group-name> [-v <vpc-id>]" +
        "\n  -g, --group-name: The name you would like the new security group to have." +
        "\n  -v, --vpc-id: The ID of a VPC to which the new security group will belong." +
        "\n     If vpc-id isn't present, the security group will be" +
        "\n     for EC2-Classic (if your AWS account supports this)" +
        "\n     or will use the default VCP for EC2-VPC.");
    }
  }


  // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  // Class that represents a command line on the console or terminal.
  // (This is the same for all examples. When you have seen it once, you can ignore it.)
  static class CommandLine
  {
    //
    // Method to parse a command line of the form: "--key value" or "-k value".
    //
    // Parameters:
    // - args: The command-line arguments passed into the application by the system.
    //
    // Returns:
    // A Dictionary with string Keys and Values.
    //
    // If a key is found without a matching value, Dictionary.Value is set to the key
    //  (including the dashes).
    // If a value is found without a matching key, Dictionary.Key is set to "--NoKeyN",
    //  where "N" represents sequential numbers.
    public static Dictionary<string,string> Parse(string[] args)
    {
      var parsedArgs = new Dictionary<string,string>();
      int i = 0, n = 0;
      while(i < args.Length)
      {
        // If the first argument in this iteration starts with a dash it's an option.
        if(args[i].StartsWith("-"))
        {
          var key = args[i++];
          var value = key;

          // Check to see if there's a value that goes with this option?
          if((i < args.Length) && (!args[i].StartsWith("-"))) value = args[i++];
          parsedArgs.Add(key, value);
        }

        // If the first argument in this iteration doesn't start with a dash, it's a value
        else
        {
          parsedArgs.Add("--NoKey" + n.ToString(), args[i++]);
          n++;
        }
      }

      return parsedArgs;
    }

    //
    // Method to get an argument from the parsed command-line arguments
    //
    // Parameters:
    // - parsedArgs: The Dictionary object returned from the Parse() method (shown above).
    // - defaultValue: The default string to return if the specified key isn't in parsedArgs.
    // - keys: An array of keys to look for in parsedArgs.
    public static string GetArgument(
      Dictionary<string,string> parsedArgs, string defaultReturn, params string[] keys)
    {
      string retval = null;
      foreach(var key in keys)
        if(parsedArgs.TryGetValue(key, out retval)) break;
      return retval ?? defaultReturn;
    }

    //
    // Method to exit the application with an error.
    public static void ErrorExit(string msg, int code=1)
    {
      Console.WriteLine("\nError");
      Console.WriteLine(msg);
      Environment.Exit(code);
    }
  }

}
```

# Actualización de grupos de seguridad
<a name="authorize-ingress"></a>

En este ejemplo, se muestra cómo utilizar la AWS SDK para .NET para añadir una regla a un grupo de seguridad. En concreto, el ejemplo agrega una regla para permitir el tráfico entrante en un determinado puerto TCP, que se puede usar, por ejemplo, en las conexiones remotas a una instancia de EC2. La aplicación toma el ID de un grupo de seguridad existente, una dirección IP (o un intervalo de direcciones) en formato CIDR y, opcionalmente, un número de puerto TCP. A continuación, agrega una regla de entrada al grupo de seguridad en cuestión.

**nota**  
Para usar este ejemplo, necesita una dirección IP (o un intervalo de direcciones) en formato CIDR. Consulte la sección **Consideraciones adicionales** al final de este tema para conocer los métodos con los que obtener la dirección IP del equipo local.

En las siguientes secciones se proporcionan fragmentos de código de este ejemplo. Tras ello, se muestra el [código completo del ejemplo](#authorize-ingress-complete-code), que se puede compilar y ejecutar tal cual.

**Topics**
+ [

## Adición de una regla de entrada
](#authorize-ingress-add-rule)
+ [

## Código completo
](#authorize-ingress-complete-code)
+ [

## Consideraciones adicionales
](#authorize-ingress-additional)

## Adición de una regla de entrada
<a name="authorize-ingress-add-rule"></a>

El siguiente fragmento de código agrega una regla de entrada a un grupo de seguridad para una dirección IP (o intervalo de direcciones) y un puerto TCP determinados.

El ejemplo que aparece [al final de este tema](#authorize-ingress-complete-code) muestra este fragmento de código en uso.

```
    //
    // Method that adds a TCP ingress rule to a security group
    private static async Task AddIngressRule(
      IAmazonEC2 eC2Client, string groupID, string ipAddress, int port)
    {
      // Create an object to hold the request information for the rule.
      // It uses an IpPermission object to hold the IP information for the rule.
      var ingressRequest = new AuthorizeSecurityGroupIngressRequest{
        GroupId = groupID};
      ingressRequest.IpPermissions.Add(new IpPermission{
        IpProtocol = "tcp",
        FromPort = port,
        ToPort = port,
        Ipv4Ranges = new List<IpRange>() { new IpRange { CidrIp = ipAddress } }
      });

      // Create the inbound rule for the security group
      AuthorizeSecurityGroupIngressResponse responseIngress =
        await eC2Client.AuthorizeSecurityGroupIngressAsync(ingressRequest);
      Console.WriteLine($"\nNew RDP rule was written in {groupID} for {ipAddress}.");
      Console.WriteLine($"Result: {responseIngress.HttpStatusCode}");
    }
```

## Código completo
<a name="authorize-ingress-complete-code"></a>

En esta sección se muestran las referencias relevantes y el código completo de este ejemplo.

### Referencias de SDK
<a name="w2aac19c15c17c13c17c17b5b1"></a>

NuGet paquetes:
+ [AWSSDK.EC2](https://www.nuget.org/packages/AWSSDK.EC2)

Elementos de programación:
+ Espacio de nombres [Amazon.EC2](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/NEC2.html)

  [EC2Cliente Class Amazon](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TEC2Client.html)
+ Espacio de nombres [Amazon.EC2.Model](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/NEC2Model.html)

  Clase [AuthorizeSecurityGroupIngressRequest](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TAuthorizeSecurityGroupIngressRequest.html)

  Clase [AuthorizeSecurityGroupIngressResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TAuthorizeSecurityGroupIngressResponse.html)

  Clase [IpPermission](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TIpPermission.html)

  Clase [IpRange](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TIpRange.html)

### El código
<a name="w2aac19c15c17c13c17c17b7b1"></a>

```
using System;
using System.Threading.Tasks;
using System.Collections.Generic;
using Amazon.EC2;
using Amazon.EC2.Model;

namespace EC2AddRuleForRDP
{
  // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  // Class to add a rule that allows inbound traffic on TCP a port
  class Program
  {
    private const int DefaultPort = 3389;

    static async Task Main(string[] args)
    {
      // Parse the command line and show help if necessary
      var parsedArgs = CommandLine.Parse(args);
      if(parsedArgs.Count == 0)
      {
        PrintHelp();
        return;
      }

      // Get the application arguments from the parsed list
      var groupID = CommandLine.GetArgument(parsedArgs, null, "-g", "--group-id");
      var ipAddress = CommandLine.GetArgument(parsedArgs, null, "-i", "--ip-address");
      var portStr = CommandLine.GetArgument(parsedArgs, DefaultPort.ToString(), "-p", "--port");
      if(string.IsNullOrEmpty(ipAddress))
        CommandLine.ErrorExit("\nYou must supply an IP address in CIDR format.");
      if(string.IsNullOrEmpty(groupID) || !groupID.StartsWith("sg-"))
        CommandLine.ErrorExit("\nThe ID for a security group is missing or incorrect.");
      if(int.Parse(portStr) == 0)
        CommandLine.ErrorExit($"\nThe given TCP port number, {portStr}, isn't allowed.");

      // Add a rule to the given security group that allows
      // inbound traffic on a TCP port
      await AddIngressRule(
        new AmazonEC2Client(), groupID, ipAddress, int.Parse(portStr));
    }


    //
    // Method that adds a TCP ingress rule to a security group
    private static async Task AddIngressRule(
      IAmazonEC2 eC2Client, string groupID, string ipAddress, int port)
    {
      // Create an object to hold the request information for the rule.
      // It uses an IpPermission object to hold the IP information for the rule.
      var ingressRequest = new AuthorizeSecurityGroupIngressRequest{
        GroupId = groupID};
      ingressRequest.IpPermissions.Add(new IpPermission{
        IpProtocol = "tcp",
        FromPort = port,
        ToPort = port,
        Ipv4Ranges = new List<IpRange>() { new IpRange { CidrIp = ipAddress } }
      });

      // Create the inbound rule for the security group
      AuthorizeSecurityGroupIngressResponse responseIngress =
        await eC2Client.AuthorizeSecurityGroupIngressAsync(ingressRequest);
      Console.WriteLine($"\nNew RDP rule was written in {groupID} for {ipAddress}.");
      Console.WriteLine($"Result: {responseIngress.HttpStatusCode}");
    }


    //
    // Command-line help
    private static void PrintHelp()
    {
      Console.WriteLine(
        "\nUsage: EC2AddRuleForRDP -g <group-id> -i <ip-address> [-p <port>]" +
        "\n  -g, --group-id: The ID of the security group to which you want to add the inbound rule." +
        "\n  -i, --ip-address: An IP address or address range in CIDR format." +
        "\n  -p, --port: The TCP port number. Defaults to 3389.");
    }
  }


  // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  // Class that represents a command line on the console or terminal.
  // (This is the same for all examples. When you have seen it once, you can ignore it.)
  static class CommandLine
  {
    //
    // Method to parse a command line of the form: "--key value" or "-k value".
    //
    // Parameters:
    // - args: The command-line arguments passed into the application by the system.
    //
    // Returns:
    // A Dictionary with string Keys and Values.
    //
    // If a key is found without a matching value, Dictionary.Value is set to the key
    //  (including the dashes).
    // If a value is found without a matching key, Dictionary.Key is set to "--NoKeyN",
    //  where "N" represents sequential numbers.
    public static Dictionary<string,string> Parse(string[] args)
    {
      var parsedArgs = new Dictionary<string,string>();
      int i = 0, n = 0;
      while(i < args.Length)
      {
        // If the first argument in this iteration starts with a dash it's an option.
        if(args[i].StartsWith("-"))
        {
          var key = args[i++];
          var value = key;

          // Check to see if there's a value that goes with this option?
          if((i < args.Length) && (!args[i].StartsWith("-"))) value = args[i++];
          parsedArgs.Add(key, value);
        }

        // If the first argument in this iteration doesn't start with a dash, it's a value
        else
        {
          parsedArgs.Add("--NoKey" + n.ToString(), args[i++]);
          n++;
        }
      }

      return parsedArgs;
    }

    //
    // Method to get an argument from the parsed command-line arguments
    //
    // Parameters:
    // - parsedArgs: The Dictionary object returned from the Parse() method (shown above).
    // - defaultValue: The default string to return if the specified key isn't in parsedArgs.
    // - keys: An array of keys to look for in parsedArgs.
    public static string GetArgument(
      Dictionary<string,string> parsedArgs, string defaultReturn, params string[] keys)
    {
      string retval = null;
      foreach(var key in keys)
        if(parsedArgs.TryGetValue(key, out retval)) break;
      return retval ?? defaultReturn;
    }

    //
    // Method to exit the application with an error.
    public static void ErrorExit(string msg, int code=1)
    {
      Console.WriteLine("\nError");
      Console.WriteLine(msg);
      Environment.Exit(code);
    }
  }

}
```

## Consideraciones adicionales
<a name="authorize-ingress-additional"></a>
+ Si no se indica un número de puerto, la aplicación lo establece de forma predeterminada en 3389, que es el puerto de Windows RDP, con el que puede conectarse a una instancia de EC2 donde se ejecute Windows. En cambio, si lanza una instancia de EC2 que ejecuta Linux, utilice el puerto TCP 22 (SSH).
+ Observe que, en el ejemplo, `IpProtocol` está establecido en “tcp”. Los valores de `IpProtocol` se encuentran en la descripción de la `IpProtocol` propiedad de la [IpPermission](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TIpPermission.html)clase.
+ Es conveniente que tenga la dirección IP de su equipo local cuando utilice este ejemplo. Estas son algunas formas de obtener la dirección.
  + Si el equipo local (desde el que se conectará a la instancia de EC2) tiene una dirección IP pública estática, puede utilizar un servicio para obtener esa dirección. Uno de estos servicios es [http://checkip.amazonaws.com/](http://checkip.amazonaws.com/). Para obtener más información sobre la autorización del tráfico entrante, consulte [Agregar reglas a un grupo de seguridad](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/working-with-security-groups.html#adding-security-group-rule) y [Reglas de grupos de seguridad para diferentes casos de uso](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/security-group-rules-reference.html) en la [Guía del usuario de Amazon EC2](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/).
  + Otra forma de obtener la dirección IP del equipo local consiste en utilizar la [consola de Amazon EC2](https://console.aws.amazon.com/ec2/v2/home#SecurityGroups).

    Seleccione uno de sus grupos de seguridad, seleccione la pestaña **Reglas de entrada** y, luego, seleccione **Editar reglas de entrada**. En una regla de entrada, abra el menú desplegable de la columna **Origen** y seleccione **Mi IP** para ver la dirección IP de su equipo local en formato CIDR. Asegúrese de **cancelar** la operación.
+ Para comprobar los resultados de este ejemplo, puede examinar la lista de grupos de seguridad en la [consola de Amazon EC2](https://console.aws.amazon.com/ec2/v2/home#SecurityGroups).

# Uso de pares de claves de Amazon EC2
<a name="key-pairs"></a>

Amazon EC2 utiliza la criptografía de clave pública para cifrar y descifrar la información de inicio de sesión. En la criptografía de clave pública se utiliza una clave pública para cifrar datos y, a continuación, el destinatario utiliza la clave privada para descifrar los datos. El conjunto de clave pública y clave privada se denomina par de claves. Si desea iniciar sesión en una instancia de EC2, debe especificar un par de claves al lanzar la instancia y, a continuación, proporcionar la clave privada del par cuando se conecte a ella.

Al lanzar una instancia de EC2, puede crear un par de claves exclusivo para ella o utilizar uno que ya haya utilizado al iniciar otras instancias. Para obtener más información sobre los pares de claves de Amazon EC2, consulte [Uso de pares de claves de Amazon EC2](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-key-pairs.html) en la [Guía del usuario de Amazon EC2](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/).

Para obtener información sobre los requisitos APIs y requisitos previos, consulte la sección principal ([Uso de Amazon EC2](ec2-apis-intro.md)).

**Topics**
+ [

# Creación y visualización de pares de claves
](create-save-key-pair.md)
+ [

# Eliminación de pares de claves
](delete-key-pairs.md)

# Creación y visualización de pares de claves
<a name="create-save-key-pair"></a>

En este ejemplo, se muestra cómo utilizar el AWS SDK para .NET para crear un key pair. La aplicación toma el nombre del nuevo par de claves y el nombre de un archivo PEM (que tiene una extensión “.pem”). Crea el par de claves, escribe la clave privada en el archivo PEM y, a continuación, muestra todos los pares de claves disponibles. Si no proporciona argumentos de línea de comandos, la aplicación simplemente muestra todos los pares de claves disponibles.

En las siguientes secciones se proporcionan fragmentos de código de este ejemplo. Tras ello, se muestra el [código completo del ejemplo](#create-save-key-pair-complete-code), que se puede compilar y ejecutar tal cual.

**Topics**
+ [

## Creación del par de claves
](#create-save-key-pair-create)
+ [

## Visualización de los pares de claves disponibles
](#create-save-key-pair-display)
+ [

## Código completo
](#create-save-key-pair-complete-code)
+ [

## Consideraciones adicionales
](#create-save-key-pair-additional)

## Creación del par de claves
<a name="create-save-key-pair-create"></a>

El siguiente fragmento de código crea un par de claves y, a continuación, almacena la clave privada del archivo PEM especificado.

El ejemplo que aparece [al final de este tema](#create-save-key-pair-complete-code) muestra este fragmento de código en uso.

```
    //
    // Method to create a key pair and save the key material in a PEM file
    private static async Task CreateKeyPair(
      IAmazonEC2 ec2Client, string keyPairName, string pemFileName)
    {
      // Create the key pair
      CreateKeyPairResponse response =
        await ec2Client.CreateKeyPairAsync(new CreateKeyPairRequest{
          KeyName = keyPairName
        });
      Console.WriteLine($"\nCreated new key pair: {response.KeyPair.KeyName}");

      // Save the private key in a PEM file
      using (var s = new FileStream(pemFileName, FileMode.Create))
      using (var writer = new StreamWriter(s))
      {
        writer.WriteLine(response.KeyPair.KeyMaterial);
      }
    }
```

## Visualización de los pares de claves disponibles
<a name="create-save-key-pair-display"></a>

En el siguiente fragmento de código se muestra una lista de los pares de claves disponibles.

El ejemplo que aparece [al final de este tema](#create-save-key-pair-complete-code) muestra este fragmento de código en uso.

```
    //
    // Method to show the key pairs that are available
    private static async Task EnumerateKeyPairs(IAmazonEC2 ec2Client)
    {
      DescribeKeyPairsResponse response = await ec2Client.DescribeKeyPairsAsync();
      Console.WriteLine("Available key pairs:");
      foreach (KeyPairInfo item in response.KeyPairs)
        Console.WriteLine($"  {item.KeyName}");
    }
```

## Código completo
<a name="create-save-key-pair-complete-code"></a>

En esta sección se muestran las referencias relevantes y el código completo de este ejemplo.

### Referencias de SDK
<a name="w2aac19c15c17c15c11c19b5b1"></a>

NuGet paquetes:
+ [AWSSDK.EC2](https://www.nuget.org/packages/AWSSDK.EC2)

Elementos de programación:
+ Espacio de nombres [Amazon.EC2](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/NEC2.html)

  [EC2Cliente Class Amazon](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TEC2Client.html)
+ Espacio de nombres [Amazon.EC2.Model](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/NEC2Model.html)

  Clase [CreateKeyPairRequest](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TCreateKeyPairRequest.html)

  Clase [CreateKeyPairResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TCreateKeyPairResponse.html)

  Clase [DescribeKeyPairsResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TDescribeKeyPairsResponse.html)

  Clase [KeyPairInfo](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TKeyPairInfo.html)

### El código
<a name="w2aac19c15c17c15c11c19b7b1"></a>

```
using System;
using System.Threading.Tasks;
using System.IO;
using Amazon.EC2;
using Amazon.EC2.Model;
using System.Collections.Generic;

namespace EC2CreateKeyPair
{
  // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  // Class to create and store a key pair
  class Program
  {
    static async Task Main(string[] args)
    {
      // Create the EC2 client
      var ec2Client = new AmazonEC2Client();

      // Parse the command line and show help if necessary
      var parsedArgs = CommandLine.Parse(args);
      if(parsedArgs.Count == 0)
      {
        // In the case of no command-line arguments,
        // just show help and the existing key pairs
        PrintHelp();
        Console.WriteLine("\nNo arguments specified.");
        Console.Write(
          "Do you want to see a list of the existing key pairs? ((y) or n): ");
        string response = Console.ReadLine();
        if((string.IsNullOrEmpty(response)) || (response.ToLower() == "y"))
          await EnumerateKeyPairs(ec2Client);
        return;
      }

      // Get the application arguments from the parsed list
      string keyPairName =
        CommandLine.GetArgument(parsedArgs, null, "-k", "--keypair-name");
      string pemFileName =
        CommandLine.GetArgument(parsedArgs, null, "-p", "--pem-filename");
      if(string.IsNullOrEmpty(keyPairName))
        CommandLine.ErrorExit("\nNo key pair name specified." +
          "\nRun the command with no arguments to see help.");
      if(string.IsNullOrEmpty(pemFileName) || !pemFileName.EndsWith(".pem"))
        CommandLine.ErrorExit("\nThe PEM filename is missing or incorrect." +
          "\nRun the command with no arguments to see help.");

      // Create the key pair
      await CreateKeyPair(ec2Client, keyPairName, pemFileName);
      await EnumerateKeyPairs(ec2Client);
    }


    //
    // Method to create a key pair and save the key material in a PEM file
    private static async Task CreateKeyPair(
      IAmazonEC2 ec2Client, string keyPairName, string pemFileName)
    {
      // Create the key pair
      CreateKeyPairResponse response =
        await ec2Client.CreateKeyPairAsync(new CreateKeyPairRequest{
          KeyName = keyPairName
        });
      Console.WriteLine($"\nCreated new key pair: {response.KeyPair.KeyName}");

      // Save the private key in a PEM file
      using (var s = new FileStream(pemFileName, FileMode.Create))
      using (var writer = new StreamWriter(s))
      {
        writer.WriteLine(response.KeyPair.KeyMaterial);
      }
    }


    //
    // Method to show the key pairs that are available
    private static async Task EnumerateKeyPairs(IAmazonEC2 ec2Client)
    {
      DescribeKeyPairsResponse response = await ec2Client.DescribeKeyPairsAsync();
      Console.WriteLine("Available key pairs:");
      foreach (KeyPairInfo item in response.KeyPairs)
        Console.WriteLine($"  {item.KeyName}");
    }


    //
    // Command-line help
    private static void PrintHelp()
    {
      Console.WriteLine(
        "\nUsage: EC2CreateKeyPair -k <keypair-name> -p <pem-filename>" +
        "\n  -k, --keypair-name: The name you want to assign to the key pair." +
        "\n  -p, --pem-filename: The name of the PEM file to create, with a \".pem\" extension.");
    }
  }


  // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  // Class that represents a command line on the console or terminal.
  // (This is the same for all examples. When you have seen it once, you can ignore it.)
  static class CommandLine
  {
    //
    // Method to parse a command line of the form: "--key value" or "-k value".
    //
    // Parameters:
    // - args: The command-line arguments passed into the application by the system.
    //
    // Returns:
    // A Dictionary with string Keys and Values.
    //
    // If a key is found without a matching value, Dictionary.Value is set to the key
    //  (including the dashes).
    // If a value is found without a matching key, Dictionary.Key is set to "--NoKeyN",
    //  where "N" represents sequential numbers.
    public static Dictionary<string,string> Parse(string[] args)
    {
      var parsedArgs = new Dictionary<string,string>();
      int i = 0, n = 0;
      while(i < args.Length)
      {
        // If the first argument in this iteration starts with a dash it's an option.
        if(args[i].StartsWith("-"))
        {
          var key = args[i++];
          var value = key;

          // Check to see if there's a value that goes with this option?
          if((i < args.Length) && (!args[i].StartsWith("-"))) value = args[i++];
          parsedArgs.Add(key, value);
        }

        // If the first argument in this iteration doesn't start with a dash, it's a value
        else
        {
          parsedArgs.Add("--NoKey" + n.ToString(), args[i++]);
          n++;
        }
      }

      return parsedArgs;
    }

    //
    // Method to get an argument from the parsed command-line arguments
    //
    // Parameters:
    // - parsedArgs: The Dictionary object returned from the Parse() method (shown above).
    // - defaultValue: The default string to return if the specified key isn't in parsedArgs.
    // - keys: An array of keys to look for in parsedArgs.
    public static string GetArgument(
      Dictionary<string,string> parsedArgs, string defaultReturn, params string[] keys)
    {
      string retval = null;
      foreach(var key in keys)
        if(parsedArgs.TryGetValue(key, out retval)) break;
      return retval ?? defaultReturn;
    }

    //
    // Method to exit the application with an error.
    public static void ErrorExit(string msg, int code=1)
    {
      Console.WriteLine("\nError");
      Console.WriteLine(msg);
      Environment.Exit(code);
    }
  }

}
```

## Consideraciones adicionales
<a name="create-save-key-pair-additional"></a>
+ Tras ejecutar el ejemplo, puede ver el nuevo par de claves en la [consola de Amazon EC2](https://console.aws.amazon.com/ec2/#KeyPairs).
+ Al crear un par de claves, debe guardar la clave privada que se devuelve, ya que no podrá recuperarla más adelante.

# Eliminación de pares de claves
<a name="delete-key-pairs"></a>

En este ejemplo, se muestra cómo utilizar el AWS SDK para .NET para eliminar un key pair. La aplicación toma el nombre de una pareja de claves. Elimina el par de claves y, a continuación, muestra todos los pares de claves disponibles. Si no proporciona argumentos de línea de comandos, la aplicación simplemente muestra todos los pares de claves disponibles.

En las siguientes secciones se proporcionan fragmentos de código de este ejemplo. Tras ello, se muestra el [código completo del ejemplo](#delete-key-pairs-complete-code), que se puede compilar y ejecutar tal cual.

**Topics**
+ [

## Eliminación del par de claves
](#delete-key-pairs-create)
+ [

## Visualización de los pares de claves disponibles
](#delete-key-pairs-display)
+ [

## Código completo
](#delete-key-pairs-complete-code)

## Eliminación del par de claves
<a name="delete-key-pairs-create"></a>

El siguiente fragmento de código elimina un par de claves.

El ejemplo que aparece [al final de este tema](#delete-key-pairs-complete-code) muestra este fragmento de código en uso.

```
    //
    // Method to delete a key pair
    private static async Task DeleteKeyPair(IAmazonEC2 ec2Client, string keyName)
    {
      await ec2Client.DeleteKeyPairAsync(new DeleteKeyPairRequest{
        KeyName = keyName});
      Console.WriteLine($"\nKey pair {keyName} has been deleted (if it existed).");
    }
```

## Visualización de los pares de claves disponibles
<a name="delete-key-pairs-display"></a>

En el siguiente fragmento de código se muestra una lista de los pares de claves disponibles.

El ejemplo que aparece [al final de este tema](#delete-key-pairs-complete-code) muestra este fragmento de código en uso.

```
    //
    // Method to show the key pairs that are available
    private static async Task EnumerateKeyPairs(IAmazonEC2 ec2Client)
    {
      DescribeKeyPairsResponse response = await ec2Client.DescribeKeyPairsAsync();
      Console.WriteLine("Available key pairs:");
      foreach (KeyPairInfo item in response.KeyPairs)
        Console.WriteLine($"  {item.KeyName}");
    }
```

## Código completo
<a name="delete-key-pairs-complete-code"></a>

En esta sección se muestran las referencias relevantes y el código completo de este ejemplo.

### Referencias de SDK
<a name="w2aac19c15c17c15c13c19b5b1"></a>

NuGet paquetes:
+ [AWSSDK.EC2](https://www.nuget.org/packages/AWSSDK.EC2)

Elementos de programación:
+ Espacio de nombres [Amazon.EC2](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/NEC2.html)

  [EC2Cliente Class Amazon](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TEC2Client.html)
+ Espacio de nombres [Amazon.EC2.Model](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/NEC2Model.html)

  Clase [https://docs.aws.amazon.com/sdkfornet/v3/apidocs/](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/)

  Clase [DescribeKeyPairsResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TDescribeKeyPairsResponse.html)

  Clase [KeyPairInfo](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TKeyPairInfo.html)

### El código
<a name="w2aac19c15c17c15c13c19b7b1"></a>

```
using System;
using System.Threading.Tasks;
using Amazon.EC2;
using Amazon.EC2.Model;

namespace EC2DeleteKeyPair
{
  class Program
  {
    static async Task Main(string[] args)
    {
      // Create the EC2 client
      var ec2Client = new AmazonEC2Client();

      if(args.Length == 1)
      {
        // Delete a key pair (if it exists)
        await DeleteKeyPair(ec2Client, args[0]);

        // Display the key pairs that are left
        await EnumerateKeyPairs(ec2Client);
      }
      else
      {
        Console.WriteLine("\nUsage: EC2DeleteKeyPair keypair-name");
        Console.WriteLine("  keypair-name - The name of the key pair you want to delete.");
        Console.WriteLine("\nNo arguments specified.");
        Console.Write(
          "Do you want to see a list of the existing key pairs? ((y) or n): ");
        string response = Console.ReadLine();
        if((string.IsNullOrEmpty(response)) || (response.ToLower() == "y"))
          await EnumerateKeyPairs(ec2Client);
      }
    }


    //
    // Method to delete a key pair
    private static async Task DeleteKeyPair(IAmazonEC2 ec2Client, string keyName)
    {
      await ec2Client.DeleteKeyPairAsync(new DeleteKeyPairRequest{
        KeyName = keyName});
      Console.WriteLine($"\nKey pair {keyName} has been deleted (if it existed).");
    }


    //
    // Method to show the key pairs that are available
    private static async Task EnumerateKeyPairs(IAmazonEC2 ec2Client)
    {
      DescribeKeyPairsResponse response = await ec2Client.DescribeKeyPairsAsync();
      Console.WriteLine("Available key pairs:");
      foreach (KeyPairInfo item in response.KeyPairs)
        Console.WriteLine($"  {item.KeyName}");
    }
  }
}
```

# Visualización de regiones y zonas de disponibilidad de Amazon EC2
<a name="using-regions-and-availability-zones"></a>

Amazon EC2 está alojado en varias ubicaciones de todo el mundo. Dichas ubicaciones se componen de regiones y zonas de disponibilidad. Cada región es un área geográfica distinta y tiene varias ubicaciones aisladas, denominadas zonas de disponibilidad.

Para obtener más información acerca de las regiones y zonas de disponibilidad, consulte [Regiones y zonas](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-regions-availability-zones.html) en la [Guía del usuario de Amazon EC2](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/).

En este ejemplo, se muestra cómo utilizar el AWS SDK para .NET para obtener detalles sobre las regiones y las zonas de disponibilidad relacionadas con un cliente EC2. La aplicación muestra listas de las regiones y las zonas de disponibilidad disponibles para un cliente de EC2.

## Referencias de SDK
<a name="w2aac19c15c17c17b9b1"></a>

NuGet paquetes:
+ [AWSSDK.EC2](https://www.nuget.org/packages/AWSSDK.EC2)

Elementos de programación:
+ Espacio de nombres [Amazon.EC2](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/NEC2.html)

  [EC2Cliente Class Amazon](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TEC2Client.html)
+ Espacio de nombres [Amazon.EC2.Model](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/NEC2Model.html)

  Clase [DescribeAvailabilityZonesResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TDescribeAvailabilityZonesResponse.html)

  Clase [DescribeRegionsResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TDescribeRegionsResponse.html)

  Clase [AvailabilityZone](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TAvailabilityZone.html)

  Clase [Region](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TRegion.html)

```
using System;
using System.Threading.Tasks;
using Amazon.EC2;
using Amazon.EC2.Model;

namespace EC2RegionsAndZones
{
  class Program
  {
    static async Task Main(string[] args)
    {
      Console.WriteLine(
        "Finding the Regions and Availability Zones available to an EC2 client...");

      // Create the EC2 client
      var ec2Client = new AmazonEC2Client();

      // Display the Regions and Availability Zones
      await DescribeRegions(ec2Client);
      await DescribeAvailabilityZones(ec2Client);
    }


    //
    // Method to display Regions
    private static async Task DescribeRegions(IAmazonEC2 ec2Client)
    {
      Console.WriteLine("\nRegions that are enabled for the EC2 client:");
      DescribeRegionsResponse response = await ec2Client.DescribeRegionsAsync();
      foreach (Region region in response.Regions)
        Console.WriteLine(region.RegionName);
    }


    //
    // Method to display Availability Zones
    private static async Task DescribeAvailabilityZones(IAmazonEC2 ec2Client)
    {
      Console.WriteLine("\nAvailability Zones for the EC2 client's region:");
      DescribeAvailabilityZonesResponse response =
        await ec2Client.DescribeAvailabilityZonesAsync();
      foreach (AvailabilityZone az in response.AvailabilityZones)
        Console.WriteLine(az.ZoneName);
    }
  }
}
```

# Uso de instancias de Amazon EC2
<a name="how-to-ec2"></a>

Puede usarlo AWS SDK para .NET para controlar las instancias de Amazon EC2 con operaciones como crear, iniciar y terminar. En los temas de esta sección se proporcionan algunos ejemplos de cómo hacerlo. Para obtener más información sobre las instancias de EC2, consulte [Instancias de Amazon EC2](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/Instances.html) en la [Guía del usuario de Amazon EC2](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/).

Para obtener información sobre los requisitos APIs y requisitos previos, consulte la sección principal ()[Uso de Amazon EC2](ec2-apis-intro.md).

**Topics**
+ [Lanzamiento de una instancia de EC2](run-instance.md)
+ [Terminación de una instancia de EC2](terminate-instance.md)

# Lanzamiento de una instancia de Amazon EC2
<a name="run-instance"></a>

En este ejemplo, se muestra cómo utilizarla AWS SDK para .NET para lanzar una o más instancias de Amazon EC2 configuradas de forma idéntica desde la misma imagen de máquina de Amazon (AMI). La aplicación utiliza las [diferentes entradas](#run-instance-gather) que proporcione para lanzar una instancia de EC2 y, a continuación, la monitoriza hasta que deja de estar en estado “Pendiente”.

Cuando la instancia de EC2 está en ejecución, puede conectarse a ella de forma remota, como se describe en [(opcional) Conexión a la instancia](#connect-to-instance).

**aviso**  
EC2-Classic se retirará el 15 de agosto de 2022. Le recomendamos que migre de EC2-Classic a una VPC. Para obtener más información, consulte la entrada del blog [EC2-Classic Networking se retira: cómo prepararse](https://aws.amazon.com/blogs/aws/ec2-classic-is-retiring-heres-how-to-prepare/).

En las siguientes secciones se proporcionan fragmentos de código y otra información de este ejemplo. Después de los fragmentos de código se muestra el [código completo del ejemplo](#run-instance-complete-code), que se puede compilar y ejecutar tal cual.

**Topics**
+ [

## Reunir todo lo necesario
](#run-instance-gather)
+ [

## Iniciar una instancia
](#run-instance-launch)
+ [

## Monitorización de la instancia
](#run-instance-monitor)
+ [

## Código completo
](#run-instance-complete-code)
+ [

## Consideraciones adicionales
](#run-instance-additional)
+ [

## (opcional) Conexión a la instancia
](#connect-to-instance)
+ [

## Limpieza
](#run-instance-cleanup)

## Reunir todo lo necesario
<a name="run-instance-gather"></a>

Para lanzar una instancia de EC2, necesitará varios elementos.
+ Una [VPC](https://docs.aws.amazon.com/vpc/latest/userguide/) donde se lanzará la instancia. Si va a ser una instancia de Windows y se va a conectar a ella a través de RDP, lo más probable es que la VPC necesite tener asociada una puerta de enlace de Internet, así como una entrada correspondiente a esa puerta de enlace de Internet en la tabla de enrutamiento. Para obtener más información, consulte [Puertas de enlace de Internet](https://docs.aws.amazon.com/vpc/latest/userguide/VPC_Internet_Gateway.html) en la *Guía del usuario de Amazon VPC*.
+ El ID de una subred existente en la VPC donde se lanzará la instancia. Una forma sencilla de encontrarlo o crearlo es iniciar sesión en la [consola de Amazon VPC](https://console.aws.amazon.com/vpc/home#subnets), pero también puede obtenerlo mediante programación mediante los métodos y. [CreateSubnetAsync[DescribeSubnetsAsync](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/MEC2DescribeSubnetsAsyncDescribeSubnetsRequestCancellationToken.html)](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/MEC2CreateSubnetAsyncCreateSubnetRequestCancellationToken.html)
**nota**  
Si no proporciona este parámetro, la nueva instancia se lanza en la VPC predeterminada de la cuenta.
+ El ID de un grupo de seguridad existente que pertenezca a la VPC donde se lanzará la instancia. Para obtener más información, consulte [Uso de grupos de seguridad en Amazon EC2](security-groups.md).
+ Si desea conectarse a la instancia nueva, el grupo de seguridad mencionado anteriormente debe tener una regla de entrada adecuada que permita el tráfico SSH en el puerto 22 (instancia de Linux) o el tráfico RDP en el puerto 3389 (instancia de Windows). Para obtener información sobre cómo hacerlo, consulte [Actualización de grupos de seguridad](authorize-ingress.md), así como la sección [Consideraciones adicionales](authorize-ingress.md#authorize-ingress-additional) al final de ese tema.
+ La imagen de máquina de Amazon (AMI) que se utilizará para crear la instancia. Para obtener más información AMIs, consulte [Amazon Machine Images (AMIs)](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AMIs.html) en la Guía del [usuario de Amazon EC2](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/). En concreto, consulte [Buscar una AMI](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/finding-an-ami.html) y [compartirla AMIs](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/sharing-amis.html).
+ El nombre de un par de claves de EC2 existente, que se utiliza para conectarse a la nueva instancia. Para obtener más información, consulte [Uso de pares de claves de Amazon EC2](key-pairs.md).
+ El nombre del archivo PEM que contiene la clave privada del par de claves de EC2 mencionado anteriormente. El archivo PEM se utiliza cuando se [conecta de forma remota](#connect-to-instance) a la instancia.

## Iniciar una instancia
<a name="run-instance-launch"></a>

El siguiente fragmento de código lanza una instancia de EC2.

El ejemplo que aparece [cerca del final de este tema](#run-instance-complete-code) muestra este fragmento de código en uso.

```
    //
    // Method to launch the instances
    // Returns a list with the launched instance IDs
    private static async Task<List<string>> LaunchInstances(
      IAmazonEC2 ec2Client, RunInstancesRequest requestLaunch)
    {
      var instanceIds = new List<string>();
      RunInstancesResponse responseLaunch =
        await ec2Client.RunInstancesAsync(requestLaunch);

      Console.WriteLine("\nNew instances have been created.");
      foreach (Instance item in responseLaunch.Reservation.Instances)
      {
        instanceIds.Add(item.InstanceId);
        Console.WriteLine($"  New instance: {item.InstanceId}");
      }

      return instanceIds;
    }
```

## Monitorización de la instancia
<a name="run-instance-monitor"></a>

El siguiente fragmento de código monitoriza la instancia hasta que deja de estar en estado “Pendiente”.

El ejemplo que aparece [cerca del final de este tema](#run-instance-complete-code) muestra este fragmento de código en uso.

Consulte la [InstanceState](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TInstanceState.html)clase para ver los valores válidos de la `Instance.State.Code` propiedad.

```
    //
    // Method to wait until the instances are running (or at least not pending)
    private static async Task CheckState(IAmazonEC2 ec2Client, List<string> instanceIds)
    {
      Console.WriteLine(
        "\nWaiting for the instances to start." +
        "\nPress any key to stop waiting. (Response might be slightly delayed.)");

      int numberRunning;
      DescribeInstancesResponse responseDescribe;
      var requestDescribe = new DescribeInstancesRequest{
        InstanceIds = instanceIds};

      // Check every couple of seconds
      int wait = 2000;
      while(true)
      {
        // Get and check the status for each of the instances to see if it's past pending.
        // Once all instances are past pending, break out.
        // (For this example, we are assuming that there is only one reservation.)
        Console.Write(".");
        numberRunning = 0;
        responseDescribe = await ec2Client.DescribeInstancesAsync(requestDescribe);
        foreach(Instance i in responseDescribe.Reservations[0].Instances)
        {
          // Check the lower byte of State.Code property
          // Code == 0 is the pending state
          if((i.State.Code & 255) > 0) numberRunning++;
        }
        if(numberRunning == responseDescribe.Reservations[0].Instances.Count)
          break;

        // Wait a bit and try again (unless the user wants to stop waiting)
        Thread.Sleep(wait);
        if(Console.KeyAvailable)
          break;
      }

      Console.WriteLine("\nNo more instances are pending.");
      foreach(Instance i in responseDescribe.Reservations[0].Instances)
      {
        Console.WriteLine($"For {i.InstanceId}:");
        Console.WriteLine($"  VPC ID: {i.VpcId}");
        Console.WriteLine($"  Instance state: {i.State.Name}");
        Console.WriteLine($"  Public IP address: {i.PublicIpAddress}");
        Console.WriteLine($"  Public DNS name: {i.PublicDnsName}");
        Console.WriteLine($"  Key pair name: {i.KeyName}");
      }
    }
```

## Código completo
<a name="run-instance-complete-code"></a>

En esta sección se muestran las referencias relevantes y el código completo de este ejemplo.

### Referencias de SDK
<a name="w2aac19c15c17c19b9c27b5b1"></a>

NuGet paquetes:
+ [AWSSDK.EC2](https://www.nuget.org/packages/AWSSDK.EC2)

Elementos de programación:
+ Espacio de nombres [Amazon.EC2](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/NEC2.html)

  [EC2Cliente Class Amazon](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TEC2Client.html)

  Clase [InstanceType](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TInstanceType.html)
+ Espacio de nombres [Amazon.EC2.Model](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/NEC2Model.html)

  Clase [DescribeInstancesRequest](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TDescribeInstancesRequest.html)

  Clase [DescribeInstancesResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TDescribeInstancesResponse.html)

  Clase [Instance](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TInstance.html)

  Clase [InstanceNetworkInterfaceSpecification](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TInstanceNetworkInterfaceSpecification.html)

  Clase [RunInstancesRequest](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TRunInstancesRequest.html)

  Clase [RunInstancesResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TRunInstancesResponse.html)

### El código
<a name="w2aac19c15c17c19b9c27b7b1"></a>

```
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Collections.Generic;
using Amazon.EC2;
using Amazon.EC2.Model;

namespace EC2LaunchInstance
{
  // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  // Class to launch an EC2 instance
  class Program
  {
    static async Task Main(string[] args)
    {
      // Parse the command line and show help if necessary
      var parsedArgs = CommandLine.Parse(args);
      if(parsedArgs.Count == 0)
      {
        PrintHelp();
        return;
      }

      // Get the application arguments from the parsed list
      string groupID =
        CommandLine.GetArgument(parsedArgs, null, "-g", "--group-id");
      string ami =
        CommandLine.GetArgument(parsedArgs, null, "-a", "--ami-id");
      string keyPairName =
        CommandLine.GetArgument(parsedArgs, null, "-k", "--keypair-name");
      string subnetID =
        CommandLine.GetArgument(parsedArgs, null, "-s", "--subnet-id");
      if(   (string.IsNullOrEmpty(groupID) || !groupID.StartsWith("sg-"))
         || (string.IsNullOrEmpty(ami) || !ami.StartsWith("ami-"))
         || (string.IsNullOrEmpty(keyPairName))
         || (!string.IsNullOrEmpty(subnetID) && !subnetID.StartsWith("subnet-")))
        CommandLine.ErrorExit(
          "\nOne or more of the required arguments is missing or incorrect." +
          "\nRun the command with no arguments to see help.");

      // Create an EC2 client
      var ec2Client = new AmazonEC2Client();

      // Create an object with the necessary properties
      RunInstancesRequest request = GetRequestData(groupID, ami, keyPairName, subnetID);

      // Launch the instances and wait for them to start running
      var instanceIds = await LaunchInstances(ec2Client, request);
      await CheckState(ec2Client, instanceIds);
    }


    //
    // Method to put together the properties needed to launch the instance.
    private static RunInstancesRequest GetRequestData(
      string groupID, string ami, string keyPairName, string subnetID)
    {
      // Common properties
      var groupIDs = new List<string>() { groupID };
      var request = new RunInstancesRequest()
      {
        // The first three of these would be additional command-line arguments or similar.
        InstanceType = InstanceType.T1Micro,
        MinCount = 1,
        MaxCount = 1,
        ImageId = ami,
        KeyName = keyPairName
      };

      // Properties specifically for EC2 in a VPC.
      if(!string.IsNullOrEmpty(subnetID))
      {
        request.NetworkInterfaces =
          new List<InstanceNetworkInterfaceSpecification>() {
            new InstanceNetworkInterfaceSpecification() {
              DeviceIndex = 0,
              SubnetId = subnetID,
              Groups = groupIDs,
              AssociatePublicIpAddress = true
            }
          };
      }

      // Properties specifically for EC2-Classic
      else
      {
        request.SecurityGroupIds = groupIDs;
      }
      return request;
    }


    //
    // Method to launch the instances
    // Returns a list with the launched instance IDs
    private static async Task<List<string>> LaunchInstances(
      IAmazonEC2 ec2Client, RunInstancesRequest requestLaunch)
    {
      var instanceIds = new List<string>();
      RunInstancesResponse responseLaunch =
        await ec2Client.RunInstancesAsync(requestLaunch);

      Console.WriteLine("\nNew instances have been created.");
      foreach (Instance item in responseLaunch.Reservation.Instances)
      {
        instanceIds.Add(item.InstanceId);
        Console.WriteLine($"  New instance: {item.InstanceId}");
      }

      return instanceIds;
    }


    //
    // Method to wait until the instances are running (or at least not pending)
    private static async Task CheckState(IAmazonEC2 ec2Client, List<string> instanceIds)
    {
      Console.WriteLine(
        "\nWaiting for the instances to start." +
        "\nPress any key to stop waiting. (Response might be slightly delayed.)");

      int numberRunning;
      DescribeInstancesResponse responseDescribe;
      var requestDescribe = new DescribeInstancesRequest{
        InstanceIds = instanceIds};

      // Check every couple of seconds
      int wait = 2000;
      while(true)
      {
        // Get and check the status for each of the instances to see if it's past pending.
        // Once all instances are past pending, break out.
        // (For this example, we are assuming that there is only one reservation.)
        Console.Write(".");
        numberRunning = 0;
        responseDescribe = await ec2Client.DescribeInstancesAsync(requestDescribe);
        foreach(Instance i in responseDescribe.Reservations[0].Instances)
        {
          // Check the lower byte of State.Code property
          // Code == 0 is the pending state
          if((i.State.Code & 255) > 0) numberRunning++;
        }
        if(numberRunning == responseDescribe.Reservations[0].Instances.Count)
          break;

        // Wait a bit and try again (unless the user wants to stop waiting)
        Thread.Sleep(wait);
        if(Console.KeyAvailable)
          break;
      }

      Console.WriteLine("\nNo more instances are pending.");
      foreach(Instance i in responseDescribe.Reservations[0].Instances)
      {
        Console.WriteLine($"For {i.InstanceId}:");
        Console.WriteLine($"  VPC ID: {i.VpcId}");
        Console.WriteLine($"  Instance state: {i.State.Name}");
        Console.WriteLine($"  Public IP address: {i.PublicIpAddress}");
        Console.WriteLine($"  Public DNS name: {i.PublicDnsName}");
        Console.WriteLine($"  Key pair name: {i.KeyName}");
      }
    }


    //
    // Command-line help
    private static void PrintHelp()
    {
      Console.WriteLine(
        "\nUsage: EC2LaunchInstance -g <group-id> -a <ami-id> -k <keypair-name> [-s <subnet-id>]" +
        "\n  -g, --group-id: The ID of the security group." +
        "\n  -a, --ami-id: The ID of an Amazon Machine Image." +
        "\n  -k, --keypair-name - The name of a key pair." +
        "\n  -s, --subnet-id: The ID of a subnet. Required only for EC2 in a VPC.");
    }
  }


  // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  // Class that represents a command line on the console or terminal.
  // (This is the same for all examples. When you have seen it once, you can ignore it.)
  static class CommandLine
  {
    //
    // Method to parse a command line of the form: "--key value" or "-k value".
    //
    // Parameters:
    // - args: The command-line arguments passed into the application by the system.
    //
    // Returns:
    // A Dictionary with string Keys and Values.
    //
    // If a key is found without a matching value, Dictionary.Value is set to the key
    //  (including the dashes).
    // If a value is found without a matching key, Dictionary.Key is set to "--NoKeyN",
    //  where "N" represents sequential numbers.
    public static Dictionary<string,string> Parse(string[] args)
    {
      var parsedArgs = new Dictionary<string,string>();
      int i = 0, n = 0;
      while(i < args.Length)
      {
        // If the first argument in this iteration starts with a dash it's an option.
        if(args[i].StartsWith("-"))
        {
          var key = args[i++];
          var value = key;

          // Check to see if there's a value that goes with this option?
          if((i < args.Length) && (!args[i].StartsWith("-"))) value = args[i++];
          parsedArgs.Add(key, value);
        }

        // If the first argument in this iteration doesn't start with a dash, it's a value
        else
        {
          parsedArgs.Add("--NoKey" + n.ToString(), args[i++]);
          n++;
        }
      }

      return parsedArgs;
    }

    //
    // Method to get an argument from the parsed command-line arguments
    //
    // Parameters:
    // - parsedArgs: The Dictionary object returned from the Parse() method (shown above).
    // - defaultValue: The default string to return if the specified key isn't in parsedArgs.
    // - keys: An array of keys to look for in parsedArgs.
    public static string GetArgument(
      Dictionary<string,string> parsedArgs, string defaultReturn, params string[] keys)
    {
      string retval = null;
      foreach(var key in keys)
        if(parsedArgs.TryGetValue(key, out retval)) break;
      return retval ?? defaultReturn;
    }

    //
    // Method to exit the application with an error.
    public static void ErrorExit(string msg, int code=1)
    {
      Console.WriteLine("\nError");
      Console.WriteLine(msg);
      Environment.Exit(code);
    }
  }

}
```

## Consideraciones adicionales
<a name="run-instance-additional"></a>
+ Al comprobar el estado de una instancia EC2, puede añadir un filtro a la `Filter` propiedad del [DescribeInstancesRequest](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TDescribeInstancesRequest.html)objeto. Con esta técnica, puede limitar la solicitud a unas instancias determinadas, por ejemplo, las instancias con una etiqueta concreta especificada por el usuario.
+ En aras de una mayor brevedad, se han asignado valores típicos a algunas propiedades, pero cualquiera o todas estas propiedades se pueden determinar mediante programación o usando entradas de usuario.
+ Los valores que puede utilizar para el [RunInstancesRequest](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TRunInstancesRequest.html)objeto `MinCount` y `MaxCount` sus propiedades vienen determinados por la zona de disponibilidad de destino y el número máximo de instancias permitido para el tipo de instancia. Para obtener más información, consulte [¿Cuántas instancias puedo ejecutar en Amazon EC2?](https://aws.amazon.com/ec2/faqs/#How_many_instances_can_I_run_in_Amazon_EC2) en las preguntas frecuentes generales de Amazon EC2.
+ Si desea utilizar un tipo de instancia diferente al de este ejemplo, puede elegir entre varios tipos. Para obtener más información, consulte [Tipos de instancias de Amazon EC2](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-types.html) en la [Guía del usuario de Amazon EC2](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/). Consulte también [Detalles del tipo de instancia](https://aws.amazon.com/ec2/instance-types/) y [Explorador de tipos de instancia](https://aws.amazon.com/ec2/instance-explorer/).
+ También puede asociar un [rol de IAM](net-dg-hosm.md) a una instancia al lanzarla. Para ello, cree un [IamInstanceProfileSpecification](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TIamInstanceProfileSpecification.html)objeto cuya `Name` propiedad esté establecida en el nombre de un rol de IAM. A continuación, añada ese objeto a la `IamInstanceProfile` propiedad del [RunInstancesRequest](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TRunInstancesRequest.html)objeto.
**nota**  
Para lanzar una instancia de EC2 que tenga un rol de IAM asociado, la configuración de un usuario de IAM debe incluir determinados permisos. Para obtener más información sobre los permisos necesarios, consulte la sección [Concesión de permisos a un usuario para transferir un rol de IAM a una instancia](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html#permission-to-pass-iam-roles) en la [Guía del usuario de Amazon EC2](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/).

## (opcional) Conexión a la instancia
<a name="connect-to-instance"></a>

En cuanto se esté ejecutando una instancia, puede conectarse de forma remota a ella utilizando el cliente remoto adecuado. Tanto si las instancias son de Linux o de Windows, necesita la dirección IP pública o el nombre DNS público de la instancia. También necesitará lo siguiente.

**Instancias de Linux**

Puede usar un cliente SSH para conectarse a la instancia de Linux. Asegúrese de que el grupo de seguridad que utilizó al lanzar la instancia permite el tráfico SSH en el puerto 22, tal y como se describe en [Actualización de grupos de seguridad](authorize-ingress.md).

También necesitará el archivo que contiene la parte privada de par de claves que usó para lanzar la instancia, es decir, el archivo PEM.

Para obtener más información, consulte [Conexión con la instancia de Linux](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/connect-to-linux-instance.html) en la Guía del usuario de Amazon EC2.

**Instancias de Windows**

Puede usar un cliente RDP para conectarse a la instancia. Asegúrese de que el grupo de seguridad que utilizó al lanzar la instancia permite el tráfico RDP en el puerto 3389, tal y como se describe en [Actualización de grupos de seguridad](authorize-ingress.md).

También necesitará una contraseña de administrador. Puede obtenerlo mediante el siguiente código de ejemplo, que requiere el ID de la instancia y la parte privada del par de claves que usó para lanzar la instancia, es decir, el archivo PEM.

Para obtener más información, consulte [Conexión a la instancia de Windows](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/connecting_to_windows_instance.html) en la Guía del usuario de Amazon EC2.

**aviso**  
Este código de ejemplo devuelve la contraseña de administrador de la instancia en texto si formato.

### Referencias de SDK
<a name="w2aac19c15c17c19b9c35c23b1"></a>

NuGet paquetes:
+ [AWSSDK.EC2](https://www.nuget.org/packages/AWSSDK.EC2)

Elementos de programación:
+ Espacio de nombres [Amazon.EC2](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/NEC2.html)

  [EC2Cliente Class Amazon](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TEC2Client.html)
+ Espacio de nombres [Amazon.EC2.Model](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/NEC2Model.html)

  Clase [GetPasswordDataRequest](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TGetPasswordDataRequest.html)

  Clase [GetPasswordDataResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TGetPasswordDataResponse.html)

### El código
<a name="w2aac19c15c17c19b9c35c25b1"></a>

```
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using Amazon.EC2;
using Amazon.EC2.Model;

namespace EC2GetWindowsPassword
{
  // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  // Class to get the Administrator password of a Windows EC2 instance
  class Program
  {
    static async Task Main(string[] args)
    {
      // Parse the command line and show help if necessary
      var parsedArgs = CommandLine.Parse(args);
      if(parsedArgs.Count == 0)
      {
        PrintHelp();
        return;
      }

      // Get the application arguments from the parsed list
      string instanceID =
        CommandLine.GetArgument(parsedArgs, null, "-i", "--instance-id");
      string pemFileName =
        CommandLine.GetArgument(parsedArgs, null, "-p", "--pem-filename");
      if(   (string.IsNullOrEmpty(instanceID) || !instanceID.StartsWith("i-"))
         || (string.IsNullOrEmpty(pemFileName) || !pemFileName.EndsWith(".pem")))
        CommandLine.ErrorExit(
          "\nOne or more of the required arguments is missing or incorrect." +
          "\nRun the command with no arguments to see help.");

      // Create the EC2 client
      var ec2Client = new AmazonEC2Client();

      // Get and display the password
      string password = await GetPassword(ec2Client, instanceID, pemFileName);
      Console.WriteLine($"\nPassword: {password}");
    }


    //
    // Method to get the administrator password of a Windows EC2 instance
    private static async Task<string> GetPassword(
      IAmazonEC2 ec2Client, string instanceID, string pemFilename)
    {
      string password = string.Empty;
      GetPasswordDataResponse response =
        await ec2Client.GetPasswordDataAsync(new GetPasswordDataRequest{
          InstanceId = instanceID});
      if(response.PasswordData != null)
      {
        password = response.GetDecryptedPassword(File.ReadAllText(pemFilename));
      }
      else
      {
        Console.WriteLine($"\nThe password is not available for instance {instanceID}.");
        Console.WriteLine($"If this is a Windows instance, the password might not be ready.");
      }
      return password;
    }


    //
    // Command-line help
    private static void PrintHelp()
    {
      Console.WriteLine(
        "\nUsage: EC2GetWindowsPassword -i <instance-id> -p pem-filename" +
        "\n  -i, --instance-id: The name of the EC2 instance." +
        "\n  -p, --pem-filename: The name of the PEM file with the private key.");
    }
  }

  // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  // Class that represents a command line on the console or terminal.
  // (This is the same for all examples. When you have seen it once, you can ignore it.)
  static class CommandLine
  {
    //
    // Method to parse a command line of the form: "--key value" or "-k value".
    //
    // Parameters:
    // - args: The command-line arguments passed into the application by the system.
    //
    // Returns:
    // A Dictionary with string Keys and Values.
    //
    // If a key is found without a matching value, Dictionary.Value is set to the key
    //  (including the dashes).
    // If a value is found without a matching key, Dictionary.Key is set to "--NoKeyN",
    //  where "N" represents sequential numbers.
    public static Dictionary<string,string> Parse(string[] args)
    {
      var parsedArgs = new Dictionary<string,string>();
      int i = 0, n = 0;
      while(i < args.Length)
      {
        // If the first argument in this iteration starts with a dash it's an option.
        if(args[i].StartsWith("-"))
        {
          var key = args[i++];
          var value = key;

          // Check to see if there's a value that goes with this option?
          if((i < args.Length) && (!args[i].StartsWith("-"))) value = args[i++];
          parsedArgs.Add(key, value);
        }

        // If the first argument in this iteration doesn't start with a dash, it's a value
        else
        {
          parsedArgs.Add("--NoKey" + n.ToString(), args[i++]);
          n++;
        }
      }

      return parsedArgs;
    }

    //
    // Method to get an argument from the parsed command-line arguments
    //
    // Parameters:
    // - parsedArgs: The Dictionary object returned from the Parse() method (shown above).
    // - defaultValue: The default string to return if the specified key isn't in parsedArgs.
    // - keys: An array of keys to look for in parsedArgs.
    public static string GetArgument(
      Dictionary<string,string> parsedArgs, string defaultReturn, params string[] keys)
    {
      string retval = null;
      foreach(var key in keys)
        if(parsedArgs.TryGetValue(key, out retval)) break;
      return retval ?? defaultReturn;
    }

    //
    // Method to exit the application with an error.
    public static void ErrorExit(string msg, int code=1)
    {
      Console.WriteLine("\nError");
      Console.WriteLine(msg);
      Environment.Exit(code);
    }
  }

}
```

## Limpieza
<a name="run-instance-cleanup"></a>

Cuando ya no necesite la instancia de EC2, asegúrese de terminarla, como se describe en [Terminación de una instancia de Amazon EC2](terminate-instance.md).

# Terminación de una instancia de Amazon EC2
<a name="terminate-instance"></a>

Cuando ya no necesite una o varias de las instancias de Amazon EC2, puede terminarlas.

En este ejemplo, se muestra cómo utilizarlos AWS SDK para .NET para terminar las instancias de EC2. Se toma como entrada un ID de instancia.

## Referencias de SDK
<a name="w2aac19c15c17c19c11b7b1"></a>

NuGet paquetes:
+ [AWSSDK.EC2](https://www.nuget.org/packages/AWSSDK.EC2)

Elementos de programación:
+ Espacio de nombres [Amazon.EC2](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/NEC2.html)

  [EC2Cliente Class Amazon](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TEC2Client.html)
+ Espacio de nombres [Amazon.EC2.Model](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/NEC2Model.html)

  Clase [TerminateInstancesRequest](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TTerminateInstancesRequest.html)

  Clase [TerminateInstancesResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TTerminateInstancesResponse.html)

```
using System;
using System.Threading.Tasks;
using System.Collections.Generic;
using Amazon.EC2;
using Amazon.EC2.Model;

namespace EC2TerminateInstance
{
  class Program
  {
    static async Task Main(string[] args)
    {
      if((args.Length == 1) && (args[0].StartsWith("i-")))
      {
        // Terminate the instance
        var ec2Client = new AmazonEC2Client();
        await TerminateInstance(ec2Client, args[0]);
      }
      else
      {
        Console.WriteLine("\nCommand-line argument missing or incorrect.");
        Console.WriteLine("\nUsage: EC2TerminateInstance instance-ID");
        Console.WriteLine("  instance-ID - The EC2 instance you want to terminate.");
        return;
      }
    }

    //
    // Method to terminate an EC2 instance
    private static async Task TerminateInstance(IAmazonEC2 ec2Client, string instanceID)
    {
      var request = new TerminateInstancesRequest{
        InstanceIds = new List<string>() { instanceID }};
      TerminateInstancesResponse response =
        await ec2Client.TerminateInstancesAsync(new TerminateInstancesRequest{
          InstanceIds = new List<string>() { instanceID }
        });
      foreach (InstanceStateChange item in response.TerminatingInstances)
      {
        Console.WriteLine("Terminated instance: " + item.InstanceId);
        Console.WriteLine("Instance state: " + item.CurrentState.Name);
      }
    }
  }
}
```

Tras ejecutar el ejemplo, es conveniente iniciar sesión en la [consola de Amazon EC2](https://console.aws.amazon.com/ec2/) para confirmar que la [instancia EC2](https://console.aws.amazon.com/ec2/v2/home#Instances) se ha terminado.

# Tutorial de instancias de spot de Amazon EC2
<a name="how-to-spot-instances"></a>

En este tutorial, se muestra cómo utilizarlos AWS SDK para .NET para gestionar las instancias puntuales de Amazon EC2.

## Descripción general de
<a name="tutor-spot-net-overview"></a>

Las instancias de spot permiten solicitar capacidad de Amazon EC2 sin utilizar por un precio inferior al precio bajo demanda. Esto puede reducir considerablemente los costos de EC2 correspondientes a aplicaciones que pueden interrumpirse.

Este es un resumen general de cómo solicitar y utilizar instancias de spot.

1. Cree una solicitud de instancia de spot, especificando el precio máximo que está dispuesto a pagar.

1. Una vez atendida la solicitud, ejecute la instancia como lo haría con cualquier otra instancia de Amazon EC2.

1. Ejecute la instancia todo el tiempo que desee y, a continuación, termínela, a menos que el *precio de instancia spot* cambie y la instancia termine automáticamente.

1. Limpie la solicitud de instancia de spot cuando ya no la necesite para que no se creen más instancias de spot.

Esta descripción general de las instancias de spot es muy genérica. Para comprender mejor las instancias de spot, consulte [Instancias de spot](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-spot-instances.html) en la [Guía del usuario de Amazon EC2](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/).

## Acerca de este tutorial
<a name="about-spot-instances-tutorial"></a>

Al seguir este tutorial, utilizará el AWS SDK para .NET para hacer lo siguiente:
+ Creación de una solicitud de instancia de spot
+ Determinar cuándo se ha atendido la solicitud de instancia de spot
+ Cancelar la solicitud de instancia de spot
+ Terminar las instancias asociadas

En las siguientes secciones se proporcionan fragmentos de código y otra información de este ejemplo. Después de los fragmentos de código se muestra el [código completo del ejemplo](#tutor-spot-net-main), que se puede compilar y ejecutar tal cual.

**Topics**
+ [

## Descripción general de
](#tutor-spot-net-overview)
+ [

## Acerca de este tutorial
](#about-spot-instances-tutorial)
+ [

## Requisitos previos
](#tutor-spot-net-prereq)
+ [

## Reunir todo lo necesario
](#tutor-spot-net-gather)
+ [

## Creación de una solicitud de instancia de spot
](#tutor-spot-net-submit)
+ [

## Determinación del estado de la solicitud de instancia de spot
](#tutor-spot-net-request-state)
+ [

## Limpieza de las solicitudes de instancia de spot
](#tutor-spot-net-clean-up-request)
+ [

## Limpieza de las instancias de spot
](#tutor-spot-net-clean-up-instance)
+ [

## Código completo
](#tutor-spot-net-main)
+ [

## Consideraciones adicionales
](#tutor-spot-net-additional)

## Requisitos previos
<a name="tutor-spot-net-prereq"></a>

Para obtener información sobre los requisitos APIs y requisitos previos, consulte la sección principal ([Uso de Amazon EC2](ec2-apis-intro.md)).

## Reunir todo lo necesario
<a name="tutor-spot-net-gather"></a>

Para crear una solicitud de instancia de spot, necesitará varias cosas. 
+ El número de instancias y el tipo de instancia. Hay varios tipos de instancias para elegir. Para obtener más información, consulte [Tipos de instancias de Amazon EC2](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-types.html) en la [Guía del usuario de Amazon EC2](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/). Consulte también [Detalles del tipo de instancia](https://aws.amazon.com/ec2/instance-types/) y [Explorador de tipos de instancia](https://aws.amazon.com/ec2/instance-explorer/).

  En este tutorial, el número predeterminado es 1.
+ La imagen de máquina de Amazon (AMI) que se utilizará para crear la instancia. Para obtener más información AMIs, consulte [Amazon Machine Images (AMIs)](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AMIs.html) en la Guía del [usuario de Amazon EC2](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/). En concreto, consulte [Buscar una AMI](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/finding-an-ami.html) y [compartirla AMIs](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/sharing-amis.html).
+ El precio máximo que está dispuesto a pagar por hora de instancia. Puede ver los precios de todos los tipos de instancias (tanto de las instancias bajo demanda como de las instancias de spot) en la [página de precios de Amazon EC2](https://aws.amazon.com/ec2/pricing/). El precio predeterminado de este tutorial se explica más adelante.
+ Si quiere conectarse a una instancia de forma remota, un grupo de seguridad con la configuración y los recursos adecuados. Esto se describe en [Uso de grupos de seguridad en Amazon EC2](security-groups.md) y en la información sobre cómo [reunir todo lo necesario](run-instance.md#run-instance-gather) y cómo [conectarse a una instancia](run-instance.md#connect-to-instance) en [Lanzamiento de una instancia de Amazon EC2](run-instance.md). Para que todo sea más sencillo, en este tutorial se utiliza el grupo de seguridad **predeterminado** que tienen todas las cuentas de AWS más nuevas.

Hay muchas formas de abordar la solicitud de instancias de spot. Estas son algunas estrategias comunes:
+ Realizar solicitudes que seguro que van a costar menos que el precio bajo demanda
+ Realizar solicitudes según en el valor del cálculo resultante
+ Realizar solicitudes adquirir capacidad informática lo más rápidamente posible

Las siguientes explicaciones hacen referencia al [historial de precios de las instancias de spot](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-spot-instances-history.html) de la [Guía del usuario de Amazon EC2](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/).

### Reducir el costo por debajo del precio bajo demanda
<a name="reduce-cost"></a>

Tiene una tarea de procesamiento por lotes que tardará en ejecutarse una cantidad determinada de horas o días. Sin embargo, es flexible con respecto a cuándo comienza y finaliza. Desea ver si puede completarla por menos del valor del costo de las instancias bajo demanda.

Examina el historial de precios de instancia de spot de tipos de instancia usando la consola de administración de Amazon EC2 o la API de Amazon EC2. Una vez que haya analizado el historial de precios para su tipo de instancia deseado en una zona de disponibilidad especificada, tendrá dos enfoques alternativos para su solicitud:
+ Especificar una solicitud en el extremo superior del rango de precios de instancias de spot, que aún son inferiores al precio bajo demanda, contando con que lo más probable es que su solicitud de instancia de spot puntual se atienda y se ejecute durante un tiempo de computación consecutivo suficiente para completar la tarea.
+ Especificar una solicitud en el extremo inferior del rango de precios y tener previsto combinar muchas instancias lanzadas con el tiempo a través de una solicitud persistente. Las instancias se ejecutarían el tiempo suficiente, combinadas, para completar la tarea con un costo total aún más reducido

### No pagar un importe superior al valor del resultado
<a name="value-of-result"></a>

Tiene una tarea de procesamiento de datos para ejecutar. Conoce las ventajas de los resultados de la tarea lo suficientemente bien como para saber lo valiosos que son en términos de costos de computación.

Una vez que analizado el historial de precios de instancias de spot del tipo de instancia, elige un precio en el que el costo del tiempo de computación no es superior al valor de los resultados de la tarea. Crea una solicitud persistente y deja que se ejecute intermitentemente a medida que el precio de instancia de spot fluctúa en torno a su solicitud o por debajo de esta.

### Adquirir capacidad de computación con rapidez
<a name="acquire-quickly"></a>

Tiene una necesidad a corto plazo no anticipada de capacidad adicional que no está disponible a través de las instancias bajo demanda. Una vez analizado el historial de precios de instancia de spot del tipo de instancia, elige un precio por encima del precio histórico para mejorar significativamente la probabilidad de que la solicitud se atienda con rapidez y continúe computándose hasta completarse.

Tras reunir todo lo necesario y elegir una estrategia, está listo para solicitar una instancia de spot. En este tutorial, el precio máximo de instancias de spot predeterminado se establece que sea el mismo que el precio bajo demanda (que es 0,003 USD para este tutorial). Establecer el precio de esta manera maximiza las posibilidades de que se cumpla la solicitud.

## Creación de una solicitud de instancia de spot
<a name="tutor-spot-net-submit"></a>

En el siguiente fragmento de código se muestra cómo crear una solicitud de instancia de spot con los elementos que ha reunido anteriormente.

El ejemplo que aparece [al final de este tema](#tutor-spot-net-main) muestra este fragmento de código en uso.

```
    //
    // Method to create a Spot Instance request
    private static async Task<SpotInstanceRequest> CreateSpotInstanceRequest(
      IAmazonEC2 ec2Client, string amiId, string securityGroupName,
      InstanceType instanceType, string spotPrice, int instanceCount)
    {
      var launchSpecification = new LaunchSpecification{
        ImageId = amiId,
        InstanceType = instanceType
      };
      launchSpecification.SecurityGroups.Add(securityGroupName);
      var request = new RequestSpotInstancesRequest{
        SpotPrice = spotPrice,
        InstanceCount = instanceCount,
        LaunchSpecification = launchSpecification
      };

      RequestSpotInstancesResponse result =
        await ec2Client.RequestSpotInstancesAsync(request);
      return result.SpotInstanceRequests[0];
    }
```

El valor importante que devuelve este método es el identificador de solicitud de la instancia puntual, que se encuentra en el `SpotInstanceRequestId` elemento del [SpotInstanceRequest](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TSpotInstanceRequest.html)objeto devuelto.

**nota**  
Se le cobrará por cualquier instancia de spot que se lance. Para evitar costos innecesarios, asegúrese de [cancelar todas las solicitudes](#tutor-spot-net-clean-up-request) y de [terminar cualquier instancia](#tutor-spot-net-clean-up-instance).

## Determinación del estado de la solicitud de instancia de spot
<a name="tutor-spot-net-request-state"></a>

En el siguiente fragmento de código se muestra cómo obtener información sobre la solicitud de instancia de spot. Puede utilizar esa información para tomar algunas decisiones relativas a su código, por ejemplo, si debe seguir esperando a que se atienda una solicitud de instancia de spot.

El ejemplo que aparece [al final de este tema](#tutor-spot-net-main) muestra este fragmento de código en uso.

```
    //
    // Method to get information about a Spot Instance request, including the status,
    // instance ID, etc.
    // It gets the information for a specific request (as opposed to all requests).
    private static async Task<SpotInstanceRequest> GetSpotInstanceRequestInfo(
      IAmazonEC2 ec2Client, string requestId)
    {
      var describeRequest = new DescribeSpotInstanceRequestsRequest();
      describeRequest.SpotInstanceRequestIds.Add(requestId);

      DescribeSpotInstanceRequestsResponse describeResponse =
        await ec2Client.DescribeSpotInstanceRequestsAsync(describeRequest);
      return describeResponse.SpotInstanceRequests[0];
    }
```

El método devuelve información sobre la solicitud de instancia de spot, como el ID de la instancia, su estado y el código de estado. Para obtener más información sobre los códigos de estado de las solicitudes de instancias de spot, consulte [Estado de las solicitudes de spot](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/spot-bid-status.html#spot-instance-bid-status-understand) en la [Guía del usuario de Amazon EC2](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/).

## Limpieza de las solicitudes de instancia de spot
<a name="tutor-spot-net-clean-up-request"></a>

Cuando ya no necesite solicitar instancias de spot, es importante cancelar las solicitudes pendientes para evitar que se vuelvan a atenderse. En el siguiente fragmento de código se muestra cómo cancelar una solicitud de instancia de spot.

El ejemplo que aparece [al final de este tema](#tutor-spot-net-main) muestra este fragmento de código en uso.

```
    //
    // Method to cancel a Spot Instance request
    private static async Task CancelSpotInstanceRequest(
      IAmazonEC2 ec2Client, string requestId)
    {
      var cancelRequest = new CancelSpotInstanceRequestsRequest();
      cancelRequest.SpotInstanceRequestIds.Add(requestId);

      await ec2Client.CancelSpotInstanceRequestsAsync(cancelRequest);
    }
```

## Limpieza de las instancias de spot
<a name="tutor-spot-net-clean-up-instance"></a>

Para no incurrir en costos innecesarios, es importante terminar cualquier instancia que se haya iniciado a partir de solicitudes de instancia de spot; las instancias no terminarán si solamente se cancelan, lo que significa que se le seguirá cobrando por ellas. En el siguiente fragmento de código se muestra cómo terminar una instancia después de obtener el identificador de instancia de una instancia de spot activa.

El ejemplo que aparece [al final de este tema](#tutor-spot-net-main) muestra este fragmento de código en uso.

```
    //
    // Method to terminate a Spot Instance
    private static async Task TerminateSpotInstance(
      IAmazonEC2 ec2Client, string requestId)
    {
      var describeRequest = new DescribeSpotInstanceRequestsRequest();
      describeRequest.SpotInstanceRequestIds.Add(requestId);

      // Retrieve the Spot Instance request to check for running instances.
      DescribeSpotInstanceRequestsResponse describeResponse =
        await ec2Client.DescribeSpotInstanceRequestsAsync(describeRequest);

      // If there are any running instances, terminate them
      if(   (describeResponse.SpotInstanceRequests[0].Status.Code
              == "request-canceled-and-instance-running")
         || (describeResponse.SpotInstanceRequests[0].State == SpotInstanceState.Active))
      {
        TerminateInstancesResponse response =
          await ec2Client.TerminateInstancesAsync(new TerminateInstancesRequest{
            InstanceIds = new List<string>(){
              describeResponse.SpotInstanceRequests[0].InstanceId } });
        foreach (InstanceStateChange item in response.TerminatingInstances)
        {
          Console.WriteLine($"\n  Terminated instance: {item.InstanceId}");
          Console.WriteLine($"  Instance state: {item.CurrentState.Name}\n");
        }
      }
    }
```

## Código completo
<a name="tutor-spot-net-main"></a>

En el siguiente ejemplo de código se utilizan los métodos descritos anteriormente para crear y cancelar una solicitud de instancia de spot y terminar una instancia de spot.

### Referencias de SDK
<a name="w2aac19c15c17c21c43b5b1"></a>

NuGet paquetes:
+ [AWSSDK.EC2](https://www.nuget.org/packages/AWSSDK.EC2)

Elementos de programación:
+ Espacio de nombres [Amazon.EC2](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/NEC2.html)

  [EC2Cliente Class Amazon](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TEC2Client.html)

  Clase [InstanceType](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TInstanceType.html)
+ Espacio de nombres [Amazon.EC2.Model](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/NEC2Model.html)

  Clase [CancelSpotInstanceRequestsRequest](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TCancelSpotInstanceRequestsRequest.html)

  Clase [DescribeSpotInstanceRequestsRequest](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TDescribeSpotInstanceRequestsRequest.html)

  Clase [DescribeSpotInstanceRequestsResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TDescribeSpotInstanceRequestsResponse.html)

  Clase [InstanceStateChange](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TInstanceStateChange.html)

  Clase [LaunchSpecification](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TLaunchSpecification.html)

  Clase [RequestSpotInstancesRequest](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TRequestSpotInstancesRequest.html)

  Clase [RequestSpotInstancesResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TRequestSpotInstancesResponse.html)

  Clase [SpotInstanceRequest](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TSpotInstanceRequest.html)

  Clase [TerminateInstancesRequest](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TTerminateInstancesRequest.html)

  Clase [TerminateInstancesResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TTerminateInstancesResponse.html)

### El código
<a name="w2aac19c15c17c21c43b7b1"></a>

```
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Collections.Generic;
using Amazon.EC2;
using Amazon.EC2.Model;

namespace EC2SpotInstanceRequests
{
  class Program
  {
    static async Task Main(string[] args)
    {
      // Some default values.
      // These could be made into command-line arguments instead.
      var instanceType = InstanceType.T1Micro;
      string securityGroupName = "default";
      string spotPrice = "0.003";
      int instanceCount = 1;

      // Parse the command line arguments
      if((args.Length != 1) || (!args[0].StartsWith("ami-")))
      {
        Console.WriteLine("\nUsage: EC2SpotInstanceRequests ami");
        Console.WriteLine("  ami: the Amazon Machine Image to use for the Spot Instances.");
        return;
      }

      // Create the Amazon EC2 client.
      var ec2Client = new AmazonEC2Client();

      // Create the Spot Instance request and record its ID
      Console.WriteLine("\nCreating spot instance request...");
      var req = await CreateSpotInstanceRequest(
        ec2Client, args[0], securityGroupName, instanceType, spotPrice, instanceCount);
      string requestId = req.SpotInstanceRequestId;

      // Wait for an EC2 Spot Instance to become active
      Console.WriteLine(
        $"Waiting for Spot Instance request with ID {requestId} to become active...");
      int wait = 1;
      var start = DateTime.Now;
      while(true)
      {
        Console.Write(".");

        // Get and check the status to see if the request has been fulfilled.
        var requestInfo = await GetSpotInstanceRequestInfo(ec2Client, requestId);
        if(requestInfo.Status.Code == "fulfilled")
        {
          Console.WriteLine($"\nSpot Instance request {requestId} " +
            $"has been fulfilled by instance {requestInfo.InstanceId}.\n");
          break;
        }

        // Wait a bit and try again, longer each time (1, 2, 4, ...)
        Thread.Sleep(wait);
        wait = wait * 2;
      }

      // Show the user how long it took to fulfill the Spot Instance request.
      TimeSpan span = DateTime.Now.Subtract(start);
      Console.WriteLine($"That took {span.TotalMilliseconds} milliseconds");

      // Perform actions here as needed.
      // For this example, simply wait for the user to hit a key.
      // That gives them a chance to look at the EC2 console to see
      // the running instance if they want to.
      Console.WriteLine("Press any key to start the cleanup...");
      Console.ReadKey(true);

      // Cancel the request.
      // Do this first to make sure that the request can't be re-fulfilled
      // once the Spot Instance has been terminated.
      Console.WriteLine("Canceling Spot Instance request...");
      await CancelSpotInstanceRequest(ec2Client, requestId);

      // Terminate the Spot Instance that's running.
      Console.WriteLine("Terminating the running Spot Instance...");
      await TerminateSpotInstance(ec2Client, requestId);

      Console.WriteLine("Done. Press any key to exit...");
      Console.ReadKey(true);
    }


    //
    // Method to create a Spot Instance request
    private static async Task<SpotInstanceRequest> CreateSpotInstanceRequest(
      IAmazonEC2 ec2Client, string amiId, string securityGroupName,
      InstanceType instanceType, string spotPrice, int instanceCount)
    {
      var launchSpecification = new LaunchSpecification{
        ImageId = amiId,
        InstanceType = instanceType
      };
      launchSpecification.SecurityGroups.Add(securityGroupName);
      var request = new RequestSpotInstancesRequest{
        SpotPrice = spotPrice,
        InstanceCount = instanceCount,
        LaunchSpecification = launchSpecification
      };

      RequestSpotInstancesResponse result =
        await ec2Client.RequestSpotInstancesAsync(request);
      return result.SpotInstanceRequests[0];
    }


    //
    // Method to get information about a Spot Instance request, including the status,
    // instance ID, etc.
    // It gets the information for a specific request (as opposed to all requests).
    private static async Task<SpotInstanceRequest> GetSpotInstanceRequestInfo(
      IAmazonEC2 ec2Client, string requestId)
    {
      var describeRequest = new DescribeSpotInstanceRequestsRequest();
      describeRequest.SpotInstanceRequestIds.Add(requestId);

      DescribeSpotInstanceRequestsResponse describeResponse =
        await ec2Client.DescribeSpotInstanceRequestsAsync(describeRequest);
      return describeResponse.SpotInstanceRequests[0];
    }


    //
    // Method to cancel a Spot Instance request
    private static async Task CancelSpotInstanceRequest(
      IAmazonEC2 ec2Client, string requestId)
    {
      var cancelRequest = new CancelSpotInstanceRequestsRequest();
      cancelRequest.SpotInstanceRequestIds.Add(requestId);

      await ec2Client.CancelSpotInstanceRequestsAsync(cancelRequest);
    }


    //
    // Method to terminate a Spot Instance
    private static async Task TerminateSpotInstance(
      IAmazonEC2 ec2Client, string requestId)
    {
      var describeRequest = new DescribeSpotInstanceRequestsRequest();
      describeRequest.SpotInstanceRequestIds.Add(requestId);

      // Retrieve the Spot Instance request to check for running instances.
      DescribeSpotInstanceRequestsResponse describeResponse =
        await ec2Client.DescribeSpotInstanceRequestsAsync(describeRequest);

      // If there are any running instances, terminate them
      if(   (describeResponse.SpotInstanceRequests[0].Status.Code
              == "request-canceled-and-instance-running")
         || (describeResponse.SpotInstanceRequests[0].State == SpotInstanceState.Active))
      {
        TerminateInstancesResponse response =
          await ec2Client.TerminateInstancesAsync(new TerminateInstancesRequest{
            InstanceIds = new List<string>(){
              describeResponse.SpotInstanceRequests[0].InstanceId } });
        foreach (InstanceStateChange item in response.TerminatingInstances)
        {
          Console.WriteLine($"\n  Terminated instance: {item.InstanceId}");
          Console.WriteLine($"  Instance state: {item.CurrentState.Name}\n");
        }
      }
    }
  }
}
```

## Consideraciones adicionales
<a name="tutor-spot-net-additional"></a>
+ Tras ejecutar el tutorial, se recomienda iniciar sesión en la [consola de Amazon EC2](https://console.aws.amazon.com/ec2/) para confirmar que la [solicitud de instancia de spot](https://console.aws.amazon.com/ec2/home#SpotInstances:) se ha cancelado y que la [instancia de spot](https://console.aws.amazon.com/ec2/v2/home#Instances) se ha terminado.

# Acceder AWS Identity and Access Management (IAM) con el AWS SDK para .NET
<a name="iam-apis-intro"></a>

The AWS SDK para .NET supports [AWS Identity and Access Management](https://docs.aws.amazon.com/IAM/latest/UserGuide/), que es un servicio web que permite a AWS los clientes gestionar los usuarios y los permisos de los usuarios AWS.

Un *usuario AWS Identity and Access Management * (IAM) es una entidad en AWS la que se crea. La entidad representa a una persona o aplicación con la que interactúa. AWS Para obtener más información sobre los usuarios de IAM, consulte [Usuarios de IAM](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_users.html) e [IAM y cuotas de AWS STS](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-limits.html) en la Guía del usuario de IAM.

Para conceder permisos a un usuario, hay que crear una *política* de IAM. Una política es un *documento de política* que incluye una lista de las acciones que un usuario puede realizar y los recursos a los que pueden afectar dichas acciones. Para obtener más información sobre las políticas de IAM, consulte [Políticas y permisos](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html) en la *Guía del usuario de IAM*.

**aviso**  
Para evitar riesgos de seguridad, no utilice a los usuarios de IAM para la autenticación cuando desarrolle software especialmente diseñado o trabaje con datos reales. En cambio, utilice la federación con un proveedor de identidades como [AWS IAM Identity Center](https://docs.aws.amazon.com/singlesignon/latest/userguide/what-is.html).

## APIs
<a name="w2aac19c15c19c13"></a>

Los proveedores son AWS SDK para .NET APIs para los clientes de IAM. Le APIs permiten trabajar con funciones de IAM, como usuarios, roles y claves de acceso.

Esta sección contiene una pequeña cantidad de ejemplos que muestran los patrones que puede seguir al trabajar con ellos APIs. Para ver el conjunto completo de APIs, consulta la [referencia de la AWS SDK para .NET API](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/) (y desplázate hasta «Amazon. IdentityManagement«).

En esta sección también se incluye [un ejemplo](net-dg-hosm.md) que muestra cómo asociar un rol de IAM a instancias de Amazon EC2 para administrar las credenciales más fácilmente.

[Los IAM APIs los proporciona elAWSSDK. IdentityManagement](https://www.nuget.org/packages/AWSSDK.IdentityManagement) NuGetpaquete.

## Requisitos previos
<a name="w2aac19c15c19c15"></a>

Antes de comenzar, asegúrese de que ha [configurado el entorno y el proyecto](net-dg-config.md). Revise también la información en [Características de SDK](net-dg-sdk-features.md).

## Temas
<a name="w2aac19c15c19c17"></a>

**Topics**
+ [

## APIs
](#w2aac19c15c19c13)
+ [

## Requisitos previos
](#w2aac19c15c19c15)
+ [

## Temas
](#w2aac19c15c19c17)
+ [Creación de políticas administradas a partir de JSON](iam-policies-create-json.md)
+ [Visualización de documentos de política](iam-policies-display.md)
+ [Concesión de acceso con un rol](net-dg-hosm.md)

# Creación de políticas administradas de IAM a partir de JSON
<a name="iam-policies-create-json"></a>

En este ejemplo, se muestra cómo utilizarla AWS SDK para .NET para crear una [política gestionada de IAM](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_managed-vs-inline.html#aws-managed-policies) a partir de un documento de política determinado en JSON. La aplicación crea un objeto de cliente de IAM, lee el documento de política de un archivo y, a continuación, crea la política.

**nota**  
Para ver un ejemplo de documento de política en JSON, consulte la sección [Consideraciones adicionales](#iam-policies-create-json-additional) al final de este tema.

En las siguientes secciones se proporcionan fragmentos de código de este ejemplo. Tras ello, se muestra el [código completo del ejemplo](#iam-policies-create-json-complete-code), que se puede compilar y ejecutar tal cual.

**Topics**
+ [

## Creación de la política
](#iam-policies-create-json-create)
+ [

## Código completo
](#iam-policies-create-json-complete-code)
+ [

## Consideraciones adicionales
](#iam-policies-create-json-additional)

## Creación de la política
<a name="iam-policies-create-json-create"></a>

El siguiente fragmento de código crea una política administrada de IAM con el nombre y el documento de política especificados.

El ejemplo que aparece [al final de este tema](#iam-policies-create-json-complete-code) muestra este fragmento de código en uso.

```
    //
    // Method to create an IAM policy from a JSON file
    private static async Task<CreatePolicyResponse> CreateManagedPolicy(
      IAmazonIdentityManagementService iamClient, string policyName, string jsonFilename)
    {
      return await iamClient.CreatePolicyAsync(new CreatePolicyRequest{
        PolicyName = policyName,
        PolicyDocument = File.ReadAllText(jsonFilename)});
    }
```

## Código completo
<a name="iam-policies-create-json-complete-code"></a>

En esta sección se muestran las referencias relevantes y el código completo de este ejemplo.

### Referencias de SDK
<a name="w2aac19c15c19c21c17b5b1"></a>

NuGet paquetes:
+ [AWSSDK.IdentityManagement](https://www.nuget.org/packages/AWSSDK.IdentityManagement)

Elementos de programación:
+ [Espacio de nombres Amazon. IdentityManagement](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/IAM/NIAM.html)

  Clase [AmazonIdentityManagementServiceClient](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/IAM/TIAMServiceClient.html)
+ [Espacio de nombres Amazon. IdentityManagement](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/IAM/NIAMModel.html).Modelo

  Clase [CreatePolicyRequest](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/IAM/TCreatePolicyRequest.html)

  Clase [CreatePolicyResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/IAM/TCreatePolicyResponse.html)

### El código
<a name="w2aac19c15c19c21c17b7b1"></a>

```
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using Amazon.IdentityManagement;
using Amazon.IdentityManagement.Model;

namespace IamCreatePolicyFromJson
{
  // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  // Class to create an IAM policy with a given policy document
  class Program
  {
    private const int MaxArgs = 2;

    static async Task Main(string[] args)
    {
      // Parse the command line and show help if necessary
      var parsedArgs = CommandLine.Parse(args);
      if((parsedArgs.Count == 0) || (parsedArgs.Count > MaxArgs))
      {
        PrintHelp();
        return;
      }

      // Get the application arguments from the parsed list
      string policyName =
        CommandLine.GetArgument(parsedArgs, null, "-p", "--policy-name");
      string policyFilename =
        CommandLine.GetArgument(parsedArgs, null, "-j", "--json-filename");
      if(   string.IsNullOrEmpty(policyName)
         || (string.IsNullOrEmpty(policyFilename) || !policyFilename.EndsWith(".json")))
        CommandLine.ErrorExit(
          "\nOne or more of the required arguments is missing or incorrect." +
          "\nRun the command with no arguments to see help.");

      // Create an IAM service client
      var iamClient = new AmazonIdentityManagementServiceClient();

      // Create the new policy
      var response = await CreateManagedPolicy(iamClient, policyName, policyFilename);
      Console.WriteLine($"\nPolicy {response.Policy.PolicyName} has been created.");
      Console.WriteLine($"  Arn: {response.Policy.Arn}");
    }


    //
    // Method to create an IAM policy from a JSON file
    private static async Task<CreatePolicyResponse> CreateManagedPolicy(
      IAmazonIdentityManagementService iamClient, string policyName, string jsonFilename)
    {
      return await iamClient.CreatePolicyAsync(new CreatePolicyRequest{
        PolicyName = policyName,
        PolicyDocument = File.ReadAllText(jsonFilename)});
    }


    //
    // Command-line help
    private static void PrintHelp()
    {
      Console.WriteLine(
        "\nUsage: IamCreatePolicyFromJson -p <policy-name> -j <json-filename>" +
        "\n  -p, --policy-name: The name you want the new policy to have." +
        "\n  -j, --json-filename: The name of the JSON file with the policy document.");
    }
  }


  // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  // Class that represents a command line on the console or terminal.
  // (This is the same for all examples. When you have seen it once, you can ignore it.)
  static class CommandLine
  {
    //
    // Method to parse a command line of the form: "--key value" or "-k value".
    //
    // Parameters:
    // - args: The command-line arguments passed into the application by the system.
    //
    // Returns:
    // A Dictionary with string Keys and Values.
    //
    // If a key is found without a matching value, Dictionary.Value is set to the key
    //  (including the dashes).
    // If a value is found without a matching key, Dictionary.Key is set to "--NoKeyN",
    //  where "N" represents sequential numbers.
    public static Dictionary<string,string> Parse(string[] args)
    {
      var parsedArgs = new Dictionary<string,string>();
      int i = 0, n = 0;
      while(i < args.Length)
      {
        // If the first argument in this iteration starts with a dash it's an option.
        if(args[i].StartsWith("-"))
        {
          var key = args[i++];
          var value = key;

          // Check to see if there's a value that goes with this option?
          if((i < args.Length) && (!args[i].StartsWith("-"))) value = args[i++];
          parsedArgs.Add(key, value);
        }

        // If the first argument in this iteration doesn't start with a dash, it's a value
        else
        {
          parsedArgs.Add("--NoKey" + n.ToString(), args[i++]);
          n++;
        }
      }

      return parsedArgs;
    }

    //
    // Method to get an argument from the parsed command-line arguments
    //
    // Parameters:
    // - parsedArgs: The Dictionary object returned from the Parse() method (shown above).
    // - defaultValue: The default string to return if the specified key isn't in parsedArgs.
    // - keys: An array of keys to look for in parsedArgs.
    public static string GetArgument(
      Dictionary<string,string> parsedArgs, string defaultReturn, params string[] keys)
    {
      string retval = null;
      foreach(var key in keys)
        if(parsedArgs.TryGetValue(key, out retval)) break;
      return retval ?? defaultReturn;
    }

    //
    // Method to exit the application with an error.
    public static void ErrorExit(string msg, int code=1)
    {
      Console.WriteLine("\nError");
      Console.WriteLine(msg);
      Environment.Exit(code);
    }
  }

}
```

## Consideraciones adicionales
<a name="iam-policies-create-json-additional"></a>
+ El siguiente es un ejemplo de documento de política que se puede copiar en un archivo JSON y utilizar como entrada para esta aplicación:

------
#### [ JSON ]

****  

  ```
  {
    "Version":"2012-10-17",		 	 	 
    "Id"  : "DotnetTutorialPolicy",
    "Statement" : [
      {
        "Sid" : "DotnetTutorialPolicyS3",
        "Effect" : "Allow",
        "Action" : [
          "s3:Get*",
          "s3:List*"
        ],
        "Resource" : "*"
      },
      {
        "Sid" : "DotnetTutorialPolicyPolly",
        "Effect": "Allow",
        "Action": [
          "polly:DescribeVoices",
          "polly:SynthesizeSpeech"
        ],
        "Resource": "*"
      }
    ]
  }
  ```

------
+ Para confirmar que la política se ha creado, consulte la [consola de IAM](https://console.aws.amazon.com/iam/home#/policies). En la lisa desplegable **Filtrar políticas**, seleccione **Administrado por el cliente**. Elimine la política cuando ya no la necesite.
+  Para obtener más información sobre la creación de políticas, consulte [Crear políticas de IAM](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_create.html) y la [Referencia de políticas JSON de IAM](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies.html) en la [Guía del usuario de IAM](https://docs.aws.amazon.com/IAM/latest/UserGuide/).

# Visualización del documento de política de una política administrada de IAM
<a name="iam-policies-display"></a>

En este ejemplo, se muestra cómo utilizar el AWS SDK para .NET para mostrar un documento de política. La aplicación crea un objeto de cliente de IAM, busca la versión predeterminada de la política administrada de IAM indicada y, a continuación, muestra el documento de política en JSON.

En las siguientes secciones se proporcionan fragmentos de código de este ejemplo. Tras ello, se muestra el [código completo del ejemplo](#iam-policies-display-complete-code), que se puede compilar y ejecutar tal cual.

**Topics**
+ [

## Búsqueda de la versión predeterminada
](#iam-policies-display-version)
+ [

## Visualización del documento de política
](#iam-policies-display-doc)
+ [

## Código completo
](#iam-policies-display-complete-code)

## Búsqueda de la versión predeterminada
<a name="iam-policies-display-version"></a>

En el siguiente fragmento de código se busca la versión predeterminada de la política de IAM indicada.

El ejemplo que aparece [al final de este tema](#iam-policies-display-complete-code) muestra este fragmento de código en uso.

```
    //
    // Method to determine the default version of an IAM policy
    // Returns a string with the version
    private static async Task<string> GetDefaultVersion(
      IAmazonIdentityManagementService iamClient, string policyArn)
    {
      // Retrieve all the versions of this policy
      string defaultVersion = string.Empty;
      ListPolicyVersionsResponse reponseVersions =
        await iamClient.ListPolicyVersionsAsync(new ListPolicyVersionsRequest{
          PolicyArn = policyArn});

      // Find the default version
      foreach(PolicyVersion version in reponseVersions.Versions)
      {
        if(version.IsDefaultVersion)
        {
          defaultVersion = version.VersionId;
          break;
        }
      }

      return defaultVersion;
    }
```

## Visualización del documento de política
<a name="iam-policies-display-doc"></a>

El siguiente fragmento de código muestra el documento de política en JSON de la política de IAM indicada.

El ejemplo que aparece [al final de este tema](#iam-policies-display-complete-code) muestra este fragmento de código en uso.

```
    //
    // Method to retrieve and display the policy document of an IAM policy
    private static async Task ShowPolicyDocument(
      IAmazonIdentityManagementService iamClient, string policyArn, string defaultVersion)
    {
      // Retrieve the policy document of the default version
      GetPolicyVersionResponse responsePolicy =
        await iamClient.GetPolicyVersionAsync(new GetPolicyVersionRequest{
          PolicyArn = policyArn,
          VersionId = defaultVersion});

      // Display the policy document (in JSON)
      Console.WriteLine($"Version {defaultVersion} of the policy (in JSON format):");
      Console.WriteLine(
        $"{HttpUtility.UrlDecode(responsePolicy.PolicyVersion.Document)}");
    }
```

## Código completo
<a name="iam-policies-display-complete-code"></a>

En esta sección se muestran las referencias relevantes y el código completo de este ejemplo.

### Referencias de SDK
<a name="w2aac19c15c19c23c19b5b1"></a>

NuGet paquetes:
+ [AWSSDK.IdentityManagement](https://www.nuget.org/packages/AWSSDK.IdentityManagement)

Elementos de programación:
+ [Espacio de nombres Amazon. IdentityManagement](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/IAM/NIAM.html)

  Clase [AmazonIdentityManagementServiceClient](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/IAM/TIAMServiceClient.html)
+ [Espacio de nombres Amazon. IdentityManagement](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/IAM/NIAMModel.html).Modelo

  Clase [GetPolicyVersionRequest](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/IAM/TGetPolicyVersionRequest.html)

  Clase [GetPolicyVersionResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/IAM/TGetPolicyVersionResponse.html)

  Clase [ListPolicyVersionsRequest](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/IAM/TListPolicyVersionsRequest.html)

  Clase [ListPolicyVersionsResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/IAM/TListPolicyVersionsResponse.html)

  Clase [PolicyVersion](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/IAM/TPolicyVersion.html)

### El código
<a name="w2aac19c15c19c23c19b7b1"></a>

```
using System;
using System.Web;
using System.Threading.Tasks;
using Amazon.IdentityManagement;
using Amazon.IdentityManagement.Model;

namespace IamDisplayPolicyJson
{
  class Program
  {
    static async Task Main(string[] args)
    {
      // Parse the command line and show help if necessary
      if(args.Length != 1)
      {
        Console.WriteLine("\nUsage: IamDisplayPolicyJson policy-arn");
        Console.WriteLine("   policy-arn: The ARN of the policy to retrieve.");
        return;
      }
      if(!args[0].StartsWith("arn:"))
      {
        Console.WriteLine("\nCould not find policy ARN in the command-line arguments:");
        Console.WriteLine($"{args[0]}");
        return;
      }

      // Create an IAM service client
      var iamClient = new AmazonIdentityManagementServiceClient();

      // Retrieve and display the policy document of the given policy
      string defaultVersion = await GetDefaultVersion(iamClient, args[0]);
      if(string.IsNullOrEmpty(defaultVersion))
        Console.WriteLine($"Could not find the default version for policy {args[0]}.");
      else
        await ShowPolicyDocument(iamClient, args[0], defaultVersion);
    }


    //
    // Method to determine the default version of an IAM policy
    // Returns a string with the version
    private static async Task<string> GetDefaultVersion(
      IAmazonIdentityManagementService iamClient, string policyArn)
    {
      // Retrieve all the versions of this policy
      string defaultVersion = string.Empty;
      ListPolicyVersionsResponse reponseVersions =
        await iamClient.ListPolicyVersionsAsync(new ListPolicyVersionsRequest{
          PolicyArn = policyArn});

      // Find the default version
      foreach(PolicyVersion version in reponseVersions.Versions)
      {
        if(version.IsDefaultVersion)
        {
          defaultVersion = version.VersionId;
          break;
        }
      }

      return defaultVersion;
    }


    //
    // Method to retrieve and display the policy document of an IAM policy
    private static async Task ShowPolicyDocument(
      IAmazonIdentityManagementService iamClient, string policyArn, string defaultVersion)
    {
      // Retrieve the policy document of the default version
      GetPolicyVersionResponse responsePolicy =
        await iamClient.GetPolicyVersionAsync(new GetPolicyVersionRequest{
          PolicyArn = policyArn,
          VersionId = defaultVersion});

      // Display the policy document (in JSON)
      Console.WriteLine($"Version {defaultVersion} of the policy (in JSON format):");
      Console.WriteLine(
        $"{HttpUtility.UrlDecode(responsePolicy.PolicyVersion.Document)}");
    }
  }
}
```

# Concesión de acceso mediante un rol de IAM
<a name="net-dg-hosm"></a>

En este tutorial, se muestra cómo utilizarlos AWS SDK para .NET para habilitar las funciones de IAM en las instancias de Amazon EC2.

## Descripción general de
<a name="hosm-overview"></a>

Todas las solicitudes AWS deben estar firmadas criptográficamente con las credenciales emitidas por. AWS Por tanto, se necesita una estrategia para administrar las credenciales de las aplicaciones que se ejecutan en instancias de Amazon EC2. Debe distribuir, almacenar y rotar estas credenciales de forma segura, pero también mantenerlas accesibles en las aplicaciones.

Con los roles de IAM, estas credenciales se pueden administrar de forma eficaz. Debe crear un rol de IAM y configurarlo con los permisos que una aplicación requiere y, a continuación, asociar ese rol a una instancia de EC2. Para obtener más información sobre las ventajas de usar roles de IAM, consulte [Roles de IAM para Amazon EC2](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html) en la [Guía del usuario de Amazon EC2](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/). Consulte también la información sobre [roles de IAM](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles.html) de la Guía del usuario de IAM.

En el caso de una aplicación creada con el AWS SDK para .NET, cuando la aplicación crea un objeto de cliente para un AWS servicio, el objeto busca credenciales de varias fuentes posibles. En [Resolución de credenciales y perfil](creds-assign.md) se muestra el orden de la búsqueda.

Si el objeto de cliente no encuentra credenciales en ningún origen, recupera unas credenciales temporales que tienen los mismos permisos que los asociados al rol de IAM y que están en los metadatos de la instancia de EC2. Estas credenciales se utilizan para realizar llamadas AWS desde el objeto cliente.

## Acerca de este tutorial
<a name="about-hosm-tutorial"></a>

Al seguir este tutorial, utilizará la AWS SDK para .NET (y otras herramientas) para lanzar una instancia de Amazon EC2 con una función de IAM asociada y, a continuación, verá una aplicación en la instancia que utilice los permisos de la función de IAM.

**Topics**
+ [

## Descripción general de
](#hosm-overview)
+ [

## Acerca de este tutorial
](#about-hosm-tutorial)
+ [

## Creación de una aplicación de Amazon S3 de ejemplo
](#net-dg-hosm-sample-s3-app)
+ [

## Creación de un rol de IAM
](#net-dg-hosm-create-the-role)
+ [

## Lanzamiento de una instancia de EC2 y asociación del rol de IAM
](#net-dg-hosm-launch-ec2-instance)
+ [

## Conexión a la instancia EC2
](#net-dg-hosm-connect)
+ [

## Ejecutar la aplicación de muestra en la instancia EC2
](#net-dg-hosm-run-the-app)
+ [

## Limpieza
](#net-dg-hosm-cleanup)

## Creación de una aplicación de Amazon S3 de ejemplo
<a name="net-dg-hosm-sample-s3-app"></a>

Esta aplicación de ejemplo recupera un objeto de Amazon S3. Para ejecutar la aplicación de ejemplo, necesita lo siguiente:
+ Un bucket de Amazon S3 que contiene un archivo de texto
+ AWS credenciales de su máquina de desarrollo que le permiten acceder al depósito.

Para obtener información acerca de cómo crear un bucket de Amazon S3 y cómo cargar un archivo, consulte [Guía del usuario de Amazon Simple Storage Service](https://docs.aws.amazon.com/AmazonS3/latest/userguide/). Para obtener información sobre AWS las credenciales, consulte[Configure la autenticación del SDK con AWS](creds-idc.md).

Cree un proyecto .NET Core con el siguiente código. A continuación, pruebe la aplicación en el equipo de desarrollo.

**nota**  
En el equipo de desarrollo está instalado el tiempo de ejecución de .NET Core, que permite ejecutar la aplicación sin publicarla. Al crear una instancia de EC2 más adelante en este tutorial, puede optar por instalar el tiempo de ejecución de .NET Core en esa instancia. Esto le proporciona una experiencia similar, y la transferencia de archivos es más pequeña.  
 Sin embargo, también puede optar por no instalar el tiempo de ejecución de .NET Core en la instancia. Si se decanta por esta opción, debe publicar la aplicación de forma que se incluya todas las dependencias al transferirla a la instancia.

### Referencias de SDK
<a name="w2aac19c15c19c25c17c13b1"></a>

NuGet paquetes:
+ [AWSSDKS.3](https://www.nuget.org/packages/AWSSDK.S3)

Elementos de programación:
+ Espacio de nombres [Amazon.S3](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/S3/NS3.html)

  Clase [AmazonS3Client](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/S3/TS3Client.html)
+ Espacio de nombres [Amazon.S3.Model](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/S3/NS3Model.html)

  Clase [GetObjectResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/S3/TGetObjectResponse.html)

### El código
<a name="w2aac19c15c19c25c17c15b1"></a>

```
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using Amazon.S3;
using Amazon.S3.Model;

namespace S3GetTextItem
{
  // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  // Class to retrieve a text file from an S3 bucket and write it to a local file
  class Program
  {
    static async Task Main(string[] args)
    {
      // Parse the command line and show help if necessary
      var parsedArgs = CommandLine.Parse(args);
      if(parsedArgs.Count == 0)
      {
        PrintHelp();
        return;
      }

      // Get the application arguments from the parsed list
      string bucket =
        CommandLine.GetArgument(parsedArgs, null, "-b", "--bucket-name");
      string item =
        CommandLine.GetArgument(parsedArgs, null, "-t", "--text-object");
      string outFile =
        CommandLine.GetArgument(parsedArgs, null, "-o", "--output-filename");
      if(   string.IsNullOrEmpty(bucket)
         || string.IsNullOrEmpty(item)
         || string.IsNullOrEmpty(outFile))
        CommandLine.ErrorExit(
          "\nOne or more of the required arguments is missing or incorrect." +
          "\nRun the command with no arguments to see help.");

      // Create the S3 client object and get the file object from the bucket.
      var response = await GetObject(new AmazonS3Client(), bucket, item);

      // Write the contents of the file object to the given output file.
      var reader = new StreamReader(response.ResponseStream);
      string contents = reader.ReadToEnd();
      using (var s = new FileStream(outFile, FileMode.Create))
      using (var writer = new StreamWriter(s))
        writer.WriteLine(contents);
    }


    //
    // Method to get an object from an S3 bucket.
    private static async Task<GetObjectResponse> GetObject(
      IAmazonS3 s3Client, string bucket, string item)
    {
        Console.WriteLine($"Retrieving {item} from bucket {bucket}.");
        return await s3Client.GetObjectAsync(bucket, item);
    }


    //
    // Command-line help
    private static void PrintHelp()
    {
      Console.WriteLine(
        "\nUsage: S3GetTextItem -b <bucket-name> -t <text-object> -o <output-filename>" +
        "\n  -b, --bucket-name: The name of the S3 bucket." +
        "\n  -t, --text-object: The name of the text object in the bucket." +
        "\n  -o, --output-filename: The name of the file to write the text to.");
    }
  }


  // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  // Class that represents a command line on the console or terminal.
  // (This is the same for all examples. When you have seen it once, you can ignore it.)
  static class CommandLine
  {
    //
    // Method to parse a command line of the form: "--key value" or "-k value".
    //
    // Parameters:
    // - args: The command-line arguments passed into the application by the system.
    //
    // Returns:
    // A Dictionary with string Keys and Values.
    //
    // If a key is found without a matching value, Dictionary.Value is set to the key
    //  (including the dashes).
    // If a value is found without a matching key, Dictionary.Key is set to "--NoKeyN",
    //  where "N" represents sequential numbers.
    public static Dictionary<string,string> Parse(string[] args)
    {
      var parsedArgs = new Dictionary<string,string>();
      int i = 0, n = 0;
      while(i < args.Length)
      {
        // If the first argument in this iteration starts with a dash it's an option.
        if(args[i].StartsWith("-"))
        {
          var key = args[i++];
          var value = key;

          // Check to see if there's a value that goes with this option?
          if((i < args.Length) && (!args[i].StartsWith("-"))) value = args[i++];
          parsedArgs.Add(key, value);
        }

        // If the first argument in this iteration doesn't start with a dash, it's a value
        else
        {
          parsedArgs.Add("--NoKey" + n.ToString(), args[i++]);
          n++;
        }
      }

      return parsedArgs;
    }

    //
    // Method to get an argument from the parsed command-line arguments
    //
    // Parameters:
    // - parsedArgs: The Dictionary object returned from the Parse() method (shown above).
    // - defaultValue: The default string to return if the specified key isn't in parsedArgs.
    // - keys: An array of keys to look for in parsedArgs.
    public static string GetArgument(
      Dictionary<string,string> parsedArgs, string defaultReturn, params string[] keys)
    {
      string retval = null;
      foreach(var key in keys)
        if(parsedArgs.TryGetValue(key, out retval)) break;
      return retval ?? defaultReturn;
    }

    //
    // Method to exit the application with an error.
    public static void ErrorExit(string msg, int code=1)
    {
      Console.WriteLine("\nError");
      Console.WriteLine(msg);
      Environment.Exit(code);
    }
  }

}
```

Si lo desea, puede eliminar temporalmente las credenciales que use en el equipo de desarrollo para ver cómo responde la aplicación (no se olvide de restaurarlas cuando acabe).

## Creación de un rol de IAM
<a name="net-dg-hosm-create-the-role"></a>

Cree un rol de IAM que tenga los permisos adecuados para obtener acceso a Amazon S3.

1. Abra la [consola de IAM](https://console.aws.amazon.com/iam/).

1. En el panel de navegación, seleccione **Roles** y luego seleccione **Crear rol**.

1. Seleccione **Servicio de AWS **, busque y seleccione **EC2** y seleccione **Siguiente: Permisos**.

1. En **Adjuntar políticas de permisos**, busca y selecciona **AmazonS3 ReadOnlyAccess**. Revise la política si lo desea y, a continuación, seleccione **Siguiente: Etiquetas**.

1. Agregue etiquetas si lo desea y, a continuación, seleccione **Siguiente: Revisar**.

1. Escriba un nombre y una descripción para el rol y, a continuación, elija **Crear rol**. Recuerde este nombre, ya que lo necesitará cuando lance su instancia EC2.

## Lanzamiento de una instancia de EC2 y asociación del rol de IAM
<a name="net-dg-hosm-launch-ec2-instance"></a>

Lance una instancia de EC2 con el rol de IAM que creó anteriormente. Puede hacerlo de las siguientes maneras:
+ **Con la consola de EC2**

  Para iniciar una instancia mediante la consola de EC2, consulte [Inicialización de una instancia con el nuevo asistente de inicialización de instancias](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-launch-instance-wizard.html) en la [Guía del usuario de Amazon EC2](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/).

  Al revisar la página de inicio, al menos deberá expandir el panel **Detalles avanzados** para que pueda especificar el rol de IAM que creó anteriormente en el **perfil de instancia de IAM**.
+ **Usando el AWS SDK para .NET**

  Para obtener información al respecto, consulte [Lanzamiento de una instancia de Amazon EC2](run-instance.md), así como la sección [Consideraciones adicionales](run-instance.md#run-instance-additional) al final de ese tema.

Para lanzar una instancia de EC2 que tenga un rol de IAM asociado, la configuración de un usuario de IAM debe incluir determinados permisos. Para obtener más información sobre los permisos necesarios, consulte la sección [Concesión de permisos a un usuario para transferir un rol de IAM a una instancia](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html#permission-to-pass-iam-roles) en la [Guía del usuario de Amazon EC2](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/).

## Conexión a la instancia EC2
<a name="net-dg-hosm-connect"></a>

Conéctese a la instancia EC2 para poder transferirle la aplicación de muestra y luego ejecutarla. Necesitarás el archivo que contiene la parte privada del par de claves que usaste para lanzar la instancia, es decir, el archivo PEM.

Para obtener más información acerca de cómo conectarse a una instancia, consulte [Conexión con la instancia de Linux](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/connect-to-linux-instance.html) o [Conexión con la instancia de Windows](https://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/connecting_to_windows_instance.html) en la [Guía del usuario de Amazon EC2](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/). Cuando se conecte, hágalo de forma que pueda transferir archivos desde el equipo de desarrollo a la instancia.

Si usa Visual Studio en Windows, también se puede conectar a la instancia mediante el Kit de herramientas para Visual Studio. Para obtener más información, consulte [Conexión a una instancia de Amazon EC2](https://docs.aws.amazon.com/toolkit-for-visual-studio/latest/user-guide/tkv-ec2-ami.html#connect-ec2) en la Guía del AWS Toolkit for Visual Studio usuario.

## Ejecutar la aplicación de muestra en la instancia EC2
<a name="net-dg-hosm-run-the-app"></a>

1. Copie los archivos de la aplicación de la unidad local en la instancia.

   Los archivos que transfiera dependen de cómo se haya creado la aplicación y de si la instancia tiene instalado el tiempo de ejecución de .NET Core. Para obtener información sobre cómo transferir archivos a su instancia, consulte [Conexión con la instancia de Linux](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/connect-to-linux-instance.html) (consulte la subsección correspondiente) o [Transferencia de archivos a instancias de Windows](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/connect-to-linux-instanceWindowsFileTransfer.html) en la [Guía del usuario de Amazon EC2](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/).

1. Inicie la aplicación y compruebe que se ejecuta con los mismos resultados que en el equipo de desarrollo.

1. Confirme que la aplicación usa las credenciales proporcionadas por el rol de IAM.

   1. Abra la [consola de Amazon EC2](https://console.aws.amazon.com/ec2/).

   1. Seleccione la instancia y desasocie el rol de IAM mediante **Acciones**, **Configuración de la instancia**. **Asociar o reemplazar rol de IAM**.

   1. Vuelva a ejecutar la aplicación y vea que devuelve un error de autorización.

## Limpieza
<a name="net-dg-hosm-cleanup"></a>

Cuando acabe este tutorial, si ya no quiere conservar la instancia de EC2 que ha creado, asegúrese de terminarla para no incurrir en costos no deseados. Puede hacerlo en la [consola de Amazon EC2](https://console.aws.amazon.com/ec2/) o mediante programación, tal y como se describe en [Terminación de una instancia de Amazon EC2](terminate-instance.md). Si lo desea, también puede eliminar otros recursos que haya creado durante este tutorial. Estos pueden englobar un rol de IAM, un par de claves de EC2 y un archivo PEM, un grupo de seguridad, etc.

# Uso del servicio de almacenamiento de Internet de Amazon Simple Storage Service
<a name="s3-apis-intro"></a>

 AWS SDK para .NET Es compatible con [Amazon S3](https://aws.amazon.com/s3/), que es almacenamiento para Internet. Está diseñado para facilitar a los desarrolladores recursos de computación escalables basados en Web.

## APIs
<a name="w2aac19c15c21b5"></a>

Los proveedores AWS SDK para .NET son APIs para los clientes de Amazon S3. Le APIs permiten trabajar con los recursos de Amazon S3, como depósitos y elementos. Para ver el conjunto completo APIs de Amazon S3, consulte lo siguiente:
+ [AWS SDK para .NET Referencia de API](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/) (y desplázate hasta «Amazon.S3").
+ Documentación de [Amazon.Extensions.S3.Encryption](https://aws.github.io/amazon-s3-encryption-client-dotnet/api/Amazon.Extensions.S3.Encryption.html)

Los Amazon S3 APIs vienen incluidos en los siguientes NuGet paquetes:
+ [AWSSDKS.3](https://www.nuget.org/packages/AWSSDK.S3)
+ [Amazon.Extensions.S3.Encryption](https://www.nuget.org/packages/Amazon.Extensions.S3.Encryption)

## Requisitos previos
<a name="w2aac19c15c21b7"></a>

Antes de comenzar, asegúrese de que ha [configurado el entorno y el proyecto](net-dg-config.md). Revise también la información en [Características de SDK](net-dg-sdk-features.md).

## Ejemplos en este documento
<a name="s3-apis-examples"></a>

Los siguientes temas de este documento muestran cómo utilizarlos AWS SDK para .NET para trabajar con Amazon S3.
+ [Uso de claves de KMS para el cifrado de S3](kms-keys-s3-encryption.md)

## Ejemplos en otros documentos
<a name="s3-apis-examples-other"></a>

Los siguientes enlaces a la [guía para desarrolladores de Amazon S3](https://docs.aws.amazon.com/AmazonS3/latest/userguide/) proporcionan ejemplos adicionales de cómo utilizarla AWS SDK para .NET para trabajar con Amazon S3.

**nota**  
Si bien estos ejemplos y otras consideraciones de programación se crearon para la versión 3 de la versión que AWS SDK para .NET utiliza .NET Framework, también son válidos para versiones posteriores de la versión que AWS SDK para .NET utiliza .NET Core. A veces es necesario realizar pequeños ajustes en el código.

**Ejemplos de programación de Amazon S3**
+  [Administrar ACLs](https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-using-dot-net-sdk.html) 
+  [Creación de un bucket](https://docs.aws.amazon.com/AmazonS3/latest/dev/create-bucket-get-location-example.html#create-bucket-get-location-dotnet) 
+  [Carga de un objeto](https://docs.aws.amazon.com/AmazonS3/latest/dev/UploadObjSingleOpNET.html) 
+  [Carga de varias partes con la API de alto nivel ([Amazon.S3.Transfer). TransferUtility](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/S3/TTransferUtility.html))](https://docs.aws.amazon.com/AmazonS3/latest/dev/usingHLmpuDotNet.html) 
+  [Carga multiparte con la API de bajo nivel](https://docs.aws.amazon.com/AmazonS3/latest/dev/usingLLmpuDotNet.html) 
+  [Listas de objetos](https://docs.aws.amazon.com/AmazonS3/latest/dev/list-obj-version-enabled-bucket.html#list-obj-version-enabled-bucket-sdk-examples) 
+  [Lista de claves](https://docs.aws.amazon.com/AmazonS3/latest/dev/ListingObjectKeysUsingNetSDK.html) 
+  [Obtención de un objeto](https://docs.aws.amazon.com/AmazonS3/latest/dev/RetrievingObjectUsingNetSDK.html) 
+  [Copia de un objeto](https://docs.aws.amazon.com/AmazonS3/latest/dev/CopyingObjectUsingNetSDK.html) 
+  [Copia de un objeto con la API de carga multiparte](https://docs.aws.amazon.com/AmazonS3/latest/dev/CopyingObjctsUsingLLNetMPUapi.html) 
+  [Eliminación de un objeto](https://docs.aws.amazon.com/AmazonS3/latest/dev/DeletingOneObjectUsingNetSDK.html) 
+  [Eliminación de varios objetos](https://docs.aws.amazon.com/AmazonS3/latest/dev/DeletingMultipleObjectsUsingNetSDK.html) 
+  [Restauración de un objeto](https://docs.aws.amazon.com/AmazonS3/latest/dev/restore-object-dotnet.html) 
+  [Configuración de un bucket para las notificaciones](https://docs.aws.amazon.com/AmazonS3/latest/dev/ways-to-add-notification-config-to-bucket.html) 
+  [Administración del ciclo de vida de un objeto](https://docs.aws.amazon.com/AmazonS3/latest/dev/manage-lifecycle-using-dot-net.html) 
+  [Generación de una URL de objeto prefirmada](https://docs.aws.amazon.com/AmazonS3/latest/dev/ShareObjectPreSignedURLDotNetSDK.html) 
+  [Administración de sitios web](https://docs.aws.amazon.com/AmazonS3/latest/dev/ConfigWebSiteDotNet.html) 
+  [Habilitación del uso compartido de recursos entre orígenes (CORS)](https://docs.aws.amazon.com/AmazonS3/latest/dev/ManageCorsUsingDotNet.html) 

**Consideraciones de programación adicionales**
+  [Uso de AWS SDK para .NET para la programación en Amazon S3](https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingTheMPDotNetAPI.html) 
+  [Realización de solicitudes con las credenciales temporales de usuario de IAM](https://docs.aws.amazon.com/AmazonS3/latest/dev/AuthUsingTempSessionTokenDotNet.html) 
+  [Realización de solicitudes con credenciales temporales de usuario federado](https://docs.aws.amazon.com/AmazonS3/latest/dev/AuthUsingTempFederationTokenDotNet.html) 
+  [Especificación de cifrado del lado del servidor](https://docs.aws.amazon.com/AmazonS3/latest/dev/SSEUsingDotNetSDK.html) 
+  [Especificación de cifrado del lado del servidor con claves de cifrado proporcionadas por el cliente](https://docs.aws.amazon.com/AmazonS3/latest/dev/sse-c-using-dot-net-sdk.html) 

# Uso de AWS KMS claves para el cifrado de Amazon S3 en AWS SDK para .NET
<a name="kms-keys-s3-encryption"></a>

En este ejemplo, se muestra cómo utilizar AWS Key Management Service las claves para cifrar objetos de Amazon S3. La aplicación crea una clave maestra del cliente (CMK) y la utiliza para crear un objeto [EncryptionClientV2 de AmazonS3](https://aws.github.io/amazon-s3-encryption-client-dotnet/api/Amazon.Extensions.S3.Encryption.AmazonS3EncryptionClientV2.html) para el cifrado del lado del cliente. La aplicación utiliza ese cliente para crear un objeto cifrado a partir de un determinado archivo de texto en un bucket de Amazon S3 existente. Luego, descifra el objeto y muestra su contenido.

**aviso**  
Una clase similar, `AmazonS3EncryptionClient`, está en desuso y es menos segura que la clase `AmazonS3EncryptionClientV2`. Para migrar código existente que use `AmazonS3EncryptionClient`, consulte [Migración del cliente de cifrado S3 (V1 a V2)](s3-encryption-migration-v1-v2.md).

**Topics**
+ [

## Creación de materiales de cifrado
](#kms-s3-enc-mat)
+ [

## Creación y cifrado de un objeto de Amazon S3
](#kms-s3-create-ojbect)
+ [

## Código completo
](#kms-s3-complete-code)
+ [

## Consideraciones adicionales
](#kms-s3-additional)

## Creación de materiales de cifrado
<a name="kms-s3-enc-mat"></a>

El siguiente fragmento de código crea un objeto `EncryptionMaterials` que contiene un ID de clave de KMS.

El ejemplo que aparece [al final de este tema](#kms-s3-complete-code) muestra este fragmento de código en uso.

```
      // Create a customer master key (CMK) and store the result
      CreateKeyResponse createKeyResponse =
        await new AmazonKeyManagementServiceClient().CreateKeyAsync(new CreateKeyRequest());
      var kmsEncryptionContext = new Dictionary<string, string>();
      var kmsEncryptionMaterials = new EncryptionMaterialsV2(
        createKeyResponse.KeyMetadata.KeyId, KmsType.KmsContext, kmsEncryptionContext);
```

## Creación y cifrado de un objeto de Amazon S3
<a name="kms-s3-create-ojbect"></a>

El siguiente fragmento de código crea un objeto `AmazonS3EncryptionClientV2` que utiliza los materiales de cifrado creados anteriormente. Luego, utiliza el cliente para crear y cifrar un nuevo objeto de Amazon S3.

El ejemplo que aparece [al final de este tema](#kms-s3-complete-code) muestra este fragmento de código en uso.

```
    //
    // Method to create and encrypt an object in an S3 bucket
    static async Task<GetObjectResponse> CreateAndRetrieveObjectAsync(
      EncryptionMaterialsV2 materials, string bucketName,
      string fileName, string itemName)
    {
      // CryptoStorageMode.ObjectMetadata is required for KMS EncryptionMaterials
      var config = new AmazonS3CryptoConfigurationV2(SecurityProfile.V2AndLegacy)
      {
        StorageMode = CryptoStorageMode.ObjectMetadata
      };
      var s3EncClient = new AmazonS3EncryptionClientV2(config, materials);

      // Create, encrypt, and put the object
      await s3EncClient.PutObjectAsync(new PutObjectRequest
      {
        BucketName = bucketName,
        Key = itemName,
        ContentBody = File.ReadAllText(fileName)
      });

      // Get, decrypt, and return the object
      return await s3EncClient.GetObjectAsync(new GetObjectRequest
      {
        BucketName = bucketName,
        Key = itemName
      });
    }
```

## Código completo
<a name="kms-s3-complete-code"></a>

En esta sección se muestran las referencias relevantes y el código completo de este ejemplo.

### Referencias de SDK
<a name="w2aac19c15c21c13c15b5b1"></a>

NuGet paquetes:
+ [Amazon.Extensions.S3.Encryption](https://www.nuget.org/packages/Amazon.Extensions.S3.Encryption)

Elementos de programación:
+ Espacio de nombres [Amazon.Extensions.S3.Encryption](https://aws.github.io/amazon-s3-encryption-client-dotnet/api/Amazon.Extensions.S3.Encryption.html)

  Clase [Amazon S3 V2 EncryptionClient](https://aws.github.io/amazon-s3-encryption-client-dotnet/api/Amazon.Extensions.S3.Encryption.AmazonS3EncryptionClientV2.html)

  Clase [Amazon S3 V2 CryptoConfiguration](https://aws.github.io/amazon-s3-encryption-client-dotnet/api/Amazon.Extensions.S3.Encryption.AmazonS3CryptoConfigurationV2.html)

  Clase [CryptoStorageMode](https://aws.github.io/amazon-s3-encryption-client-dotnet/api/Amazon.Extensions.S3.Encryption.CryptoStorageMode.html)

  Clase [EncryptionMaterialsV2](https://aws.github.io/amazon-s3-encryption-client-dotnet/api/Amazon.Extensions.S3.Encryption.EncryptionMaterialsV2.html)
+ Espacio de nombres [Amazon.Extensions.S3.Encryption.Primitives](https://aws.github.io/amazon-s3-encryption-client-dotnet/api/Amazon.Extensions.S3.Encryption.Primitives.html)

  Clase [KmsType](https://aws.github.io/amazon-s3-encryption-client-dotnet/api/Amazon.Extensions.S3.Encryption.Primitives.KmsType.html)
+ Espacio de nombres [Amazon.S3.Model](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/S3/NS3Model.html)

  Clase [GetObjectRequest](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/S3/TGetObjectRequest.html)

  Clase [GetObjectResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/S3/TGetObjectResponse.html)

  Clase [PutObjectRequest](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/S3/TPutObjectRequest.html)
+ [Espacio de nombres Amazon. KeyManagementService](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/KeyManagementService/NKeyManagementService.html)

  Clase [AmazonKeyManagementServiceClient](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/KeyManagementService/TKeyManagementServiceClient.html)
+ [Espacio de nombres Amazon. KeyManagementService](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/KeyManagementService/NKeyManagementServiceModel.html).Modelo

  Clase [CreateKeyRequest](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/KeyManagementService/TCreateKeyRequest.html)

  Clase [CreateKeyResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/KeyManagementService/TCreateKeyResponse.html)

### El código
<a name="w2aac19c15c21c13c15b7b1"></a>

```
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using Amazon.Extensions.S3.Encryption;
using Amazon.Extensions.S3.Encryption.Primitives;
using Amazon.S3.Model;
using Amazon.KeyManagementService;
using Amazon.KeyManagementService.Model;

namespace KmsS3Encryption
{
  // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  // Class to store text in an encrypted S3 object.
  class Program
  {
    private const int MaxArgs = 3;

    public static async Task Main(string[] args)
    {
      // Parse the command line and show help if necessary
      var parsedArgs = CommandLine.Parse(args);
      if((parsedArgs.Count == 0) || (parsedArgs.Count > MaxArgs))
      {
        PrintHelp();
        return;
      }

      // Get the application arguments from the parsed list
      string bucketName =
        CommandLine.GetArgument(parsedArgs, null, "-b", "--bucket-name");
      string fileName =
        CommandLine.GetArgument(parsedArgs, null, "-f", "--file-name");
      string itemName =
        CommandLine.GetArgument(parsedArgs, null, "-i", "--item-name");
      if(string.IsNullOrEmpty(bucketName) || (string.IsNullOrEmpty(fileName)))
        CommandLine.ErrorExit(
          "\nOne or more of the required arguments is missing or incorrect." +
          "\nRun the command with no arguments to see help.");
      if(!File.Exists(fileName))
        CommandLine.ErrorExit($"\nThe given file {fileName} doesn't exist.");
      if(string.IsNullOrEmpty(itemName))
        itemName = Path.GetFileName(fileName);

      // Create a customer master key (CMK) and store the result
      CreateKeyResponse createKeyResponse =
        await new AmazonKeyManagementServiceClient().CreateKeyAsync(new CreateKeyRequest());
      var kmsEncryptionContext = new Dictionary<string, string>();
      var kmsEncryptionMaterials = new EncryptionMaterialsV2(
        createKeyResponse.KeyMetadata.KeyId, KmsType.KmsContext, kmsEncryptionContext);

      // Create the object in the bucket, then display the content of the object
      var putObjectResponse =
        await CreateAndRetrieveObjectAsync(kmsEncryptionMaterials, bucketName, fileName, itemName);
      Stream stream = putObjectResponse.ResponseStream;
      StreamReader reader = new StreamReader(stream);
      Console.WriteLine(reader.ReadToEnd());
    }


    //
    // Method to create and encrypt an object in an S3 bucket
    static async Task<GetObjectResponse> CreateAndRetrieveObjectAsync(
      EncryptionMaterialsV2 materials, string bucketName,
      string fileName, string itemName)
    {
      // CryptoStorageMode.ObjectMetadata is required for KMS EncryptionMaterials
      var config = new AmazonS3CryptoConfigurationV2(SecurityProfile.V2AndLegacy)
      {
        StorageMode = CryptoStorageMode.ObjectMetadata
      };
      var s3EncClient = new AmazonS3EncryptionClientV2(config, materials);

      // Create, encrypt, and put the object
      await s3EncClient.PutObjectAsync(new PutObjectRequest
      {
        BucketName = bucketName,
        Key = itemName,
        ContentBody = File.ReadAllText(fileName)
      });

      // Get, decrypt, and return the object
      return await s3EncClient.GetObjectAsync(new GetObjectRequest
      {
        BucketName = bucketName,
        Key = itemName
      });
    }


    //
    // Command-line help
    private static void PrintHelp()
    {
      Console.WriteLine(
        "\nUsage: KmsS3Encryption -b <bucket-name> -f <file-name> [-i <item-name>]" +
        "\n  -b, --bucket-name: The name of an existing S3 bucket." +
        "\n  -f, --file-name: The name of a text file with content to encrypt and store in S3." +
        "\n  -i, --item-name: The name you want to use for the item." +
        "\n      If item-name isn't given, file-name will be used.");
    }

  }

  // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  // Class that represents a command line on the console or terminal.
  // (This is the same for all examples. When you have seen it once, you can ignore it.)
  static class CommandLine
  {
    //
    // Method to parse a command line of the form: "--key value" or "-k value".
    //
    // Parameters:
    // - args: The command-line arguments passed into the application by the system.
    //
    // Returns:
    // A Dictionary with string Keys and Values.
    //
    // If a key is found without a matching value, Dictionary.Value is set to the key
    //  (including the dashes).
    // If a value is found without a matching key, Dictionary.Key is set to "--NoKeyN",
    //  where "N" represents sequential numbers.
    public static Dictionary<string,string> Parse(string[] args)
    {
      var parsedArgs = new Dictionary<string,string>();
      int i = 0, n = 0;
      while(i < args.Length)
      {
        // If the first argument in this iteration starts with a dash it's an option.
        if(args[i].StartsWith("-"))
        {
          var key = args[i++];
          var value = key;

          // Check to see if there's a value that goes with this option?
          if((i < args.Length) && (!args[i].StartsWith("-"))) value = args[i++];
          parsedArgs.Add(key, value);
        }

        // If the first argument in this iteration doesn't start with a dash, it's a value
        else
        {
          parsedArgs.Add("--NoKey" + n.ToString(), args[i++]);
          n++;
        }
      }

      return parsedArgs;
    }

    //
    // Method to get an argument from the parsed command-line arguments
    //
    // Parameters:
    // - parsedArgs: The Dictionary object returned from the Parse() method (shown above).
    // - defaultValue: The default string to return if the specified key isn't in parsedArgs.
    // - keys: An array of keys to look for in parsedArgs.
    public static string GetArgument(
      Dictionary<string,string> parsedArgs, string defaultReturn, params string[] keys)
    {
      string retval = null;
      foreach(var key in keys)
        if(parsedArgs.TryGetValue(key, out retval)) break;
      return retval ?? defaultReturn;
    }

    //
    // Method to exit the application with an error.
    public static void ErrorExit(string msg, int code=1)
    {
      Console.WriteLine("\nError");
      Console.WriteLine(msg);
      Environment.Exit(code);
    }
  }

}
```

## Consideraciones adicionales
<a name="kms-s3-additional"></a>
+ Puede comprobar los resultados de este ejemplo. Para ello, vaya a la [consola de Amazon S3](https://console.aws.amazon.com/s3) y abra el bucket que proporcionó a la aplicación. Luego, busque el nuevo objeto, descárguelo y ábralo en un editor de texto.
+ La clase [AmazonS3 EncryptionClient V2](https://aws.github.io/amazon-s3-encryption-client-dotnet/api/Amazon.Extensions.S3.Encryption.AmazonS3EncryptionClientV2.html) implementa la misma interfaz que la `AmazonS3Client` clase estándar. Esto facilita la migración del código a la clase `AmazonS3EncryptionClientV2` para que el cifrado y el descifrado se realicen de forma automática y transparente en el cliente.
+ Una de las ventajas de usar una AWS KMS clave como clave maestra es que no necesita almacenar ni administrar sus propias claves maestras, ya que esto se consigue mediante AWS. Una segunda ventaja es que la `AmazonS3EncryptionClientV2` clase de AWS SDK para .NET es interoperable con la `AmazonS3EncryptionClientV2` clase de. AWS SDK para Java Esto significa que puede cifrar con el AWS SDK para Java y descifrar con el AWS SDK para .NET, y viceversa.
**nota**  
La `AmazonS3EncryptionClientV2` clase de los AWS SDK para .NET admite claves maestras de KMS solo cuando se ejecuta en modo de metadatos. El modo de archivo de instrucciones de la `AmazonS3EncryptionClientV2` clase de AWS SDK para .NET es incompatible con la `AmazonS3EncryptionClientV2` clase de AWS SDK para Java.
+ Para obtener más información sobre el cifrado del lado del cliente con la `AmazonS3EncryptionClientV2` clase y cómo funciona el cifrado de sobres, consulte Cifrado de [datos del lado del cliente con Amazon AWS SDK para .NET S3](https://aws.amazon.com/blogs/developer/client-side-data-encryption-with-aws-sdk-for-net-and-amazon-s3/).

# Envío de notificaciones desde la nube mediante Amazon Simple Notification Service
<a name="sns-apis-intro"></a>

**nota**  
La información de este tema es específica de los proyectos basados en .NET Framework y en la AWS SDK para .NET versión 3.3 y anteriores.

 AWS SDK para .NET Es compatible con Amazon Simple Notification Service (Amazon SNS), que es un servicio web que permite a las aplicaciones, los usuarios finales y los dispositivos enviar notificaciones al instante desde la nube. Para obtener más información, consulte [Amazon SNS](https://aws.amazon.com/sns/).

## Enumeración de temas de Amazon SNS
<a name="sns-list-example"></a>

En el siguiente ejemplo se muestra cómo enumerar sus temas de Amazon SNS, las suscripciones a cada tema y los atributos de cada tema. En este ejemplo se usa el valor predeterminado [AmazonSimpleNotificationServiceClient](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SNS/TSNSClient.html).

```
// using Amazon.SimpleNotificationService;
// using Amazon.SimpleNotificationService.Model;

var client = new AmazonSimpleNotificationServiceClient();
var request = new ListTopicsRequest();
var response = new ListTopicsResponse();

do
{
  response = client.ListTopics(request);

  foreach (var topic in response.Topics)
  {
    Console.WriteLine("Topic: {0}", topic.TopicArn);

    var subs = client.ListSubscriptionsByTopic(
      new ListSubscriptionsByTopicRequest
      {
        TopicArn = topic.TopicArn
      });

    var ss = subs.Subscriptions;

    if (ss.Any())
    {
      Console.WriteLine("  Subscriptions:");

      foreach (var sub in ss)
      {
        Console.WriteLine("    {0}", sub.SubscriptionArn);
      }
    }

    var attrs = client.GetTopicAttributes(
      new GetTopicAttributesRequest
      {
        TopicArn = topic.TopicArn
      }).Attributes;

    if (attrs.Any())
    {
      Console.WriteLine("  Attributes:");

      foreach (var attr in attrs)
      {
        Console.WriteLine("    {0} = {1}", attr.Key, attr.Value);
      }
    }

    Console.WriteLine();
  }

  request.NextToken = response.NextToken;

} while (!string.IsNullOrEmpty(response.NextToken));
```

## Envío de un mensaje a un tema de Amazon SNS
<a name="sns-send-message-example"></a>

En el siguiente ejemplo se muestra cómo enviar un mensaje a un tema de Amazon SNS. El ejemplo toma un argumento, el ARN del tema de Amazon SNS.

```
using System;
using System.Linq;
using System.Threading.Tasks;

using Amazon;
using Amazon.SimpleNotificationService;
using Amazon.SimpleNotificationService.Model;

namespace SnsSendMessage
{
    class Program
    {
        static void Main(string[] args)
        {
            /* Topic ARNs must be in the correct format:
             *   arn:aws:sns:REGION:ACCOUNT_ID:NAME
             *
             *  where:
             *  REGION     is the region in which the topic is created, such as us-west-2
             *  ACCOUNT_ID is your (typically) 12-character account ID
             *  NAME       is the name of the topic
             */
            string topicArn = args[0];
            string message = "Hello at " + DateTime.Now.ToShortTimeString();

            var client = new AmazonSimpleNotificationServiceClient(region: Amazon.RegionEndpoint.USWest2);

            var request = new PublishRequest
            {
                Message = message,
                TopicArn = topicArn
            };

            try
            {
                var response = client.Publish(request);

                Console.WriteLine("Message sent to topic:");
                Console.WriteLine(message);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Caught exception publishing request:");
                Console.WriteLine(ex.Message);
            }
        }
    }
}
```

Consulte el [ejemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/.dotnet/example_code_legacy/SNS/SnsSendMessage.cs), que incluye información sobre cómo compilar y ejecutar el ejemplo desde la línea de comandos, en adelante GitHub.

## Envío de un mensaje SMS a un número de teléfono
<a name="sns-send-sms-example"></a>

En el siguiente ejemplo se muestra cómo enviar un mensaje SMS a un número de teléfono. El ejemplo acepta un argumento, el número de teléfono, que debe estar en cualquiera de los dos formatos descritos en los comentarios.

```
using System;
using System.Linq;
using System.Threading.Tasks;
using Amazon;
using Amazon.SimpleNotificationService;
using Amazon.SimpleNotificationService.Model;

namespace SnsPublish
{
    class Program
    {
        static void Main(string[] args)
        {
            // US phone numbers must be in the correct format:
            // +1 (nnn) nnn-nnnn OR +1nnnnnnnnnn
            string number = args[0];
            string message = "Hello at " + DateTime.Now.ToShortTimeString();

            var client = new AmazonSimpleNotificationServiceClient(region: Amazon.RegionEndpoint.USWest2);
            var request = new PublishRequest
            {
                Message = message,
                PhoneNumber = number
            };

            try
            {
                var response = client.Publish(request);

                Console.WriteLine("Message sent to " + number + ":");
                Console.WriteLine(message);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Caught exception publishing request:");
                Console.WriteLine(ex.Message);
            }
        }
    }
}
```

Consulte el [ejemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/.dotnet/example_code_legacy/SNS/SnsPublish.cs), que incluye información sobre cómo compilar y ejecutar el ejemplo desde la línea de comandos, en adelante GitHub.

# Mensajería mediante Amazon SQS
<a name="sqs-apis-intro"></a>

 AWS SDK para .NET Es compatible con [Amazon Simple Queue Service (Amazon SQS), que es un servicio](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/) de cola de mensajes que gestiona los mensajes o los flujos de trabajo entre los componentes de un sistema.

Las colas de Amazon SQS proporcionan un mecanismo que permite enviar, almacenar y recibir mensajes entre componentes de software como, por ejemplo, microservicios, sistemas distribuidos y aplicaciones sin servidor. Esto permite desvincular esos componentes y acaba con la necesidad de tener que diseñar y operar un sistema de mensajería propio. Para obtener información sobre cómo funcionan las colas y los mensajes en Amazon SQS, consulte [Tutoriales de Amazon SQS](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-other-tutorials.html) y [Funcionamiento de Amazon SQS](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-basic-architecture.html) en la [Guía para desarrolladores de Amazon Simple Queue Service](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/).

**importante**  
Dada la naturaleza distribuida de las colas, Amazon SQS no puede garantizar que vaya a recibir los mensajes en el mismo orden en que se envían. Si necesita conservar el orden de los mensajes, utilice una [cola FIFO de Amazon SQS](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-fifo-queues.html).

## APIs
<a name="w2aac19c15c25b9"></a>

Se AWS SDK para .NET proporciona APIs para los clientes de Amazon SQS. Le APIs permiten trabajar con funciones de Amazon SQS, como colas y mensajes. Esta sección contiene una pequeña cantidad de ejemplos que le muestran los patrones que puede seguir al trabajar con ellos. APIs Para ver el conjunto completo de ellos APIs, consulta la [referencia de la AWS SDK para .NET API](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/) (y desplázate hasta «Amazon.sqs»).

Los Amazon SQS APIs se proporcionan en el paquete [AWSSDK NuGet .SQS](https://www.nuget.org/packages/AWSSDK.SQS).

## Requisitos previos
<a name="w2aac19c15c25c11"></a>

Antes de comenzar, asegúrese de que ha [configurado el entorno y el proyecto](net-dg-config.md). Revise también la información en [Características de SDK](net-dg-sdk-features.md).

## Temas
<a name="w2aac19c15c25c13"></a>

**Topics**
+ [

## APIs
](#w2aac19c15c25b9)
+ [

## Requisitos previos
](#w2aac19c15c25c11)
+ [

## Temas
](#w2aac19c15c25c13)
+ [Creación de colas](CreateQueue.md)
+ [Actualización de colas](UpdateSqsQueue.md)
+ [Eliminación de colas](DeleteSqsQueue.md)
+ [Envío de mensajes](SendMessage.md)
+ [Recepción de mensajes](ReceiveMessage.md)

# Creación de colas de Amazon SQS
<a name="CreateQueue"></a>

En este ejemplo, se muestra cómo utilizarla AWS SDK para .NET para crear una cola de Amazon SQS. La aplicación crea una [cola de mensajes fallidos](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-dead-letter-queues.html) si no se proporciona el ARN de una. A continuación, crea una cola de mensajes estándar, que incluye una cola de mensajes fallidos (una que haya proporcionado o que se haya creado).

Si no proporciona ningún argumento de línea de comandos, la aplicación simplemente muestra información de todas las colas existentes.

En las siguientes secciones se proporcionan fragmentos de código de este ejemplo. Tras ello, se muestra el [código completo del ejemplo](#CreateQueue-complete-code), que se puede compilar y ejecutar tal cual.

**Topics**
+ [

## Visualización de las colas existentes
](#CreateQueue-show-queues)
+ [

## Creación de la cola
](#CreateQueue-create-queue)
+ [

## Obtención del ARN de una cola
](#CreateQueue-get-arn)
+ [

## Código completo
](#CreateQueue-complete-code)
+ [

## Consideraciones adicionales
](#CreateQueue-additional)

## Visualización de las colas existentes
<a name="CreateQueue-show-queues"></a>

El siguiente fragmento de código muestra una lista de las colas existentes en la región del cliente de SQS, así como los atributos de cada cola.

El ejemplo que aparece [al final de este tema](#CreateQueue-complete-code) muestra este fragmento de código en uso.

```
    //
    // Method to show a list of the existing queues
    private static async Task ShowQueues(IAmazonSQS sqsClient)
    {
      ListQueuesResponse responseList = await sqsClient.ListQueuesAsync("");
      Console.WriteLine();
      foreach(string qUrl in responseList.QueueUrls)
      {
        // Get and show all attributes. Could also get a subset.
        await ShowAllAttributes(sqsClient, qUrl);
      }
    }

    //
    // Method to show all attributes of a queue
    private static async Task ShowAllAttributes(IAmazonSQS sqsClient, string qUrl)
    {
      var attributes = new List<string>{ QueueAttributeName.All };
      GetQueueAttributesResponse responseGetAtt =
        await sqsClient.GetQueueAttributesAsync(qUrl, attributes);
      Console.WriteLine($"Queue: {qUrl}");
      foreach(var att in responseGetAtt.Attributes)
        Console.WriteLine($"\t{att.Key}: {att.Value}");
    }
```

## Creación de la cola
<a name="CreateQueue-create-queue"></a>

El siguiente fragmento de código crea una cola. El fragmento de código incluye el uso de una cola de mensajes fallidos, pero esta no tiene por qué ser necesaria para sus colas.

El ejemplo que aparece [al final de este tema](#CreateQueue-complete-code) muestra este fragmento de código en uso.

```
    //
    // Method to create a queue. Returns the queue URL.
    private static async Task<string> CreateQueue(
      IAmazonSQS sqsClient, string qName, string deadLetterQueueUrl=null,
      string maxReceiveCount=null, string receiveWaitTime=null)
    {
      var attrs = new Dictionary<string, string>();

      // If a dead-letter queue is given, create a message queue
      if(!string.IsNullOrEmpty(deadLetterQueueUrl))
      {
        attrs.Add(QueueAttributeName.ReceiveMessageWaitTimeSeconds, receiveWaitTime);
        attrs.Add(QueueAttributeName.RedrivePolicy,
          $"{{\"deadLetterTargetArn\":\"{await GetQueueArn(sqsClient, deadLetterQueueUrl)}\"," +
          $"\"maxReceiveCount\":\"{maxReceiveCount}\"}}");
        // Add other attributes for the message queue such as VisibilityTimeout
      }

      // If no dead-letter queue is given, create one of those instead
      //else
      //{
      //  // Add attributes for the dead-letter queue as needed
      //  attrs.Add();
      //}

      // Create the queue
      CreateQueueResponse responseCreate = await sqsClient.CreateQueueAsync(
          new CreateQueueRequest{QueueName = qName, Attributes = attrs});
      return responseCreate.QueueUrl;
    }
```

## Obtención del ARN de una cola
<a name="CreateQueue-get-arn"></a>

El siguiente fragmento de código obtiene el ARN de la cola identificada por la URL de cola especificada.

El ejemplo que aparece [al final de este tema](#CreateQueue-complete-code) muestra este fragmento de código en uso.

```
    //
    // Method to get the ARN of a queue
    private static async Task<string> GetQueueArn(IAmazonSQS sqsClient, string qUrl)
    {
      GetQueueAttributesResponse responseGetAtt = await sqsClient.GetQueueAttributesAsync(
        qUrl, new List<string>{QueueAttributeName.QueueArn});
      return responseGetAtt.QueueARN;
    }
```

## Código completo
<a name="CreateQueue-complete-code"></a>

En esta sección se muestran las referencias relevantes y el código completo de este ejemplo.

### Referencias de SDK
<a name="w2aac19c15c25c17c25b5b1"></a>

NuGet paquetes:
+ [AWSSDK.SQS](https://www.nuget.org/packages/AWSSDK.SQS)

Elementos de programación:
+ Espacio de nombres [Amazon.SQS](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/NSQS.html)

  Clase [Amazon SQSClient](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/TSQSClient.html)

  Clase [QueueAttributeName](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/TQueueAttributeName.html)
+ Espacio de nombres [Amazon.SQS.Model](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/NSQSModel.html)

  Clase [CreateQueueRequest](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/TCreateQueueRequest.html)

  Clase [CreateQueueResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/TCreateQueueResponse.html)

  Clase [GetQueueAttributesResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/TGetQueueAttributesResponse.html)

  Clase [ListQueuesResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/TListQueuesResponse.html)

### El código
<a name="w2aac19c15c25c17c25b7b1"></a>

```
using System;
using System.Threading.Tasks;
using System.Collections.Generic;
using Amazon.SQS;
using Amazon.SQS.Model;

namespace SQSCreateQueue
{
  // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  // Class to create a queue
  class Program
  {
    private const string MaxReceiveCount = "10";
    private const string ReceiveMessageWaitTime = "2";
    private const int MaxArgs = 3;

    static async Task Main(string[] args)
    {
      // Parse the command line and show help if necessary
      var parsedArgs = CommandLine.Parse(args);
      if(parsedArgs.Count > MaxArgs)
        CommandLine.ErrorExit(
          "\nToo many command-line arguments.\nRun the command with no arguments to see help.");

      // Create the Amazon SQS client
      var sqsClient = new AmazonSQSClient();

      // In the case of no command-line arguments, just show help and the existing queues
      if(parsedArgs.Count == 0)
      {
        PrintHelp();
        Console.WriteLine("\nNo arguments specified.");
        Console.Write("Do you want to see a list of the existing queues? ((y) or n): ");
        string response = Console.ReadLine();
        if((string.IsNullOrEmpty(response)) || (response.ToLower() == "y"))
          await ShowQueues(sqsClient);
        return;
      }

      // Get the application arguments from the parsed list
      string queueName =
        CommandLine.GetArgument(parsedArgs, null, "-q", "--queue-name");
      string deadLetterQueueUrl =
        CommandLine.GetArgument(parsedArgs, null, "-d", "--dead-letter-queue");
      string maxReceiveCount =
        CommandLine.GetArgument(parsedArgs, MaxReceiveCount, "-m", "--max-receive-count");
      string receiveWaitTime =
        CommandLine.GetArgument(parsedArgs, ReceiveMessageWaitTime, "-w", "--wait-time");

      if(string.IsNullOrEmpty(queueName))
        CommandLine.ErrorExit(
          "\nYou must supply a queue name.\nRun the command with no arguments to see help.");

      // If a dead-letter queue wasn't given, create one
      if(string.IsNullOrEmpty(deadLetterQueueUrl))
      {
        Console.WriteLine("\nNo dead-letter queue was specified. Creating one...");
        deadLetterQueueUrl = await CreateQueue(sqsClient, queueName + "__dlq");
        Console.WriteLine($"Your new dead-letter queue:");
        await ShowAllAttributes(sqsClient, deadLetterQueueUrl);
      }

      // Create the message queue
      string messageQueueUrl = await CreateQueue(
        sqsClient, queueName, deadLetterQueueUrl, maxReceiveCount, receiveWaitTime);
      Console.WriteLine($"Your new message queue:");
      await ShowAllAttributes(sqsClient, messageQueueUrl);
    }


    //
    // Method to show a list of the existing queues
    private static async Task ShowQueues(IAmazonSQS sqsClient)
    {
      ListQueuesResponse responseList = await sqsClient.ListQueuesAsync("");
      Console.WriteLine();
      foreach(string qUrl in responseList.QueueUrls)
      {
        // Get and show all attributes. Could also get a subset.
        await ShowAllAttributes(sqsClient, qUrl);
      }
    }


    //
    // Method to create a queue. Returns the queue URL.
    private static async Task<string> CreateQueue(
      IAmazonSQS sqsClient, string qName, string deadLetterQueueUrl=null,
      string maxReceiveCount=null, string receiveWaitTime=null)
    {
      var attrs = new Dictionary<string, string>();

      // If a dead-letter queue is given, create a message queue
      if(!string.IsNullOrEmpty(deadLetterQueueUrl))
      {
        attrs.Add(QueueAttributeName.ReceiveMessageWaitTimeSeconds, receiveWaitTime);
        attrs.Add(QueueAttributeName.RedrivePolicy,
          $"{{\"deadLetterTargetArn\":\"{await GetQueueArn(sqsClient, deadLetterQueueUrl)}\"," +
          $"\"maxReceiveCount\":\"{maxReceiveCount}\"}}");
        // Add other attributes for the message queue such as VisibilityTimeout
      }

      // If no dead-letter queue is given, create one of those instead
      //else
      //{
      //  // Add attributes for the dead-letter queue as needed
      //  attrs.Add();
      //}

      // Create the queue
      CreateQueueResponse responseCreate = await sqsClient.CreateQueueAsync(
          new CreateQueueRequest{QueueName = qName, Attributes = attrs});
      return responseCreate.QueueUrl;
    }


    //
    // Method to get the ARN of a queue
    private static async Task<string> GetQueueArn(IAmazonSQS sqsClient, string qUrl)
    {
      GetQueueAttributesResponse responseGetAtt = await sqsClient.GetQueueAttributesAsync(
        qUrl, new List<string>{QueueAttributeName.QueueArn});
      return responseGetAtt.QueueARN;
    }


    //
    // Method to show all attributes of a queue
    private static async Task ShowAllAttributes(IAmazonSQS sqsClient, string qUrl)
    {
      var attributes = new List<string>{ QueueAttributeName.All };
      GetQueueAttributesResponse responseGetAtt =
        await sqsClient.GetQueueAttributesAsync(qUrl, attributes);
      Console.WriteLine($"Queue: {qUrl}");
      foreach(var att in responseGetAtt.Attributes)
        Console.WriteLine($"\t{att.Key}: {att.Value}");
    }


    //
    // Command-line help
    private static void PrintHelp()
    {
      Console.WriteLine(
      "\nUsage: SQSCreateQueue -q <queue-name> [-d <dead-letter-queue>]" +
        " [-m <max-receive-count>] [-w <wait-time>]" +
      "\n  -q, --queue-name: The name of the queue you want to create." +
      "\n  -d, --dead-letter-queue: The URL of an existing queue to be used as the dead-letter queue."+
      "\n      If this argument isn't supplied, a new dead-letter queue will be created." +
      "\n  -m, --max-receive-count: The value for maxReceiveCount in the RedrivePolicy of the queue." +
      $"\n      Default is {MaxReceiveCount}." +
      "\n  -w, --wait-time: The value for ReceiveMessageWaitTimeSeconds of the queue for long polling." +
      $"\n      Default is {ReceiveMessageWaitTime}.");
    }
  }


  // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  // Class that represents a command line on the console or terminal.
  // (This is the same for all examples. When you have seen it once, you can ignore it.)
  static class CommandLine
  {
    //
    // Method to parse a command line of the form: "--key value" or "-k value".
    //
    // Parameters:
    // - args: The command-line arguments passed into the application by the system.
    //
    // Returns:
    // A Dictionary with string Keys and Values.
    //
    // If a key is found without a matching value, Dictionary.Value is set to the key
    //  (including the dashes).
    // If a value is found without a matching key, Dictionary.Key is set to "--NoKeyN",
    //  where "N" represents sequential numbers.
    public static Dictionary<string,string> Parse(string[] args)
    {
      var parsedArgs = new Dictionary<string,string>();
      int i = 0, n = 0;
      while(i < args.Length)
      {
        // If the first argument in this iteration starts with a dash it's an option.
        if(args[i].StartsWith("-"))
        {
          var key = args[i++];
          var value = key;

          // Check to see if there's a value that goes with this option?
          if((i < args.Length) && (!args[i].StartsWith("-"))) value = args[i++];
          parsedArgs.Add(key, value);
        }

        // If the first argument in this iteration doesn't start with a dash, it's a value
        else
        {
          parsedArgs.Add("--NoKey" + n.ToString(), args[i++]);
          n++;
        }
      }

      return parsedArgs;
    }

    //
    // Method to get an argument from the parsed command-line arguments
    //
    // Parameters:
    // - parsedArgs: The Dictionary object returned from the Parse() method (shown above).
    // - defaultValue: The default string to return if the specified key isn't in parsedArgs.
    // - keys: An array of keys to look for in parsedArgs.
    public static string GetArgument(
      Dictionary<string,string> parsedArgs, string defaultReturn, params string[] keys)
    {
      string retval = null;
      foreach(var key in keys)
        if(parsedArgs.TryGetValue(key, out retval)) break;
      return retval ?? defaultReturn;
    }

    //
    // Method to exit the application with an error.
    public static void ErrorExit(string msg, int code=1)
    {
      Console.WriteLine("\nError");
      Console.WriteLine(msg);
      Environment.Exit(code);
    }
  }

}
```

## Consideraciones adicionales
<a name="CreateQueue-additional"></a>
+ El nombre de la cola debe estar formado solo por caracteres alfanuméricos, guiones y guiones bajos.
+ Los nombres de las colas y las colas distinguen mayúsculas URLs de minúsculas
+ Si necesita la URL de cola, pero solo tiene el nombre de la cola, utilice uno de los métodos `AmazonSQSClient.GetQueueUrlAsync`.
+ Para obtener información sobre los distintos atributos de cola que puede configurar, consulte la referencia de [CreateQueueRequest](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/TCreateQueueRequest.html)la [AWS SDK para .NET API o la referencia](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/) de [SetQueueAttributes](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SetQueueAttributes.html)la [API de Amazon Simple Queue Service](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/).
+ En este ejemplo se especifica un sondeo prolongado de todos los mensajes de la cola creada. Esto se realiza mediante el atributo `ReceiveMessageWaitTimeSeconds`.

  También puedes especificar un sondeo prolongado durante una llamada a los `ReceiveMessageAsync` métodos de la SQSClient clase [Amazon](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/TSQSClient.html). Para obtener más información, consulte [Recepción de mensajes de Amazon SQS](ReceiveMessage.md).

  Para obtener información sobre los sondeos cortos frente a los sondeos largos, consulte [Sondeos cortos y largos](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-short-and-long-polling.html) en la *Guía para desarrolladores de Amazon Simple Queue Service*.
+ Una cola de mensajes fallidos es una cola a la que otras colas (de origen) pueden enviar mensajes que no se han procesado correctamente. Para obtener más información, consulte [Colas de mensajes fallidos de Amazon SQS](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-dead-letter-queues.html) en la Guía para desarrolladores de Amazon Simple Queue Service.
+ La lista de colas y los resultados de este ejemplo también se pueden ver en la [consola de Amazon SQS](https://console.aws.amazon.com/sqs).

# Actualización de colas de Amazon SQS
<a name="UpdateSqsQueue"></a>

En este ejemplo, se muestra cómo utilizarla AWS SDK para .NET para actualizar una cola de Amazon SQS. Tras realizar algunas comprobaciones, la aplicación actualiza el atributo especificado con el valor indicado y, a continuación, muestra todos los atributos de la cola.

Si solo se incluye la URL de cola en los argumentos de la línea de comandos, la aplicación simplemente muestra todos los atributos de la cola.

En las siguientes secciones se proporcionan fragmentos de código de este ejemplo. Tras ello, se muestra el [código completo del ejemplo](#UpdateSqsQueue-complete-code), que se puede compilar y ejecutar tal cual.

**Topics**
+ [

## Visualización de atributos de cola
](#UpdateSqsQueue-show-attributes)
+ [

## Validación del nombre de atributo
](#UpdateSqsQueue-validate-attribute)
+ [

## Actualización de un atributo de cola
](#UpdateSqsQueue-update-attribute)
+ [

## Código completo
](#UpdateSqsQueue-complete-code)
+ [

## Consideraciones adicionales
](#UpdateSqsQueue-additional)

## Visualización de atributos de cola
<a name="UpdateSqsQueue-show-attributes"></a>

El siguiente fragmento de código muestra los atributos de la cola identificada por la URL de cola especificada.

El ejemplo que aparece [al final de este tema](#UpdateSqsQueue-complete-code) muestra este fragmento de código en uso.

```
    //
    // Method to show all attributes of a queue
    private static async Task ShowAllAttributes(IAmazonSQS sqsClient, string qUrl)
    {
      GetQueueAttributesResponse responseGetAtt =
        await sqsClient.GetQueueAttributesAsync(qUrl,
          new List<string>{ QueueAttributeName.All });
      Console.WriteLine($"Queue: {qUrl}");
      foreach(var att in responseGetAtt.Attributes)
        Console.WriteLine($"\t{att.Key}: {att.Value}");
    }
```

## Validación del nombre de atributo
<a name="UpdateSqsQueue-validate-attribute"></a>

El siguiente fragmento de código valida el nombre del atributo que se está actualizando.

El ejemplo que aparece [al final de este tema](#UpdateSqsQueue-complete-code) muestra este fragmento de código en uso.

```
    //
    // Method to check the name of the attribute
    private static bool ValidAttribute(string attribute)
    {
      var attOk = false;
      var qAttNameType = typeof(QueueAttributeName);
      List<string> qAttNamefields = new List<string>();
      foreach(var field in qAttNameType.GetFields())
       qAttNamefields.Add(field.Name);
      foreach(var name in qAttNamefields)
        if(attribute == name) { attOk = true; break; }
      return attOk;
    }
```

## Actualización de un atributo de cola
<a name="UpdateSqsQueue-update-attribute"></a>

El siguiente fragmento de código actualiza un atributo de la cola identificada por la URL de cola especificada.

El ejemplo que aparece [al final de este tema](#UpdateSqsQueue-complete-code) muestra este fragmento de código en uso.

```
    //
    // Method to update a queue attribute
    private static async Task UpdateAttribute(
      IAmazonSQS sqsClient, string qUrl, string attribute, string value)
    {
      await sqsClient.SetQueueAttributesAsync(qUrl,
        new Dictionary<string, string>{{attribute, value}});
    }
```

## Código completo
<a name="UpdateSqsQueue-complete-code"></a>

En esta sección se muestran las referencias relevantes y el código completo de este ejemplo.

### Referencias de SDK
<a name="w2aac19c15c25c19c25b5b1"></a>

NuGet paquetes:
+ [AWSSDK.SQS](https://www.nuget.org/packages/AWSSDK.SQS)

Elementos de programación:
+ Espacio de nombres [Amazon.SQS](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/NSQS.html)

  Clase [Amazon SQSClient](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/TSQSClient.html)

  Clase [QueueAttributeName](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/TQueueAttributeName.html)
+ Espacio de nombres [Amazon.SQS.Model](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/NSQSModel.html)

  Clase [GetQueueAttributesResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/TGetQueueAttributesResponse.html)

### El código
<a name="w2aac19c15c25c19c25b7b1"></a>

```
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Amazon.SQS;
using Amazon.SQS.Model;

namespace SQSUpdateQueue
{
  // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  // Class to update a queue
  class Program
  {
    private const int MaxArgs = 3;
    private const int InvalidArgCount = 2;

    static async Task Main(string[] args)
    {
      // Parse the command line and show help if necessary
      var parsedArgs = CommandLine.Parse(args);
      if(parsedArgs.Count == 0)
      {
        PrintHelp();
        return;
      }
      if((parsedArgs.Count > MaxArgs) || (parsedArgs.Count == InvalidArgCount))
        CommandLine.ErrorExit("\nThe number of command-line arguments is incorrect." +
          "\nRun the command with no arguments to see help.");

      // Get the application arguments from the parsed list
      var qUrl = CommandLine.GetArgument(parsedArgs, null, "-q");
      var attribute = CommandLine.GetArgument(parsedArgs, null, "-a");
      var value = CommandLine.GetArgument(parsedArgs, null, "-v", "--value");

      if(string.IsNullOrEmpty(qUrl))
        CommandLine.ErrorExit("\nYou must supply at least a queue URL." +
          "\nRun the command with no arguments to see help.");

      // Create the Amazon SQS client
      var sqsClient = new AmazonSQSClient();

      // In the case of one command-line argument, just show the attributes for the queue
      if(parsedArgs.Count == 1)
        await ShowAllAttributes(sqsClient, qUrl);

      // Otherwise, attempt to update the given queue attribute with the given value
      else
      {
        // Check to see if the attribute is valid
        if(ValidAttribute(attribute))
        {
          // Perform the update and then show all the attributes of the queue
          await UpdateAttribute(sqsClient, qUrl, attribute, value);
          await ShowAllAttributes(sqsClient, qUrl);
        }
        else
        {
          Console.WriteLine($"\nThe given attribute name, {attribute}, isn't valid.");
        }
      }
    }


    //
    // Method to show all attributes of a queue
    private static async Task ShowAllAttributes(IAmazonSQS sqsClient, string qUrl)
    {
      GetQueueAttributesResponse responseGetAtt =
        await sqsClient.GetQueueAttributesAsync(qUrl,
          new List<string>{ QueueAttributeName.All });
      Console.WriteLine($"Queue: {qUrl}");
      foreach(var att in responseGetAtt.Attributes)
        Console.WriteLine($"\t{att.Key}: {att.Value}");
    }


    //
    // Method to check the name of the attribute
    private static bool ValidAttribute(string attribute)
    {
      var attOk = false;
      var qAttNameType = typeof(QueueAttributeName);
      List<string> qAttNamefields = new List<string>();
      foreach(var field in qAttNameType.GetFields())
       qAttNamefields.Add(field.Name);
      foreach(var name in qAttNamefields)
        if(attribute == name) { attOk = true; break; }
      return attOk;
    }


    //
    // Method to update a queue attribute
    private static async Task UpdateAttribute(
      IAmazonSQS sqsClient, string qUrl, string attribute, string value)
    {
      await sqsClient.SetQueueAttributesAsync(qUrl,
        new Dictionary<string, string>{{attribute, value}});
    }


    //
    // Command-line help
    private static void PrintHelp()
    {
      Console.WriteLine("\nUsage: SQSUpdateQueue -q queue_url [-a attribute -v value]");
      Console.WriteLine("  -q: The URL of the queue you want to update.");
      Console.WriteLine("  -a: The name of the attribute to update.");
      Console.WriteLine("  -v, --value: The value to assign to the attribute.");
    }
  }


  // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  // Class that represents a command line on the console or terminal.
  // (This is the same for all examples. When you have seen it once, you can ignore it.)
  static class CommandLine
  {
    //
    // Method to parse a command line of the form: "--key value" or "-k value".
    //
    // Parameters:
    // - args: The command-line arguments passed into the application by the system.
    //
    // Returns:
    // A Dictionary with string Keys and Values.
    //
    // If a key is found without a matching value, Dictionary.Value is set to the key
    //  (including the dashes).
    // If a value is found without a matching key, Dictionary.Key is set to "--NoKeyN",
    //  where "N" represents sequential numbers.
    public static Dictionary<string,string> Parse(string[] args)
    {
      var parsedArgs = new Dictionary<string,string>();
      int i = 0, n = 0;
      while(i < args.Length)
      {
        // If the first argument in this iteration starts with a dash it's an option.
        if(args[i].StartsWith("-"))
        {
          var key = args[i++];
          var value = key;

          // Check to see if there's a value that goes with this option?
          if((i < args.Length) && (!args[i].StartsWith("-"))) value = args[i++];
          parsedArgs.Add(key, value);
        }

        // If the first argument in this iteration doesn't start with a dash, it's a value
        else
        {
          parsedArgs.Add("--NoKey" + n.ToString(), args[i++]);
          n++;
        }
      }

      return parsedArgs;
    }

    //
    // Method to get an argument from the parsed command-line arguments
    //
    // Parameters:
    // - parsedArgs: The Dictionary object returned from the Parse() method (shown above).
    // - defaultValue: The default string to return if the specified key isn't in parsedArgs.
    // - keys: An array of keys to look for in parsedArgs.
    public static string GetArgument(
      Dictionary<string,string> parsedArgs, string defaultReturn, params string[] keys)
    {
      string retval = null;
      foreach(var key in keys)
        if(parsedArgs.TryGetValue(key, out retval)) break;
      return retval ?? defaultReturn;
    }

    //
    // Method to exit the application with an error.
    public static void ErrorExit(string msg, int code=1)
    {
      Console.WriteLine("\nError");
      Console.WriteLine(msg);
      Environment.Exit(code);
    }
  }

}
```

## Consideraciones adicionales
<a name="UpdateSqsQueue-additional"></a>
+ Para actualizar el `RedrivePolicy` atributo, debe citar el valor completo y evitar las comillas de los key/value pares, según corresponda a su sistema operativo.

  Por ejemplo, en Windows el valor se crea de forma similar a la siguiente:

  ```
  "{\"deadLetterTargetArn\":\"DEAD_LETTER-QUEUE-ARN\",\"maxReceiveCount\":\"10\"}"
  ```

# Eliminación de colas de Amazon SQS
<a name="DeleteSqsQueue"></a>

En este ejemplo, se muestra cómo utilizarla AWS SDK para .NET para eliminar una cola de Amazon SQS. La aplicación elimina la cola, espera un periodo de tiempo determinado a que desaparezca y, a continuación, muestra una lista de las colas restantes.

Si no proporciona ningún argumento de línea de comandos, la aplicación simplemente muestra una lista de las colas existentes.

En las siguientes secciones se proporcionan fragmentos de código de este ejemplo. Tras ello, se muestra el [código completo del ejemplo](#DeleteSqsQueue-complete-code), que se puede compilar y ejecutar tal cual.

**Topics**
+ [

## Eliminación de la cola
](#DeleteSqsQueue-delete-queue)
+ [

## Espera para que la cola desaparezca
](#DeleteSqsQueue-wait)
+ [

## Visualización de una lista de colas existentes
](#DeleteSqsQueue-list-queues)
+ [

## Código completo
](#DeleteSqsQueue-complete-code)
+ [

## Consideraciones adicionales
](#DeleteSqsQueue-additional)

## Eliminación de la cola
<a name="DeleteSqsQueue-delete-queue"></a>

El siguiente fragmento de código elimina la cola identificada por la URL de cola especificada.

El ejemplo que aparece [al final de este tema](#DeleteSqsQueue-complete-code) muestra este fragmento de código en uso.

```
    //
    // Method to delete an SQS queue
    private static async Task DeleteQueue(IAmazonSQS sqsClient, string qUrl)
    {
      Console.WriteLine($"Deleting queue {qUrl}...");
      await sqsClient.DeleteQueueAsync(qUrl);
      Console.WriteLine($"Queue {qUrl} has been deleted.");
    }
```

## Espera para que la cola desaparezca
<a name="DeleteSqsQueue-wait"></a>

El siguiente fragmento de código espera a que finalice el proceso de eliminación, que puede tardar 60 segundos.

El ejemplo que aparece [al final de este tema](#DeleteSqsQueue-complete-code) muestra este fragmento de código en uso.

```
    //
    // Method to wait up to a given number of seconds
    private static async Task Wait(
      IAmazonSQS sqsClient, int numSeconds, string qUrl)
    {
      Console.WriteLine($"Waiting for up to {numSeconds} seconds.");
      Console.WriteLine("Press any key to stop waiting. (Response might be slightly delayed.)");
      for(int i=0; i<numSeconds; i++)
      {
        Console.Write(".");
        Thread.Sleep(1000);
        if(Console.KeyAvailable) break;

        // Check to see if the queue is gone yet
        var found = false;
        ListQueuesResponse responseList = await sqsClient.ListQueuesAsync("");
        foreach(var url in responseList.QueueUrls)
        {
          if(url == qUrl)
          {
            found = true;
            break;
          }
        }
        if(!found) break;
      }
    }
```

## Visualización de una lista de colas existentes
<a name="DeleteSqsQueue-list-queues"></a>

El siguiente fragmento de código muestra una lista de las colas existentes en la región del cliente de SQS.

El ejemplo que aparece [al final de este tema](#DeleteSqsQueue-complete-code) muestra este fragmento de código en uso.

```
    //
    // Method to show a list of the existing queues
    private static async Task ListQueues(IAmazonSQS sqsClient)
    {
      ListQueuesResponse responseList = await sqsClient.ListQueuesAsync("");
      Console.WriteLine("\nList of queues:");
      foreach(var qUrl in responseList.QueueUrls)
        Console.WriteLine($"- {qUrl}");
    }
```

## Código completo
<a name="DeleteSqsQueue-complete-code"></a>

En esta sección se muestran las referencias relevantes y el código completo de este ejemplo.

### Referencias de SDK
<a name="w2aac19c15c25c21c25b5b1"></a>

NuGet paquetes:
+ [AWSSDK.SQS](https://www.nuget.org/packages/AWSSDK.SQS)

Elementos de programación:
+ Espacio de nombres [Amazon.SQS](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/NSQS.html)

  Clase [Amazon SQSClient](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/TSQSClient.html)
+ Espacio de nombres [Amazon.SQS.Model](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/NSQSModel.html)

  Clase [ListQueuesResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/TListQueuesResponse.html)

### El código
<a name="w2aac19c15c25c21c25b7b1"></a>

```
using System;
using System.Threading;
using System.Threading.Tasks;
using Amazon.SQS;
using Amazon.SQS.Model;

namespace SQSDeleteQueue
{
  // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  // Class to update a queue
  class Program
  {
    private const int TimeToWait = 60;

    static async Task Main(string[] args)
    {
      // Create the Amazon SQS client
      var sqsClient = new AmazonSQSClient();

      // If no command-line arguments, just show a list of the queues
      if(args.Length == 0)
      {
        Console.WriteLine("\nUsage: SQSCreateQueue queue_url");
        Console.WriteLine("   queue_url - The URL of the queue you want to delete.");
        Console.WriteLine("\nNo arguments specified.");
        Console.Write("Do you want to see a list of the existing queues? ((y) or n): ");
        var response = Console.ReadLine();
        if((string.IsNullOrEmpty(response)) || (response.ToLower() == "y"))
          await ListQueues(sqsClient);
        return;
      }

      // If given a queue URL, delete that queue
      if(args[0].StartsWith("https://sqs."))
      {
        // Delete the queue
        await DeleteQueue(sqsClient, args[0]);
        // Wait for a little while because it takes a while for the queue to disappear
        await Wait(sqsClient, TimeToWait, args[0]);
        // Show a list of the remaining queues
        await ListQueues(sqsClient);
      }
      else
      {
        Console.WriteLine("The command-line argument isn't a queue URL:");
        Console.WriteLine($"{args[0]}");
      }
    }


    //
    // Method to delete an SQS queue
    private static async Task DeleteQueue(IAmazonSQS sqsClient, string qUrl)
    {
      Console.WriteLine($"Deleting queue {qUrl}...");
      await sqsClient.DeleteQueueAsync(qUrl);
      Console.WriteLine($"Queue {qUrl} has been deleted.");
    }


    //
    // Method to wait up to a given number of seconds
    private static async Task Wait(
      IAmazonSQS sqsClient, int numSeconds, string qUrl)
    {
      Console.WriteLine($"Waiting for up to {numSeconds} seconds.");
      Console.WriteLine("Press any key to stop waiting. (Response might be slightly delayed.)");
      for(int i=0; i<numSeconds; i++)
      {
        Console.Write(".");
        Thread.Sleep(1000);
        if(Console.KeyAvailable) break;

        // Check to see if the queue is gone yet
        var found = false;
        ListQueuesResponse responseList = await sqsClient.ListQueuesAsync("");
        foreach(var url in responseList.QueueUrls)
        {
          if(url == qUrl)
          {
            found = true;
            break;
          }
        }
        if(!found) break;
      }
    }


    //
    // Method to show a list of the existing queues
    private static async Task ListQueues(IAmazonSQS sqsClient)
    {
      ListQueuesResponse responseList = await sqsClient.ListQueuesAsync("");
      Console.WriteLine("\nList of queues:");
      foreach(var qUrl in responseList.QueueUrls)
        Console.WriteLine($"- {qUrl}");
    }
  }
}
```

## Consideraciones adicionales
<a name="DeleteSqsQueue-additional"></a>
+ La llamada a la API `DeleteQueueAsync` no comprueba si la cola que se va a eliminar se está usando como cola de mensajes fallidos. Esto podría comprobarse con un procedimiento más elaborado.
+ La lista de colas y los resultados de este ejemplo también se pueden ver en la [consola de Amazon SQS](https://console.aws.amazon.com/sqs).

# Envío de mensajes de Amazon SQS
<a name="SendMessage"></a>

[En este ejemplo, se muestra cómo utilizarla AWS SDK para .NET para enviar mensajes a una cola de Amazon SQS, que puede crear [mediante programación](CreateQueue.md) o mediante la consola de Amazon SQS.](https://console.aws.amazon.com/sqs) La aplicación envía un único mensaje a la cola y, a continuación, un lote de mensajes. Después, la aplicación espera a que el usuario especifique información, que pueden ser más mensajes para enviarlos a la cola o una solicitud para salir de la aplicación.

Este ejemplo y el [siguiente, que ilustra cómo recibir mensajes](ReceiveMessage.md), se pueden usar juntos para ver el flujo de mensajes en Amazon SQS.

En las siguientes secciones se proporcionan fragmentos de código de este ejemplo. Tras ello, se muestra el [código completo del ejemplo](#SendMessage-complete-code), que se puede compilar y ejecutar tal cual.

**Topics**
+ [

## Enviar un mensaje
](#SendMessage-send-message)
+ [

## Envío de un lote de mensajes
](#SendMessage-send-batch)
+ [

## Eliminación de todos los mensajes de la cola
](#SendMessage-purge-messages)
+ [

## Código completo
](#SendMessage-complete-code)
+ [

## Consideraciones adicionales
](#SendMessage-additional)

## Enviar un mensaje
<a name="SendMessage-send-message"></a>

El siguiente fragmento de código envía un mensaje a la cola identificada por la URL de cola especificada.

El ejemplo que aparece [al final de este tema](#SendMessage-complete-code) muestra este fragmento de código en uso.

```
    //
    // Method to put a message on a queue
    // Could be expanded to include message attributes, etc., in a SendMessageRequest
    private static async Task SendMessage(
      IAmazonSQS sqsClient, string qUrl, string messageBody)
    {
      SendMessageResponse responseSendMsg =
        await sqsClient.SendMessageAsync(qUrl, messageBody);
      Console.WriteLine($"Message added to queue\n  {qUrl}");
      Console.WriteLine($"HttpStatusCode: {responseSendMsg.HttpStatusCode}");
    }
```

## Envío de un lote de mensajes
<a name="SendMessage-send-batch"></a>

El siguiente fragmento de código envía un lote de mensajes a la cola identificada por la URL de cola especificada.

El ejemplo que aparece [al final de este tema](#SendMessage-complete-code) muestra este fragmento de código en uso.

```
    //
    // Method to put a batch of messages on a queue
    // Could be expanded to include message attributes, etc.,
    // in the SendMessageBatchRequestEntry objects
    private static async Task SendMessageBatch(
      IAmazonSQS sqsClient, string qUrl, List<SendMessageBatchRequestEntry> messages)
    {
      Console.WriteLine($"\nSending a batch of messages to queue\n  {qUrl}");
      SendMessageBatchResponse responseSendBatch =
        await sqsClient.SendMessageBatchAsync(qUrl, messages);
      // Could test responseSendBatch.Failed here
      foreach(SendMessageBatchResultEntry entry in responseSendBatch.Successful)
        Console.WriteLine($"Message {entry.Id} successfully queued.");
    }
```

## Eliminación de todos los mensajes de la cola
<a name="SendMessage-purge-messages"></a>

El siguiente fragmento de código elimina todos los mensajes de la cola identificada por la URL de cola especificada. Esto se conoce también como *purgar la cola*.

El ejemplo que aparece [al final de este tema](#SendMessage-complete-code) muestra este fragmento de código en uso.

```
    //
    // Method to delete all messages from the queue
    private static async Task DeleteAllMessages(IAmazonSQS sqsClient, string qUrl)
    {
      Console.WriteLine($"\nPurging messages from queue\n  {qUrl}...");
      PurgeQueueResponse responsePurge = await sqsClient.PurgeQueueAsync(qUrl);
      Console.WriteLine($"HttpStatusCode: {responsePurge.HttpStatusCode}");
    }
```

## Código completo
<a name="SendMessage-complete-code"></a>

En esta sección se muestran las referencias relevantes y el código completo de este ejemplo.

### Referencias de SDK
<a name="w2aac19c15c25c23c25b5b1"></a>

NuGet paquetes:
+ [AWSSDK.SQS](https://www.nuget.org/packages/AWSSDK.SQS)

Elementos de programación:
+ Espacio de nombres [Amazon.SQS](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/NSQS.html)

  Clase [Amazon SQSClient](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/TSQSClient.html)
+ Espacio de nombres [Amazon.SQS.Model](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/NSQSModel.html)

  Clase [PurgeQueueResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/TPurgeQueueResponse.html)

  Clase [SendMessageBatchResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/TSendMessageBatchResponse.html)

  Clase [SendMessageResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/TSendMessageResponse.html)

  Clase [SendMessageBatchRequestEntry](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/TSendMessageBatchRequestEntry.html)

  Clase [SendMessageBatchResultEntry](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/TSendMessageBatchResultEntry.html)

### El código
<a name="w2aac19c15c25c23c25b7b1"></a>

```
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Amazon.SQS;
using Amazon.SQS.Model;

namespace SQSSendMessages
{
  // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  // Class to send messages to a queue
  class Program
  {
    // Some example messages to send to the queue
    private const string JsonMessage = "{\"product\":[{\"name\":\"Product A\",\"price\": \"32\"},{\"name\": \"Product B\",\"price\": \"27\"}]}";
    private const string XmlMessage = "<products><product name=\"Product A\" price=\"32\" /><product name=\"Product B\" price=\"27\" /></products>";
    private const string CustomMessage = "||product|Product A|32||product|Product B|27||";
    private const string TextMessage = "Just a plain text message.";

    static async Task Main(string[] args)
    {
      // Do some checks on the command-line
      if(args.Length == 0)
      {
        Console.WriteLine("\nUsage: SQSSendMessages queue_url");
        Console.WriteLine("   queue_url - The URL of an existing SQS queue.");
        return;
      }
      if(!args[0].StartsWith("https://sqs."))
      {
        Console.WriteLine("\nThe command-line argument isn't a queue URL:");
        Console.WriteLine($"{args[0]}");
        return;
      }

      // Create the Amazon SQS client
      var sqsClient = new AmazonSQSClient();

      // (could verify that the queue exists)
      // Send some example messages to the given queue
      // A single message
      await SendMessage(sqsClient, args[0], JsonMessage);

      // A batch of messages
      var batchMessages = new List<SendMessageBatchRequestEntry>{
        new SendMessageBatchRequestEntry("xmlMsg", XmlMessage),
        new SendMessageBatchRequestEntry("customeMsg", CustomMessage),
        new SendMessageBatchRequestEntry("textMsg", TextMessage)};
      await SendMessageBatch(sqsClient, args[0], batchMessages);

      // Let the user send their own messages or quit
      await InteractWithUser(sqsClient, args[0]);

      // Delete all messages that are still in the queue
      await DeleteAllMessages(sqsClient, args[0]);
    }


    //
    // Method to put a message on a queue
    // Could be expanded to include message attributes, etc., in a SendMessageRequest
    private static async Task SendMessage(
      IAmazonSQS sqsClient, string qUrl, string messageBody)
    {
      SendMessageResponse responseSendMsg =
        await sqsClient.SendMessageAsync(qUrl, messageBody);
      Console.WriteLine($"Message added to queue\n  {qUrl}");
      Console.WriteLine($"HttpStatusCode: {responseSendMsg.HttpStatusCode}");
    }


    //
    // Method to put a batch of messages on a queue
    // Could be expanded to include message attributes, etc.,
    // in the SendMessageBatchRequestEntry objects
    private static async Task SendMessageBatch(
      IAmazonSQS sqsClient, string qUrl, List<SendMessageBatchRequestEntry> messages)
    {
      Console.WriteLine($"\nSending a batch of messages to queue\n  {qUrl}");
      SendMessageBatchResponse responseSendBatch =
        await sqsClient.SendMessageBatchAsync(qUrl, messages);
      // Could test responseSendBatch.Failed here
      foreach(SendMessageBatchResultEntry entry in responseSendBatch.Successful)
        Console.WriteLine($"Message {entry.Id} successfully queued.");
    }


    //
    // Method to get input from the user
    // They can provide messages to put in the queue or exit the application
    private static async Task InteractWithUser(IAmazonSQS sqsClient, string qUrl)
    {
      string response;
      while (true)
      {
        // Get the user's input
        Console.WriteLine("\nType a message for the queue or \"exit\" to quit:");
        response = Console.ReadLine();
        if(response.ToLower() == "exit") break;

        // Put the user's message in the queue
        await SendMessage(sqsClient, qUrl, response);
      }
    }


    //
    // Method to delete all messages from the queue
    private static async Task DeleteAllMessages(IAmazonSQS sqsClient, string qUrl)
    {
      Console.WriteLine($"\nPurging messages from queue\n  {qUrl}...");
      PurgeQueueResponse responsePurge = await sqsClient.PurgeQueueAsync(qUrl);
      Console.WriteLine($"HttpStatusCode: {responsePurge.HttpStatusCode}");
    }
  }
}
```

## Consideraciones adicionales
<a name="SendMessage-additional"></a>
+ Para obtener información sobre las diferentes limitaciones de los mensajes, incluidos los caracteres permitidos, consulte [Cuotas de los mensajes](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-quotas.html#quotas-messages) en la [Guía para desarrolladores de Amazon Simple Queue Service](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/).
+ Los mensajes permanecen en las colas hasta que se eliminan o hasta que la cola se purga. Cuando una aplicación ha recibido un mensaje, este no estará visible en la cola aunque siga existiendo en ella. Para obtener más información sobre los tiempos de espera de visibilidad, consulte [Tiempo de espera de visibilidad de Amazon SQS](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/AboutVT.html).
+ Además del cuerpo del mensaje, también se pueden agregar atributos a los mensajes. Para obtener más información, consulte [Metadatos de mensajes](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-message-metadata.html).

# Recepción de mensajes de Amazon SQS
<a name="ReceiveMessage"></a>

[En este ejemplo, se muestra cómo utilizarla AWS SDK para .NET para recibir mensajes de una cola de Amazon SQS, que puede crear [mediante programación](CreateQueue.md) o mediante la consola de Amazon SQS.](https://console.aws.amazon.com/sqs) La aplicación lee un solo mensaje de la cola, lo procesa (en este caso, muestra el cuerpo del mensaje en la consola) y, a continuación, lo elimina de la cola. La aplicación repite estos pasos hasta que el usuario pulse una tecla del teclado.

Este ejemplo y el [anterior, que ilustra cómo enviar mensajes](SendMessage.md), se pueden usar juntos para ver el flujo de mensajes en Amazon SQS.

En las siguientes secciones se proporcionan fragmentos de código de este ejemplo. Tras ello, se muestra el [código completo del ejemplo](#ReceiveMessage-complete-code), que se puede compilar y ejecutar tal cual.

**Topics**
+ [

## Recepción de un mensaje
](#ReceiveMessage-receive)
+ [

## Eliminación de un mensaje
](#ReceiveMessage-delete)
+ [

## Código completo
](#ReceiveMessage-complete-code)
+ [

## Consideraciones adicionales
](#ReceiveMessage-additional)

## Recepción de un mensaje
<a name="ReceiveMessage-receive"></a>

El siguiente fragmento de código recibe un mensaje de la cola identificada por la URL de cola especificada.

El ejemplo que aparece [al final de este tema](#ReceiveMessage-complete-code) muestra este fragmento de código en uso.

```
    //
    // Method to read a message from the given queue
    // In this example, it gets one message at a time
    private static async Task<ReceiveMessageResponse> GetMessage(
      IAmazonSQS sqsClient, string qUrl, int waitTime=0)
    {
      return await sqsClient.ReceiveMessageAsync(new ReceiveMessageRequest{
        QueueUrl=qUrl,
        MaxNumberOfMessages=MaxMessages,
        WaitTimeSeconds=waitTime
        // (Could also request attributes, set visibility timeout, etc.)
      });
    }
```

## Eliminación de un mensaje
<a name="ReceiveMessage-delete"></a>

El siguiente fragmento de código elimina un mensaje de la cola identificada por la URL de cola especificada.

El ejemplo que aparece [al final de este tema](#ReceiveMessage-complete-code) muestra este fragmento de código en uso.

```
    //
    // Method to delete a message from a queue
    private static async Task DeleteMessage(
      IAmazonSQS sqsClient, Message message, string qUrl)
    {
      Console.WriteLine($"\nDeleting message {message.MessageId} from queue...");
      await sqsClient.DeleteMessageAsync(qUrl, message.ReceiptHandle);
    }
```

## Código completo
<a name="ReceiveMessage-complete-code"></a>

En esta sección se muestran las referencias relevantes y el código completo de este ejemplo.

### Referencias de SDK
<a name="w2aac19c15c25c25c21b5b1"></a>

NuGet paquetes:
+ [AWSSDK.SQS](https://www.nuget.org/packages/AWSSDK.SQS)

Elementos de programación:
+ Espacio de nombres [Amazon.SQS](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/NSQS.html)

  Clase [Amazon SQSClient](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/TSQSClient.html)
+ Espacio de nombres [Amazon.SQS.Model](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/NSQSModel.html)

  Clase [ReceiveMessageRequest](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/TReceiveMessageRequest.html)

  Clase [ReceiveMessageResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/TReceiveMessageResponse.html)

### El código
<a name="w2aac19c15c25c25c21b7b1"></a>

```
using System;
using System.Threading.Tasks;
using Amazon.SQS;
using Amazon.SQS.Model;

namespace SQSReceiveMessages
{
  class Program
  {
    private const int MaxMessages = 1;
    private const int WaitTime = 2;
    static async Task Main(string[] args)
    {
      // Do some checks on the command-line
      if(args.Length == 0)
      {
        Console.WriteLine("\nUsage: SQSReceiveMessages queue_url");
        Console.WriteLine("   queue_url - The URL of an existing SQS queue.");
        return;
      }
      if(!args[0].StartsWith("https://sqs."))
      {
        Console.WriteLine("\nThe command-line argument isn't a queue URL:");
        Console.WriteLine($"{args[0]}");
        return;
      }

      // Create the Amazon SQS client
      var sqsClient = new AmazonSQSClient();

      // (could verify that the queue exists)
      // Read messages from the queue and perform appropriate actions
      Console.WriteLine($"Reading messages from queue\n  {args[0]}");
      Console.WriteLine("Press any key to stop. (Response might be slightly delayed.)");
      do
      {
        var msg = await GetMessage(sqsClient, args[0], WaitTime);
        if(msg.Messages.Count != 0)
        {
          if(ProcessMessage(msg.Messages[0]))
            await DeleteMessage(sqsClient, msg.Messages[0], args[0]);
        }
      } while(!Console.KeyAvailable);
    }


    //
    // Method to read a message from the given queue
    // In this example, it gets one message at a time
    private static async Task<ReceiveMessageResponse> GetMessage(
      IAmazonSQS sqsClient, string qUrl, int waitTime=0)
    {
      return await sqsClient.ReceiveMessageAsync(new ReceiveMessageRequest{
        QueueUrl=qUrl,
        MaxNumberOfMessages=MaxMessages,
        WaitTimeSeconds=waitTime
        // (Could also request attributes, set visibility timeout, etc.)
      });
    }


    //
    // Method to process a message
    // In this example, it simply prints the message
    private static bool ProcessMessage(Message message)
    {
      Console.WriteLine($"\nMessage body of {message.MessageId}:");
      Console.WriteLine($"{message.Body}");
      return true;
    }


    //
    // Method to delete a message from a queue
    private static async Task DeleteMessage(
      IAmazonSQS sqsClient, Message message, string qUrl)
    {
      Console.WriteLine($"\nDeleting message {message.MessageId} from queue...");
      await sqsClient.DeleteMessageAsync(qUrl, message.ReceiptHandle);
    }
  }
}
```

## Consideraciones adicionales
<a name="ReceiveMessage-additional"></a>
+ Para especificar un sondeo prolongado, en este ejemplo se usa la propiedad `WaitTimeSeconds` en cada llamada al método `ReceiveMessageAsync`.

  También se puede especificar un sondeo prolongado para todos los mensajes de una cola usando el atributo `ReceiveMessageWaitTimeSeconds` al [crear](CreateQueue.md) o [actualizar](UpdateSqsQueue.md) la cola.

  Para obtener información sobre los sondeos cortos frente a los sondeos largos, consulte [Sondeos cortos y largos](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-short-and-long-polling.html) en la *Guía para desarrolladores de Amazon Simple Queue Service*.
+ Durante el procesamiento de los mensajes, puede utilizar el controlador de recepción para cambiar el tiempo de espera de visibilidad de los mensajes. Para obtener información sobre cómo hacerlo, consulta los `ChangeMessageVisibilityAsync` métodos de la SQSClient clase [Amazon](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/TSQSClient.html).
+ Cuando se llama al método `DeleteMessageAsync` sin condiciones, el mensaje se elimina de la cola, sin importar la configuración del tiempo de espera de visibilidad.

# Uso de AWS Lambda como servicio de computación
<a name="aws-lambda"></a>

AWS SDK para .NET admite AWS Lambda, que permite ejecutar código sin aprovisionar ni administrar servidores. Para obtener más información, consulte la [página del producto AWS Lambda](https://aws.amazon.com/lambda/) y la [Guía para desarrolladores de AWS Lambda](https://docs.aws.amazon.com/lambda/latest/dg/), especialmente la sección [Trabajar con C\$1](https://docs.aws.amazon.com/lambda/latest/dg/lambda-csharp.html).

## API
<a name="w2aac19c17b5"></a>

AWS SDK para .NET proporciona API para AWS Lambda. Las API permiten trabajar con características de Lambda, como, por ejemplo, [funciones](https://docs.aws.amazon.com/lambda/latest/dg/gettingstarted-concepts.html#gettingstarted-concepts-function), [desencadenadores](https://docs.aws.amazon.com/lambda/latest/dg/gettingstarted-concepts.html#gettingstarted-concepts-trigger) y [eventos](https://docs.aws.amazon.com/lambda/latest/dg/gettingstarted-concepts.html#gettingstarted-concepts-event). Para ver el conjunto de API completo, consulte [Lambda](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/Lambda/NLambda.html) en [Referencia de API de AWS SDK para .NET](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/).

Las API de Lambda se proporcionan mediante [paquetes NuGet](https://www.nuget.org/packages?page=2&q=aws%20lambda&sortBy=relevance).

## Requisitos previos
<a name="w2aac19c17b7"></a>

Antes de comenzar, asegúrese de que ha [configurado el entorno y el proyecto](net-dg-config.md). Revise también la información en [Características de SDK](net-dg-sdk-features.md).

## Información adicional
<a name="w2aac19c17b9"></a>

Consulte [Integración de AWS con .NET Aspire](aspire-integrations.md) para obtener información sobre el desarrollo con AWS Lambda mediante .NET Aspire.

## Temas
<a name="w2aac19c17c11"></a>

**Topics**
+ [

## API
](#w2aac19c17b5)
+ [

## Requisitos previos
](#w2aac19c17b7)
+ [

## Información adicional
](#w2aac19c17b9)
+ [

## Temas
](#w2aac19c17c11)
+ [Lambda Annotations](aws-lambda-annotations.md)

# Uso de anotaciones para escribir funciones de AWS Lambda
<a name="aws-lambda-annotations"></a>

Al escribir funciones de Lambda, a veces es necesario escribir una gran cantidad de código de controlador y actualizar plantillas de AWS CloudFormation, entre otras tareas. Lambda Annotations es un marco que ayuda a aliviar estas cargas con las funciones de Lambda de .NET 6, lo que hace que la experiencia de escribir Lambda resulte más natural en C\$1.

Considere los siguientes fragmentos de código, en los que se suman dos números, como ejemplo de las ventajas de utilizar el marco Lambda Annotations.

**Sin Lambda Annotations**

```
public class Functions
{
    public APIGatewayProxyResponse LambdaMathPlus(APIGatewayProxyRequest request, ILambdaContext context)
    {
        if (!request.PathParameters.TryGetValue("x", out var xs))
        {
            return new APIGatewayProxyResponse
            {
                StatusCode = (int)HttpStatusCode.BadRequest
            };
        }
        if (!request.PathParameters.TryGetValue("y", out var ys))
        {
            return new APIGatewayProxyResponse
            {
                StatusCode = (int)HttpStatusCode.BadRequest
            };
        }

        var x = int.Parse(xs);
        var y = int.Parse(ys);

        return new APIGatewayProxyResponse
        {
            StatusCode = (int)HttpStatusCode.OK,
            Body = (x + y).ToString(),
            Headers = new Dictionary<string, string> { { "Content-Type", "text/plain" } }
        };
    } 
}
```

**Con Lambda Annotations**

```
public class Functions
{
    [LambdaFunction]
    [RestApi("/plus/{x}/{y}")]
    public int Plus(int x, int y)
    {
        return x + y;
    }
}
```

Como se muestra en el ejemplo, Lambda Annotations permite prescindir de tener que usar código repetitivo en cierta medida.

Para saber cómo utilizar el marco, así como obtener información adicional, consulte los siguientes recursos:
+ [README de GitHub](https://github.com/aws/aws-lambda-dotnet/blob/master/Libraries/src/Amazon.Lambda.Annotations/README.md), para obtener documentación sobre las API y los atributos de las Lambda Annotations.
+ La [entrada de blog](https://aws.amazon.com/blogs/developer/net-lambda-annotations-framework/) de Lambda Annotations.
+ El paquete NuGet [https://www.nuget.org/packages/Amazon.Lambda.Annotations](https://www.nuget.org/packages/Amazon.Lambda.Annotations).
+ [Proyecto PhotoAssetManagement](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/dotnetv3/cross-service/PhotoAssetManager) en GitHub. En concreto, consulte la carpeta [PamApiAnnotations](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/dotnetv3/cross-service/PhotoAssetManager/PamApiAnnotations) y las referencias a Lambda Annotations del archivo [README](https://github.com/awsdocs/aws-doc-sdk-examples/blob/main/dotnetv3/cross-service/PhotoAssetManager/README.md) del proyecto.

# Bibliotecas y marcos de alto nivel para AWS SDK para .NET
<a name="high-level-libraries"></a>

Las siguientes secciones contienen información sobre bibliotecas y marcos de alto nivel que no forman parte de la funcionalidad principal del SDK. Estas bibliotecas y marcos utilizan la funcionalidad principal del SDK para crear funciones que faciliten determinadas tareas.

Si no está familiarizado con AWS SDK para .NET, quizás le convenga echar un vistazo primero al tema [Recorrido rápido](quick-start.md). que sirve de introducción a SDK.

Antes de comenzar, asegúrese de que ha [configurado el entorno y el proyecto](net-dg-config.md). Revise también la información en [Características de SDK](net-dg-sdk-features.md).

**Topics**
+ [Marco de procesamiento de mensajes](msg-proc-fw.md)
+ [Integración de AWS con .NET Aspire](aspire-integrations.md)

# AWS Marco de procesamiento de mensajes para .NET
<a name="msg-proc-fw"></a>

El Marco de procesamiento de mensajes de AWS para .NET es un marco nativo de AWS que simplifica el desarrollo de aplicaciones de procesamiento de mensajes de .NET que utilizan servicios de AWS como Amazon Simple Queue Service (SQS), Amazon Simple Notification Service (SNS) y Amazon EventBridge. El marco reduce la cantidad de código repetitivo que deben escribir los desarrolladores, lo que le permite centrarse en la lógica empresarial a la hora de publicar y consumir mensajes. Para obtener detalles sobre cómo el marco puede simplificar su desarrollo, consulte la entrada del blog [Introducción al Marco de procesamiento de mensajes de AWS para .NET (versión preliminar)](https://aws.amazon.com/blogs/developer/introducing-the-aws-message-processing-framework-for-net-preview/). La primera parte, en particular, ofrece una demostración que muestra la diferencia entre usar llamadas a la API de bajo nivel y usar el marco.

El Marco de procesamiento de mensajes admite las siguientes actividades y características:
+ Enviar mensajes a SQS y publicar eventos en SNS y EventBridge.
+ Recibir y gestionar los mensajes de SQS mediante un sondeador de larga duración, que se suele utilizar en los servicios en segundo plano. Esto incluye administrar el tiempo de espera de visibilidad mientras se está gestionando un mensaje para evitar que otros clientes lo procesen.
+ Gestión de mensajes en funciones de AWS Lambda
+ Colas de SQS FIFO (primero en entrar, primero en salir) y temas de SNS.
+ OpenTelemetry para el registro.

Para obtener más información sobre estas actividades y características, consulte la sección **Características** de la [entrada del blog](https://aws.amazon.com/blogs/developer/introducing-the-aws-message-processing-framework-for-net-preview/) y los temas que se indican a continuación.

Antes de comenzar, asegúrese de que ha [configurado el entorno y el proyecto](net-dg-config.md). Revise también la información disponible en [Características de SDK](net-dg-sdk-features.md).

**Recursos adicionales**
+ El paquete [https://www.nuget.org/packages/AWS.Messaging/](https://www.nuget.org/packages/AWS.Messaging/) en [NuGet.org](https://www.nuget.org/).
+ La [Referencia de la API](https://aws.github.io/aws-dotnet-messaging/).
+ El archivo `README` en el repositorio de GitHub en [https://github.com/aws/aws-dotnet-messaging/](https://github.com/aws/aws-dotnet-messaging/).
+ [Inyección de dependencias de.NET](https://learn.microsoft.com/en-us/dotnet/core/extensions/dependency-injection) de Microsoft.
+ [.NET Generic Host](https://learn.microsoft.com/en-us/dotnet/core/extensions/generic-host) de Microsoft.

**Topics**
+ [Introducción](msg-proc-fw-get-started.md)
+ [Publicación de mensajes](msg-proc-fw-publish.md)
+ [Consumo de mensajes](msg-proc-fw-consume.md)
+ [FIFO](msg-proc-fw-fifo.md)
+ [Registro y telemetría abierta](msg-proc-fw-telemetry.md)
+ [Personalización](msg-proc-fw-customize.md)
+ [Seguridad](msg-proc-fw-security.md)

# Introducción al Marco de procesamiento de mensajes de AWS para .NET
<a name="msg-proc-fw-get-started"></a>

Antes de comenzar, asegúrese de que ha [configurado el entorno y el proyecto](net-dg-config.md). Revise también la información en [Características de SDK](net-dg-sdk-features.md).

En este tema se proporciona información que le ayudará a empezar a utilizar el Marco de procesamiento de mensajes. Además de la información sobre los requisitos previos y la configuración, se proporciona un tutorial que muestra cómo implementar un escenario común.

## Requisitos previos y configuración
<a name="mpf-get-started-prereq"></a>
+ Las credenciales que proporcione para su aplicación deben tener los permisos adecuados para el servicio de mensajería y las operaciones que este utilice. Para obtener más información, consulte los temas de seguridad de [SQS](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-authentication-and-access-control.html), [SNS](https://docs.aws.amazon.com/sns/latest/dg/security-iam.html) y [EventBridge](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-iam.html) en sus respectivas guías para desarrolladores. Consulte también la parte del archivo [README](https://github.com/aws/aws-dotnet-messaging/) en GitHub donde se explican los [permisos](https://github.com/aws/aws-dotnet-messaging/blob/main/README.md#permissions) específicos.
+ Para usar el Marco de procesamiento de mensajes de AWS para.NET, debe añadir el paquete [https://www.nuget.org/packages/AWS.Messaging](https://www.nuget.org/packages/AWS.Messaging) de NuGet a su proyecto. Por ejemplo:

  ```
  dotnet add package AWS.Messaging
  ```
+ El marco se integra con el [contenedor de servicios de inyección de dependencias (DI)](https://learn.microsoft.com/en-us/dotnet/core/extensions/dependency-injection) de .NET. Puede configurar el marco durante el inicio de la aplicación llamando a `AddAWSMessageBus` para añadirlo al contenedor de DI.

  ```
  var builder = WebApplication.CreateBuilder(args);
  
  // Register the AWS Message Processing Framework for .NET
  builder.Services.AddAWSMessageBus(builder =>
  {
      // Register that you'll publish messages of type ChatMessage to an existing queue
      builder.AddSQSPublisher<ChatMessage>("https://sqs.us-west-2.amazonaws.com/012345678910/MyAppProd");
  });
  ```

## Tutorial
<a name="mpf-get-started-tutorial"></a>

Este tutorial muestra cómo utilizar el Marco de procesamiento de mensajes de AWS para .NET. Crea dos aplicaciones: una API mínima ASP.NET Core que envía mensajes a una cola de Amazon SQS cuando recibe una solicitud en un punto de conexión de la API, y una aplicación de consola de larga duración que sondea estos mensajes y los gestiona. 
+ Las instrucciones de este tutorial se centran en la CLI de .NET, pero puede aplicarlas tanto con herramientas multiplataforma como con la CLI de .NET o Microsoft Visual Studio. Para obtener más información sobre estas herramientas, consulte [Instalación y configuración de la cadena de herramientas](net-dg-dev-env.md).
+ En este tutorial se da por supuesto que utiliza su perfil `[default]` para las credenciales. Asimismo, se presupone que dispone de credenciales a corto plazo con los permisos adecuados para enviar y recibir mensajes de Amazon SQS. Para obtener más información, consulte [Configure la autenticación del SDK con AWS](creds-idc.md) y los temas de seguridad de [SQS](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-authentication-and-access-control.html).

**nota**  
Al ejecutar este tutorial, puede incurrir en costes de mensajería de SQS.

### Pasos
<a name="mpf-tutorial-steps"></a>
+ [Creación de una cola de SQS](#mpf-tutorial-queue)
+ [Creación y ejecución de la aplicación de publicación](#mpf-tutorial-publish)
+ [Creación y ejecución de la aplicación de procesamiento](#mpf-tutorial-handle)
+ [Eliminación](#mpf-tutorial-cleanup)

### Creación de una cola de SQS
<a name="mpf-tutorial-queue"></a>

Este tutorial requiere una cola de SQS para enviar y recibir mensajes. Se puede crear una cola utilizando uno de los siguientes comandos para la AWS CLI o las Herramientas de AWS para PowerShell. Anote la URL de la cola que se devuelve para poder especificarla en la configuración del marco que se indica a continuación.

------
#### [ AWS CLI ]

```
aws sqs create-queue --queue-name DemoQueue
```

------
#### [ Herramientas de AWS para PowerShell ]

```
New-SQSQueue -QueueName DemoQueue
```

------

### Creación y ejecución de la aplicación de publicación
<a name="mpf-tutorial-publish"></a>

Utilice el siguiente procedimiento para crear y ejecutar la aplicación de publicación.

1. Abra un símbolo del sistema o un terminal. Busque o cree una carpeta del sistema operativo en la que pueda crear un proyecto .NET.

1. En esa carpeta, ejecute el siguiente comando para crear el proyecto .NET.

   ```
   dotnet new webapi --name Publisher
   ```

1. Acceda a la carpeta del proyecto nuevo. Añada una dependencia en el Marco de procesamiento de mensajes de AWS para .NET.

   ```
   cd Publisher
   dotnet add package AWS.Messaging
   ```
**nota**  
Si utiliza AWS IAM Identity Center para la autenticación, no olvide añadir también `AWSSDK.SSO` y `AWSSDK.SSOOIDC`.

1. Reemplace el código de `Program.cs` con lo siguiente:

   ```
   using AWS.Messaging;
   using Microsoft.AspNetCore.Mvc;
   using Publisher;
   
   var builder = WebApplication.CreateBuilder(args);
   
   // Add services to the container.
   // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle.
   builder.Services.AddEndpointsApiExplorer();
   builder.Services.AddSwaggerGen();
   
   
   // Configure the AWS Message Processing Framework for .NET.
   builder.Services.AddAWSMessageBus(builder =>
   {
       // Check for input SQS URL.
       // The SQS URL should be passed as a command line argument or set in the Debug launch profile.
       if ((args.Length == 1) && (args[0].Contains("https://sqs.")))
       {
           // Register that you'll publish messages of type GreetingMessage:
           // 1. To a specified queue.
           // 2. Using the message identifier "greetingMessage", which will be used
           //    by handlers to route the message to the appropriate handler.
           builder.AddSQSPublisher<GreetingMessage>(args[0], "greetingMessage");
       }
       // You can map additional message types to queues or topics here as well.
   });
   var app = builder.Build();
   
   
   // Configure the HTTP request pipeline.
   if (app.Environment.IsDevelopment())
   {
       app.UseSwagger();
       app.UseSwaggerUI();
   }
   
   app.UseHttpsRedirection();
   
   // Create an API Endpoint that receives GreetingMessage objects
   // from the caller and then sends them as an SQS message.
   app.MapPost("/greeting", async ([FromServices] IMessagePublisher publisher, Publisher.GreetingMessage message) =>
       {
           return await PostGreeting(message, publisher);
       })
   .WithName("SendGreeting")
   .WithOpenApi();
   
   app.Run();
   
   public partial class Program
   {
       /// <summary>
       /// Endpoint for posting a greeting message.
       /// </summary>
       /// <param name="greetingMessage">The greeting message.</param>
       /// <param name="messagePublisher">The message publisher.</param>
       /// <returns>Async task result.</returns>
       public static async Task<IResult> PostGreeting(GreetingMessage greetingMessage,
           IMessagePublisher messagePublisher)
       {
           if (greetingMessage.SenderName == null || greetingMessage.Greeting == null)
           {
               return Results.BadRequest();
           }
   
           // Publish the message to the queue configured above.
           await messagePublisher.PublishAsync(greetingMessage);
   
           return Results.Ok();
       }
   }
   
   namespace Publisher
   {
       /// <summary>
       /// This class represents the message contents.
       /// </summary>
       public class GreetingMessage
       {
           public string? SenderName { get; set; }
           public string? Greeting { get; set; }
       }
   }
   ```

1. Ejecute el siguiente comando. Se abrirá una ventana del navegador con la interfaz de usuario de Swagger, que le permitirá explorar y probar su API.

   ```
   dotnet watch run <queue URL created earlier>
   ```

1. Abra el punto de conexión de `/greeting` y seleccione **Pruébelo**.

1. Especifique los valores `senderName` y `greeting` para el mensaje y seleccione **Ejecutar**. Esto invocará a su API, que enviará el mensaje de SQS.

### Creación y ejecución de la aplicación de procesamiento
<a name="mpf-tutorial-handle"></a>

Utilice el siguiente procedimiento para crear y ejecutar la aplicación de procesamiento.

1. Abra un símbolo del sistema o un terminal. Busque o cree una carpeta del sistema operativo en la que pueda crear un proyecto .NET.

1. En esa carpeta, ejecute el siguiente comando para crear el proyecto .NET.

   ```
   dotnet new console --name Handler
   ```

1. Acceda a la carpeta del proyecto nuevo. Añada una dependencia en el Marco de procesamiento de mensajes de AWS para .NET. Añada también el paquete `Microsoft.Extensions.Hosting`, que le permite configurar el marco a través del [host genérico de .NET](https://learn.microsoft.com/en-us/dotnet/core/extensions/generic-host).

   ```
   cd Handler
   dotnet add package AWS.Messaging
   dotnet add package Microsoft.Extensions.Hosting
   ```
**nota**  
Si utiliza AWS IAM Identity Center para la autenticación, no olvide añadir también `AWSSDK.SSO` y `AWSSDK.SSOOIDC`.

1. Reemplace el código de `Program.cs` con lo siguiente:

   ```
   using AWS.Messaging;
   using Handler;
   using Microsoft.Extensions.DependencyInjection;
   using Microsoft.Extensions.Hosting;
   
   var builder = Host.CreateDefaultBuilder(args);
   
   builder.ConfigureServices(services =>
   {
       // Register the AWS Message Processing Framework for .NET.
       services.AddAWSMessageBus(builder =>
       {
           // Check for input SQS URL.
           // The SQS URL should be passed as a command line argument or set in the Debug launch profile.
           if ((args.Length == 1) && (args[0].Contains("https://sqs.")))
           {
               // Register you'll poll the following queue.
               builder.AddSQSPoller(args[0]);
   
               // And that messages of type "greetingMessage" should be:
               // 1. Deserialized as GreetingMessage objects.
               // 2. Which are then passed to GreetingMessageHandler.
               builder.AddMessageHandler<GreetingMessageHandler, GreetingMessage>("greetingMessage");
   
           }
           // You can add additional message handlers here, using different message types. 
       });
   });
   
   var host = builder.Build();
   await host.RunAsync();
   
   namespace Handler
   {
       /// <summary>
       /// This class represents the message contents.
       /// </summary>
       public class GreetingMessage
       {
           public string? SenderName { get; set; }
           public string? Greeting { get; set; }
       }
   
       /// <summary>
       /// This handler is invoked each time you receive the message.
       /// </summary>
       public class GreetingMessageHandler : IMessageHandler<GreetingMessage>
       {
           public Task<MessageProcessStatus> HandleAsync(
               MessageEnvelope<GreetingMessage> messageEnvelope,
               CancellationToken token = default)
           {
               Console.WriteLine(
                   $"Received message {messageEnvelope.Message.Greeting} from {messageEnvelope.Message.SenderName}");
               return Task.FromResult(MessageProcessStatus.Success());
           }
       }
   }
   ```

1. Ejecute el siguiente comando. Esto inicia un sondeador de larga duración.

   ```
   dotnet run <queue URL created earlier>
   ```

   Poco después de iniciarse, la aplicación recibirá el mensaje que se envió en la primera parte de este tutorial y registrará el siguiente mensaje:

   ```
   Received message {greeting} from {senderName}
   ```

1. Pulse `Ctrl+C` para detener el sondeador.

### Eliminación
<a name="mpf-tutorial-cleanup"></a>

Utilice uno de los siguientes comandos para la AWS CLI o las Herramientas de AWS para PowerShell para eliminar la cola.

------
#### [ AWS CLI ]

```
aws sqs delete-queue --queue-url "<queue URL created earlier>"
```

------
#### [ Herramientas de AWS para PowerShell ]

```
Remove-SQSQueue -QueueUrl "<queue URL created earlier>"
```

------

# Publicación de mensajes con el Marco de procesamiento de mensajes de AWS para .NET
<a name="msg-proc-fw-publish"></a>

El Marco de procesamiento de mensajes de AWS para .NET permite publicar o procesar uno o más tipos de mensajes o hacer ambas cosas en la misma aplicación. 

El siguiente código muestra la configuración de una aplicación que publica distintos tipos de mensajes en distintos servicios de AWS. 

```
var builder = WebApplication.CreateBuilder(args);

// Register the AWS Message Processing Framework for .NET
builder.Services.AddAWSMessageBus(builder =>
{
    // Register that you'll send messages of type ChatMessage to an existing queue
    builder.AddSQSPublisher<ChatMessage>("https://sqs.us-west-2.amazonaws.com/012345678910/MyAppProd");

    // Register that you'll publish messages of type OrderInfo to an existing SNS topic
    builder.AddSNSPublisher<OrderInfo>("arn:aws:sns:us-west-2:012345678910:MyAppProd");

    // Register that you'll publish messages of type FoodItem to an existing EventBridge bus
    builder.AddEventBridgePublisher<FoodItem>("arn:aws:events:us-west-2:012345678910:event-bus/default");
});
```

Una vez que haya registrado el marco durante el inicio, introduzca el elemento `IMessagePublisher` genérico en el código. Llame a su método `PublishAsync` para publicar cualquiera de los tipos de mensajes que se configuraron anteriormente. El publicador genérico determinará el destino al que se debe enrutar el mensaje en función de su tipo. 

 En el siguiente ejemplo, un controlador MVC de ASP.NET recibe mensajes de `ChatMessage` y eventos de `OrderInfo` de los usuarios y, a continuación, los publica en Amazon SQS y Amazon SNS, respectivamente. Ambos tipos de mensajes se pueden publicar con el publicador genérico que se configuró anteriormente.

```
[ApiController]
[Route("[controller]")]
public class PublisherController : ControllerBase
{
    private readonly IMessagePublisher _messagePublisher;

    public PublisherController(IMessagePublisher messagePublisher)
    {
        _messagePublisher = messagePublisher;
    }

    [HttpPost("chatmessage", Name = "Chat Message")]
    public async Task<IActionResult> PublishChatMessage([FromBody] ChatMessage message)
    {
        // Perform business and validation logic on the ChatMessage here.
        if (message == null)
        {
            return BadRequest("A chat message was not submitted. Unable to forward to the message queue.");
        }
        if (string.IsNullOrEmpty(message.MessageDescription))
        {
            return BadRequest("The MessageDescription cannot be null or empty.");
        }

        // Send the ChatMessage to SQS, using the generic publisher.
        await _messagePublisher.PublishAsync(message);

        return Ok();
    }

    [HttpPost("order", Name = "Order")]
    public async Task<IActionResult> PublishOrder([FromBody] OrderInfo message)
    {
        if (message == null)
        {
            return BadRequest("An order was not submitted.");
        }

        // Publish the OrderInfo to SNS, using the generic publisher.
        await _messagePublisher.PublishAsync(message);

        return Ok();
    }
}
```

Para enrutar un mensaje a la lógica de gestión adecuada, el marco utiliza metadatos denominados *identificador del tipo de mensaje*. De forma predeterminada, es el nombre completo del tipo .NET del mensaje, incluido su nombre del ensamblado. Si envía y gestiona mensajes, este mecanismo funciona bien si comparte la definición de sus objetos de mensaje entre proyectos. Sin embargo, si los mensajes se redefinen en diferentes espacios de nombres, o si se intercambian mensajes con otros marcos o lenguajes de programación, es posible que sea necesario sobrescribir el identificador de tipo de mensaje.

```
var builder = Host.CreateDefaultBuilder(args);

builder.ConfigureServices(services =>
{
    // Register the AWS Message Processing Framework for .NET
    services.AddAWSMessageBus(builder =>
    {
        // Register that you'll publish messages of type GreetingMessage to an existing queue
        builder.AddSQSPublisher<GreetingMessage>("https://sqs.us-west-2.amazonaws.com/012345678910/MyAppProd", "greetingMessage");
    });
});
```

## Publicadores específicos del servicio
<a name="service-specific-publishers"></a>

El ejemplo que se muestra arriba usa el elemento `IMessagePublisher` genérico, que puede publicarse en cualquier servicio de AWS compatible en función del tipo de mensaje configurado. El marco también proporciona publicadores de servicios específicos para Amazon SQS, Amazon SNS y Amazon EventBridge. Estos publicadores específicos exponen opciones que solo se aplican a ese servicio y que pueden incorporarse mediante los tipos `ISQSPublisher`, `ISNSPublisher` y `IEventBridgePublisher`.

Por ejemplo, al enviar mensajes a una cola FIFO de SQS, debe establecer el [ID de grupo de mensajes](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/FIFO-key-terms.html) adecuado. El siguiente código vuelve a mostrar el ejemplo de `ChatMessage`, pero ahora se utiliza un elemento `ISQSPublisher` para configurar las opciones específicas de SQS.

```
public class PublisherController : ControllerBase
{
    private readonly ISQSPublisher _sqsPublisher;

    public PublisherController(ISQSPublisher sqsPublisher)
    {
        _sqsPublisher = sqsPublisher;
    }

    [HttpPost("chatmessage", Name = "Chat Message")]
    public async Task<IActionResult> PublishChatMessage([FromBody] ChatMessage message)
    {
        // Perform business and validation logic on the ChatMessage here
        if (message == null)
        {
            return BadRequest("A chat message was not submitted. Unable to forward to the message queue.");
        }
        if (string.IsNullOrEmpty(message.MessageDescription))
        {
            return BadRequest("The MessageDescription cannot be null or empty.");
        }

        // Send the ChatMessage to SQS using the injected ISQSPublisher, with SQS-specific options
        await _sqsPublisher.SendAsync(message, new SQSOptions
        {
            DelaySeconds = <delay-in-seconds>,
            MessageAttributes = <message-attributes>,
            MessageDeduplicationId = <message-deduplication-id>,
            MessageGroupId = <message-group-id>
        });

        return Ok();
    }
}
```

Se puede hacer lo mismo con SNS y EventBridge, utilizando `ISNSPublisher` y `IEventBridgePublisher` respectivamente.

```
await _snsPublisher.PublishAsync(message, new SNSOptions
{
    Subject = <subject>,
    MessageAttributes = <message-attributes>,
    MessageDeduplicationId = <message-deduplication-id>,
    MessageGroupId = <message-group-id>
});
```

```
await _eventBridgePublisher.PublishAsync(message, new EventBridgeOptions
{
    DetailType = <detail-type>,
    Resources = <resources>,
    Source = <source>,
    Time = <time>,
    TraceHeader = <trace-header>
});
```

De forma predeterminada, los mensajes de un tipo determinado se envían al destino que se haya configurado previamente. Sin embargo, puede anular el destino de un solo mensaje utilizando los publicadores específicos del mensaje. También puede anular el cliente AWS SDK para .NET subyacente que se utiliza para publicar el mensaje, lo que puede resultar útil en aplicaciones con varios usuarios en las que es necesario cambiar las funciones o las credenciales, según el destino.

```
await _sqsPublisher.SendAsync(message, new SQSOptions
{
    OverrideClient = <override IAmazonSQS client>,
    QueueUrl = <override queue URL>
});
```

# Consumo de mensajes con el Marco de procesamiento de mensajes de AWS para .NET
<a name="msg-proc-fw-consume"></a>

El Marco de procesamiento de mensajes de AWS para .NET permite consumir los mensajes que se han [publicado](msg-proc-fw-publish.md) mediante el marco o uno de los servicios de mensajería. Los mensajes se pueden consumir de diversas formas. A continuación se describen algunas de ellas.

## Controladores de mensajes
<a name="handle-a-message"></a>

Para consumir mensajes, implemente un controlador de mensajes mediante la interfaz de `IMessageHandler` para cada tipo de mensaje que quiera procesar. La asignación entre los tipos de mensajes y los controladores de mensajes se configura al iniciar el proyecto.

```
await Host.CreateDefaultBuilder(args)
    .ConfigureServices(services =>
    {
        // Register the AWS Message Processing Framework for .NET
        services.AddAWSMessageBus(builder =>
        {
            // Register an SQS Queue that the framework will poll for messages.
            // NOTE: The URL given below is an example. Use the appropriate URL for your SQS Queue.
            builder.AddSQSPoller("https://sqs.us-west-2.amazonaws.com/012345678910/MyAppProd");

            // Register all IMessageHandler implementations with the message type they should process. 
            // Here messages that match our ChatMessage .NET type will be handled by our ChatMessageHandler
            builder.AddMessageHandler<ChatMessageHandler, ChatMessage>();
        });
    })
    .Build()
    .RunAsync();
```

El siguiente código muestra un ejemplo de controlador de mensajes para un mensaje de `ChatMessage`. 

```
public class ChatMessageHandler : IMessageHandler<ChatMessage>
{
    public Task<MessageProcessStatus> HandleAsync(MessageEnvelope<ChatMessage> messageEnvelope, CancellationToken token = default)
    {
        // Add business and validation logic here.
        if (messageEnvelope == null)
        {
            return Task.FromResult(MessageProcessStatus.Failed());
        }

        if (messageEnvelope.Message == null)
        {
            return Task.FromResult(MessageProcessStatus.Failed());
        }

        ChatMessage message = messageEnvelope.Message;

        Console.WriteLine($"Message Description: {message.MessageDescription}");

        // Return success so the framework will delete the message from the queue.
        return Task.FromResult(MessageProcessStatus.Success());
    }
}
```

El elemento `MessageEnvelope` exterior contiene metadatos usados por el marco. Su propiedad `message` es el tipo de mensaje (en este caso, `ChatMessage`).

Puede devolver `MessageProcessStatus.Success()` para indicar que el mensaje se ha procesado correctamente y el marco eliminará el mensaje de la cola de Amazon SQS. Si devuelve `MessageProcessStatus.Failed()`, el mensaje permanecerá en la cola, donde podrá volver a procesarse o moverse a una [cola de mensajes fallidos](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-dead-letter-queues.html) (si está configurada).

## Gestión de mensajes en un proceso de larga duración
<a name="long-running-process"></a>

Puede llamar a `AddSQSPoller` con una URL de cola de SQS para iniciar un proceso [https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.hosting.backgroundservice](https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.hosting.backgroundservice) de larga duración que sondee continuamente la cola y procese los mensajes.

```
await Host.CreateDefaultBuilder(args)
    .ConfigureServices(services =>
    {
        // Register the AWS Message Processing Framework for .NET
        services.AddAWSMessageBus(builder =>
        {
            // Register an SQS Queue that the framework will poll for messages.
            // NOTE: The URL given below is an example. Use the appropriate URL for your SQS Queue.
            builder.AddSQSPoller("https://sqs.us-west-2.amazonaws.com/012345678910/MyAppProd", options => 
            {
                // The maximum number of messages from this queue that the framework will process concurrently on this client.
                options.MaxNumberOfConcurrentMessages = 10;

                // The duration each call to SQS will wait for new messages.
                options.WaitTimeSeconds = 20; 
            });

            // Register all IMessageHandler implementations with the message type they should process.
            builder.AddMessageHandler<ChatMessageHandler, ChatMessage>();
        });
    })
    .Build()
    .RunAsync();
```

### Configuración de SQS Message Poller
<a name="config-msg-poller"></a>

SQS Message Poller se puede configurar mediante `SQSMessagePollerOptions` al llamar a `AddSQSPoller`.
+ `MaxNumberOfConcurrentMessages`: el número máximo de mensajes de la cola que se pueden procesar simultáneamente. El valor predeterminado es 10.
+ `WaitTimeSeconds`: la duración (en segundos) durante la cual la llamada `ReceiveMessage` de SQS espera a que llegue un mensaje a la cola antes de devolver una respuesta. Si hay un mensaje disponible, la llamada devuelve una respuesta antes de que transcurra el tiempo especificado en `WaitTimeSeconds`. El valor predeterminado es 20.

**Gestión del tiempo de espera de visibilidad de los mensajes**

Los mensajes de SQS tienen un [tiempo de espera de visibilidad](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-visibility-timeout.html). Cuando un consumidor comienza a gestionar un mensaje determinado, este permanece en la cola, pero se oculta a los demás consumidores para evitar que se procese más de una vez. Si el mensaje no se gestiona y se elimina antes de volver a ser visible, es posible que otro consumidor intente gestionar el mismo mensaje.

El marco realizará un seguimiento del tiempo de espera de visibilidad de los mensajes que gestiona actualmente e intentará ampliarlo. Puede configurar este comportamiento en `SQSMessagePollerOptions` al llamar a `AddSQSPoller`.
+ `VisibilityTimeout`: la duración en segundos durante la cual los mensajes recibidos permanecen ocultos a las solicitudes de recuperación posteriores. El valor predeterminado es 30.
+ `VisibilityTimeoutExtensionThreshold`: cuando el tiempo de espera de la visibilidad de un mensaje esté a punto de vencer, el marco ampliará dicho tiempo de espera (añadiendo de nuevo los segundos especificados en `VisibilityTimeout`). El valor predeterminado es 5.
+ `VisibilityTimeoutExtensionHeartbeatInterval`: la frecuencia en segundos con la que el marco comprueba los mensajes que están a punto de caducar dentro del umbral `VisibilityTimeoutExtensionThreshold` y, a continuación, amplía su tiempo de espera de visibilidad. El valor predeterminado es 1.

 En el siguiente ejemplo, el marco comprobará cada segundo si hay mensajes que aún se están procesando. Para aquellos mensajes que estén a menos de 5 segundos de volver a ser visibles, el marco ampliará automáticamente el tiempo de espera de visibilidad de cada mensaje en otros 30 segundos.

```
// NOTE: The URL given below is an example. Use the appropriate URL for your SQS Queue.
builder.AddSQSPoller("https://sqs.us-west-2.amazonaws.com/012345678910/MyAppProd", options => 
{
    options.VisibilityTimeout = 30;
    options.VisibilityTimeoutExtensionThreshold = 5;
    VisibilityTimeoutExtensionHeartbeatInterval = 1;
});
```

## Gestión de mensajes en funciones de AWS Lambda
<a name="lambda-functions"></a>

Puede usar el Marco de procesamiento de mensajes de AWS para .NET con la [integración de SQS con Lambda](https://docs.aws.amazon.com/lambda/latest/dg/with-sqs.html). Esto lo proporciona el paquete `AWS.Messaging.Lambda`. Consulte su archivo [README](https://github.com/aws/aws-dotnet-messaging/blob/main/src/AWS.Messaging.Lambda/README.md) para empezar.

# Uso de FIFO con el Marco de procesamiento de mensajes de AWS para .NET
<a name="msg-proc-fw-fifo"></a>

En aquellos casos de uso en los que el orden y la deduplicación de los mensajes son fundamentales, el AWS Marco de procesamiento de mensajes para .NET admite [colas de Amazon SQS](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-fifo-queues.html) y [temas de Amazon SNS](https://docs.aws.amazon.com/sns/latest/dg/sns-fifo-topics.html) FIFO (primero en entrar, primero en salir).

## Publicación
<a name="mpf-fifo-publish"></a>

Para publicar mensajes en una cola o tema FIFO, debe establecer el ID del grupo de mensajes, que determina el grupo al que pertenece el mensaje. Los mensajes de un grupo se procesan en orden. Puede establecerlo en los publicadores de mensajes específicos de SQS y SNS.

```
await _sqsPublisher.PublishAsync(message, new SQSOptions
{
    MessageDeduplicationId = <message-deduplication-id>,
    MessageGroupId = <message-group-id>
});
```

## Suscripción
<a name="mpf-fifo-subscribe"></a>

Para gestionar los mensajes de una cola FIFO, el marco gestiona los mensajes de un determinado grupo de mensajes en el orden en que se recibieron para cada llamada de `ReceiveMessages`. El marco entra en este modo de funcionamiento automáticamente cuando se configura con una cola que termina en `.fifo`.

```
await Host.CreateDefaultBuilder(args)
    .ConfigureServices(services =>
    {
        // Register the AWS Message Processing Framework for .NET.
        services.AddAWSMessageBus(builder =>
        {
            // Because this is a FIFO queue, the framework automatically handles these messages in order.
            builder.AddSQSPoller("https://sqs.us-west-2.amazonaws.com/012345678910/MPF.fifo");
            builder.AddMessageHandler<OrderMessageHandler, OrderMessage>();
        });
    })
    .Build()
    .RunAsync();
```

# Registro y telemetría abierta para el Marco de procesamiento de mensajes de AWS para .NET
<a name="msg-proc-fw-telemetry"></a>

El Marco de procesamiento de mensajes de AWS para .NET está diseñado para que OpenTelemetry registre el [seguimiento](https://opentelemetry.io/docs/concepts/signals/traces/) de cada mensaje publicado o gestionado por el marco. Esto lo proporciona el paquete [https://www.nuget.org/packages/AWS.Messaging.Telemetry.OpenTelemetry](https://www.nuget.org/packages/AWS.Messaging.Telemetry.OpenTelemetry). Consulte su archivo [README](https://github.com/aws/aws-dotnet-messaging/blob/main/src/AWS.Messaging.Telemetry.OpenTelemetry/README.md) para empezar.

**nota**  
Para obtener información de seguridad relacionada con el registro, consulte [Seguridad para el Marco de procesamiento de mensajes de AWS para .NET](msg-proc-fw-security.md).

# Personalización del Marco de procesamiento de mensajes de AWS para .NET
<a name="msg-proc-fw-customize"></a>

El Marco de procesamiento de mensajes de AWS para .NET crea, envía y gestiona los mensajes en tres “capas” diferentes:

1. En la capa más externa, el marco crea la solicitud o respuesta nativa de AWS específica de un servicio. Con Amazon SQS, por ejemplo, crea solicitudes [https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessage.html](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessage.html) y trabaja con los objetos [https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_Message.html](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_Message.html) definidos por el servicio.

1. Dentro de la solicitud y respuesta SQS, el marco establece el elemento `MessageBody` (`Message` para Amazon SNS o `Detail` para Amazon EventBridge) en un [CloudEvent con formato JSON](https://github.com/cloudevents/spec/blob/v1.0.2/cloudevents/formats/json-format.md). Contiene metadatos establecidos por el marco que son accesibles en el objeto `MessageEnvelope` al gestionar un mensaje.

1. En la capa más interna, el atributo `data` del objeto JSON de CloudEvent contiene una serialización JSON del objeto .NET que se envió o recibió como mensaje.

   ```
   {
       "id":"b02f156b-0f02-48cf-ae54-4fbbe05cffba",
       "source":"/aws/messaging",
       "specversion":"1.0",
       "type":"Publisher.Models.ChatMessage",
       "time":"2023-11-21T16:36:02.8957126+00:00",
       "data":"<the ChatMessage object serialized as JSON>"
   }
   ```

Puede personalizar la configuración y la lectura del sobre del mensaje:
+ `"id"` identifica el mensaje de forma única. De forma predeterminada, se establece un nuevo GUID, pero esto se puede anular implementando su propio elemento `IMessageIdGenerator` e inyectándolo en el contenedor DI. 
+ `"type"` controla cómo se enruta el mensaje a los controladores. De forma predeterminada, utiliza el nombre completo del tipo .NET que corresponde al mensaje. Puede anularlo mediante el parámetro `messageTypeIdentifier` al asignar el tipo de mensaje al destino a través de `AddSQSPublisher`, `AddSNSPublisher` o `AddEventBridgePublisher`.
+ `"source"` indica qué sistema o servidor envió el mensaje.
  + Este será el nombre de la función si se publica desde AWS Lambda, el nombre del clúster y el ARN de la tarea si está en Amazon ECS o el ID de la instancia si está en Amazon EC2. De lo contrario, será un valor alternativo de `/aws/messaging`. 
  + Puede anularlo mediante `AddMessageSource` o `AddMessageSourceSuffix` en el elemento `MessageBusBuilder`.
+ `"time"` se ha definido en la fecha y hora actual en UTC. Esto se puede anular implementando su propio elemento `IDateTimeHandler` e inyectándolo en el contenedor DI.
+ `"data"` contiene una representación en JSON del objeto .NET que se envió o recibió como mensaje:
  + `ConfigureSerializationOptions` en el elemento `MessageBusBuilder` le permite configurar el objeto [https://learn.microsoft.com/en-us/dotnet/api/system.text.json.jsonserializeroptions](https://learn.microsoft.com/en-us/dotnet/api/system.text.json.jsonserializeroptions) que se utilizará para serializar y deserializar el mensaje.
  + Para añadir atributos adicionales o transformar el sobre del mensaje una vez que el marco lo haya creado, puede implementar `ISerializationCallback` y registrarlo mediante `AddSerializationCallback` en `MessageBusBuilder`.

# Seguridad para el Marco de procesamiento de mensajes de AWS para .NET
<a name="msg-proc-fw-security"></a>

El Marco de procesamiento de mensajes de AWS para .NET se basa en AWS SDK para .NET para comunicarse con AWS. Para obtener más información acerca de la seguridad de AWS SDK para .NET, consulte [Seguridad para este AWS producto o servicio](security.md).

Por motivos de seguridad, el marco no registra los mensajes de datos enviados por el usuario. Si desea habilitar esta funcionalidad con fines de depuración, debe llamar a `EnableDataMessageLogging()` en el bus de mensajes de la siguiente manera:

```
builder.Services.AddAWSMessageBus(bus =>
{
    builder.EnableDataMessageLogging();
});
```

Si detecta un posible problema de seguridad, consulte la [política de seguridad](https://github.com/aws/aws-dotnet-messaging/security/policy) para obtener información sobre cómo informar al respecto.

# Integración de AWS con .NET Aspire en AWS SDK para .NET
<a name="aspire-integrations"></a>

.NET Aspire es una nueva forma de crear aplicaciones listas para la nube. En particular, proporciona una orquestación para los entornos locales en la que se puede ejecutar, conectar y depurar los componentes de las aplicaciones distribuidas. Para mejorar el ciclo de desarrollo interno de las aplicaciones listas para la nube, se han creado integraciones con .NET Aspire para conectar las aplicaciones .NET a los recursos de AWS. Estas integraciones están disponibles a través del paquete NuGet de [Aspire.Hosting.AWS](https://www.nuget.org/packages/Aspire.Hosting.AWS).

Están disponibles las siguientes integraciones de .NET Aspire:
+ La capacidad de aprovisionar sus recursos de AWS mediante [CloudFormation](https://aws.amazon.com/cloudformation/). Esta integración se utiliza en el proyecto AppHost de .NET Aspire.

  Para obtener más información, consulte la entrada del blog [Integración de AWS con .NET Aspire](https://aws.amazon.com/blogs/developer/integrating-aws-with-net-aspire/).
+ Instalación, configuración y conexión de AWS SDK para .NET a [Amazon DynamoDB local](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocalHistory.html). Esta integración se utiliza en el proyecto AppHost de .NET Aspire.

  Para obtener más información, consulte la entrada del blog [Integración de AWS con .NET Aspire](https://aws.amazon.com/blogs/developer/integrating-aws-with-net-aspire/).
+ Habilite un entorno de desarrollo local para las características de [AWS Lambda](https://aws.amazon.com/lambda/). Esta integración se utiliza en el proyecto AppHost de .NET Aspire.

  Para obtener más información, consulte las publicaciones del blog [Creación y depuración de aplicaciones de .NET Lambda con .NET Aspire (parte 1)](https://aws.amazon.com/blogs/developer/building-lambda-with-aspire-part-1/) y [Creación y depuración de aplicaciones de .NET Lambda con .NET Aspire (parte 2)](https://aws.amazon.com/blogs/developer/building-lambda-with-aspire-part-2/).
**nota**  
Esta es una documentación preliminar para una característica en versión preliminar. Está sujeta a cambios.

  Como esta característica está en versión preliminar, tendrá que activar las características en versión preliminar. Para obtener información adicional sobre esta característica en versión preliminar y sobre cómo activarla, consulte el [tema del rastreador de desarrollo en GitHub](https://github.com/aws/integrations-on-dotnet-aspire-for-aws/issues/17).

## Información adicional
<a name="aspire-integrations-additional"></a>

Para obtener más información sobre cómo usar las integraciones que están disponibles en [Aspire.Hosting.aws](https://www.nuget.org/packages/Aspire.Hosting.AWS), consulte los siguientes recursos.
+ Entrada del blog [Integración de AWS con .NET Aspire](https://aws.amazon.com/blogs/developer/integrating-aws-with-net-aspire/).
+ Publicaciones del blog [Creación y depuración de aplicaciones de .NET Lambda con .NET Aspire (parte 1)](https://aws.amazon.com/blogs/developer/building-lambda-with-aspire-part-1/) y [Creación y depuración de aplicaciones de .NET Lambda con .NET Aspire (parte 2)](https://aws.amazon.com/blogs/developer/building-lambda-with-aspire-part-2/).
+ El repositorio [integrations-on-dotnet-aspire-for-aws](https://github.com/aws/integrations-on-dotnet-aspire-for-aws) en GitHub.
+ El archivo [README](https://github.com/aws/integrations-on-dotnet-aspire-for-aws/blob/main/src/Aspire.Hosting.AWS/README.md) del paquete NuGet de [Aspire.Hosting.AWS](https://www.nuget.org/packages/Aspire.Hosting.AWS).

# Compatibilidad con otros servicios y configuraciones de AWS
<a name="other-apis-intro"></a>

AWS SDK para .NET admite otros servicios de AWS aparte de los descritos en las secciones anteriores. Para obtener información sobre las API de todos los servicios compatibles, consulte la [Referencia de API de AWS SDK para .NET](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/).

Además de los espacios de nombres de servicios de AWS individuales, AWS SDK para .NET también proporciona las siguientes API:


****  

| Area | Descripción | Recursos | 
| --- | --- | --- | 
|  AWSCompatibilidad con   |  Acceso mediante programación a casos de AWS Support y características de Trusted Advisor.  |  Consulte [Amazon.AWSSupport](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/AWSSupport/NAWSSupport.html) y [Amazon.AWSSupport.Model](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/AWSSupport/NAWSSupportModel.html).  | 
|  General  |  Clases auxiliares y enumeraciones.  |  Consulte [Amazon](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/Amazon/N.html) y [Amazon.Util](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/Util/NUtil.html).  | 