Tutorial: Desarrollo de una aplicación de consola de .NET con Azure Cosmos DB for NoSQL
SE APLICA A: NoSQL
El SDK de Azure para .NET permite agregar datos a una API para contenedor NoSQL, ya sean operaciones individuales asincrónicas o un lote transaccional. Este tutorial le guía por el proceso de creación de una nueva aplicación de consola de .NET que agrega varios elementos a un contenedor.
En este tutorial, aprenderá a:
- Creación de una base de datos mediante la API for NoSQL
- Creación de una aplicación de consola de .NET y adición de Azure SDK para .NET
- Adición de elementos individuales a un contenedor de API for NoSQL
- Recuperación eficaz de elementos desde un contenedor de API for NoSQL
- Creación de una transacción con cambios por lotes para el contenedor de API for NoSQL
Requisitos previos
- Una cuenta existente de Azure Cosmos DB for NoSQL.
- Si tiene una suscripción de Azure, cree una nueva cuenta.
- ¿No tiene una suscripción de Azure? Puede probar Azure Cosmos DB de forma gratuita, sin necesidad de usar su tarjeta de crédito.
- Visual Studio Code
- .NET 8 o posterior
- Experiencia en la escritura de aplicaciones de C#.
Creación de recursos de API for NoSQL
En primer lugar, cree una base de datos vacía en la cuenta de API for NoSQL. Más adelante, creará un contenedor mediante Azure SDK para .NET.
Vaya a la cuenta de API for NoSQL existente en Azure Portal.
En el menú de recursos, seleccione Registros.
En la página Claves, compruebe y anote el valor de los campos URI y PRIMARY KEY. Estos valores se usarán a lo largo del tutorial.
En el menú de recursos, seleccione Explorador de datos.
En la página de Data Explorer, seleccione la opción Nueva base de datos en la barra de comandos.
En el cuadro de diálogo Nueva base de datos, cree un contenedor con esta configuración:
Value Id. de base de datos cosmicworks
Tipo de rendimiento de la base de datos Manual Cantidad de rendimiento de la base de datos 400
Para crear la base de datos, seleccione Aceptar.
Creación de una aplicación de consola de .NET
Ahora, creará una nueva aplicación de consola de .NET e importará Azure SDK para .NET mediante la biblioteca Microsoft.Azure.Cosmos
de NuGet.
Abra un terminal en un directorio vacío.
Creación de una nueva aplicación de consola mediante la plantilla integrada
console
dotnet new console --langVersion preview
Agregue la versión 3.31.1-preview del paquete
Microsoft.Azure.Cosmos
de NuGet.dotnet add package Microsoft.Azure.Cosmos --version 3.31.1-preview
Agregue también la versión preliminar del paquete
System.CommandLine
De NuGet.dotnet add package System.CommandLine --prerelease
Agregue también el paquete
Humanizer
de NuGet.dotnet add package Humanizer
Compile el proyecto de la aplicación de consola.
dotnet build
Abra Visual Studio Code mediante la carpeta del proyecto actual como área de trabajo.
Sugerencia
Puede ejecutar
code .
en el terminal para abrir Visual Studio Code e iniciar automáticamente el directorio de trabajo como área de trabajo actual.Vaya al archivo Program.cs y ábralo. Elimine el código existente del archivo.
Agregue este código al archivo para usar la biblioteca System.CommandLine y analizar la línea de comandos para dos cadenas transferidas a través de las opciones
--first
y--last
.using System.CommandLine; var command = new RootCommand(); var nameOption = new Option<string>("--name") { IsRequired = true }; var emailOption = new Option<string>("--email"); var stateOption = new Option<string>("--state") { IsRequired = true }; var countryOption = new Option<string>("--country") { IsRequired = true }; command.AddOption(nameOption); command.AddOption(emailOption); command.AddOption(stateOption); command.AddOption(countryOption); command.SetHandler( handle: CosmosHandler.ManageCustomerAsync, nameOption, emailOption, stateOption, countryOption ); await command.InvokeAsync(args);
Nota:
Para este tutorial, no es fundamental conocer el funcionamiento del analizador de línea de comandos. El analizador tiene cuatro opciones que se pueden especificar cuando se ejecuta la aplicación. Tres de las opciones son necesarias, ya que se usarán para generar los campos de id. y clave de partición.
En este punto, el proyecto no se compilará, ya que aún no se ha definido el método estático
CosmosHandler.ManageCustomerAsync
.Guarde el archivo Program.cs.
Adición de elementos a un contenedor mediante el SDK
A continuación, usará operaciones individuales para agregar elementos al contenedor de API for NoSQL. En esta sección, se definirá el método CosmosHandler.ManageCustomerAsync
.
Cree un nuevo archivo CosmosHandler.cs.
En el archivo CosmosHandler.cs, agregue una nueva directiva con los espacios de nombres
Humanizer
yMicrosoft.Azure.Cosmos
.using Humanizer; using Microsoft.Azure.Cosmos;
Cree un nuevo método estático denominado
CosmosHandler
.public static class CosmosHandler { }
Con el fin de comprobar que la aplicación funciona, cree una breve implementación del método estático
ManageCustomerAsync
para imprimir la entrada de la línea de comandos.public static async Task ManageCustomerAsync(string name, string email, string state, string country) { await Console.Out.WriteLineAsync($"Hello {name} of {state}, {country}!"); }
Guarde el archivo CosmosHandler.cs.
De nuevo en el terminal, ejecute la aplicación.
dotnet run -- --name 'Mica Pereira' --state 'Washington' --country 'United States'
La salida del comando debe ser un saludo divertido.
Hello Mica Pereira of Washington, United States!
Vuelva al archivo CosmosHandler.cs.
En la clase estática CosmosHandler, agregue un nuevo miembro
private static readonly
del tipoCosmosClient
denominado_client
.private static readonly CosmosClient _client;
Cree un nuevo constructor estático para la clase
CosmosHandler
.static CosmosHandler() { }
En el constructor, cree una nueva instancia de la clase
CosmosClient
pasando dos parámetros de cadena con los valores URI y PRIMARY KEY que registró anteriormente en el laboratorio. Almacene esta nueva instancia en el miembro_client
.static CosmosHandler() { _client = new CosmosClient( accountEndpoint: "<uri>", authKeyOrResourceToken: "<primary-key>" ); }
De nuevo dentro de la clase estática CosmosHandler, cree un nuevo método asincrónico denominado
GetContainerAsync
que devuelva un valorContainer
.private static async Task<Container> GetContainerAsync() { }
Para los pasos siguientes, agregue este código dentro del método
GetContainerAsync
.Obtenga la base de datos
cosmicworks
y almacénela en una variable denominadadatabase
.Database database = _client.GetDatabase("cosmicworks");
Cree una nueva variable
List<>
genérica de valoresstring
en una lista de rutas de acceso de clave de partición jerárquica y almacénela en una variable denominadakeyPaths
.List<string> keyPaths = new() { "/address/country", "/address/state" };
Cree una nueva variable
ContainerProperties
con el nombre del contenedor (customers
) y la lista de rutas de acceso de clave de partición.ContainerProperties properties = new( id: "customers", partitionKeyPaths: keyPaths );
Use el método
CreateContainerIfNotExistsAsync
para proporcionar las propiedades del contenedor y recuperar este. En función del nombre, este método creará de forma asincrónica el contenedor si aún no existe en la base de datos. Obtenga el resultado como la salida del métodoGetContainerAsync
.return await database.CreateContainerIfNotExistsAsync( containerProperties: properties );
Elimine todo el código del método
ManageCustomerAsync
.Para los pasos siguientes, agregue este código dentro del método
ManageCustomerAsync
.Llame de forma asincrónica al método
GetContainerAsync
y almacene el resultado en una variable denominadacontainer
.Container container = await GetContainerAsync();
Cree una variable denominada
id
que use el métodoKebaberize
de Humanizer para transformar el parámetro de métodoname
.string id = name.Kebaberize();
Nota
El método
Kebaberize
reemplazará todos los espacios por guiones y cambiará el texto a minúsculas.Cree un nuevo elemento con tipo anónimo mediante los parámetros de método
name
,state
ycountry
, junto con la variableid
. Almacene el elemento como una variable denominadacustomer
.var customer = new { id = id, name = name, address = new { state = state, country = country } };
Use el método asincrónico
CreateItemAsync
del contenedor para crear un nuevo elemento en el contenedor y asignar los metadatos de respuesta HTTP a una variable denominadaresponse
.var response = await container.CreateItemAsync(customer);
Escriba los valores de las propiedades
StatusCode
yRequestCharge
de la variableresponse
en la consola. Escriba también el valor de la variableid
.Console.WriteLine($"[{response.StatusCode}]\t{id}\t{response.RequestCharge} RUs");
Guarde el archivo CosmosHandler.cs.
De nuevo en el terminal, vuelva a ejecutar la aplicación.
dotnet run -- --name 'Mica Pereira' --state 'Washington' --country 'United States'
La salida del comando deberá incluir un estado y un cargo asociado a la solicitud para la operación.
[Created] mica-pereira 7.05 RUs
Nota
El cargo asociado a la solicitud puede variar.
Ejecute la aplicación una vez más.
dotnet run -- --name 'Mica Pereira' --state 'Washington' --country 'United States'
Esta vez, el programa debería bloquearse. Si se desplaza por el mensaje de error, verá que el bloqueo se produjo debido a un conflicto en el identificador único de los elementos.
Unhandled exception: Microsoft.Azure.Cosmos.CosmosException : Response status code does not indicate success: Conflict (409);Reason: ( Errors : [ "Resource with specified id or name already exists." ] );
Recuperación de un elemento mediante el SDK
Una vez que se ha creado el primer elemento en el contenedor, podrá usar el mismo SDK para recuperar el elemento. Consulte aquí el elemento para comparar la diferencia en el consumo de unidades de solicitud (RU).
Vuelva al archivo CosmosHandler.cs o ábralo.
Elimine todas las líneas de código del método
ManageCustomerAsync
, salvo por las dos primeras líneas.public static async Task ManageCustomerAsync(string name, string email, string state, string country) { Container container = await GetContainerAsync(); string id = name.Kebaberize(); }
Para los pasos siguientes, agregue este código dentro del método
ManageCustomerAsync
.Use el método asincrónico
CreateItemAsync
del contenedor para crear un nuevo elemento en el contenedor y asignar los metadatos de respuesta HTTP a una variable denominadaresponse
.var response = await container.CreateItemAsync(customer);
Cree una nueva cadena denominada
sql
con una consulta SQL para recuperar elementos en los que coincida un filtro (@id
).string sql = @" SELECT * FROM customers c WHERE c.id = @id ";
Cree una nueva variable
QueryDefinition
denominadaquery
que pase la cadenasql
como el único parámetro de consulta. Además, use el método fluidWithParameter
para aplicar el valor de la variableid
al parámetro@id
.var query = new QueryDefinition( query: sql ) .WithParameter("@id", id);
Use el método genérico
GetItemQueryIterator<>
y la variablequery
para crear un iterador que obtenga datos de Azure Cosmos DB. Almacene el elemento como una variable denominadafeed
. Encapsule esta expresión completa en una instrucción using para desechar el iterador más adelante.using var feed = container.GetItemQueryIterator<dynamic>( queryDefinition: query );
Llame de forma asincrónica al método
ReadNextAsync
de la variablefeed
y almacene el resultado en una variable denominadaresponse
.var response = await feed.ReadNextAsync();
Escriba los valores de las propiedades
StatusCode
yRequestCharge
de la variableresponse
en la consola. Escriba también el valor de la variableid
.Console.WriteLine($"[{response.StatusCode}]\t{id}\t{response.RequestCharge} RUs");
Guarde el archivo CosmosHandler.cs.
De nuevo en el terminal, ejecute la aplicación para leer el elemento único mediante una consulta SQL.
dotnet run -- --name 'Mica Pereira' --state 'Washington' --country 'United States'
La salida del comando debe indicar que la consulta requería varias unidades de solicitud (RU).
[OK] mica-pereira 2.82 RUs
De nuevo en el archivo CosmosHandler.cs, vuelva a eliminar todas las líneas de código del método
ManageCustomerAsync
, salvo por las dos primeras líneas.public static async Task ManageCustomerAsync(string name, string email, string state, string country) { Container container = await GetContainerAsync(); string id = name.Kebaberize(); }
Para los pasos siguientes, agregue este código dentro del método
ManageCustomerAsync
.Cree una nueva instancia de
PartitionKeyBuilder
agregando los parámetrosstate
ycountry
como un valor de clave de partición de varias partes.var partitionKey = new PartitionKeyBuilder() .Add(country) .Add(state) .Build();
Use el método
ReadItemAsync<>
del contenedor para leer el elemento del contenedor mediante las variablesid
ypartitionKey
. Guarde el resultado en una variable denominadaresponse
.var response = await container.ReadItemAsync<dynamic>( id: id, partitionKey: partitionKey );
Escriba los valores de las propiedades
StatusCode
yRequestCharge
de la variableresponse
en la consola. Escriba también el valor de la variableid
.Console.WriteLine($"[{response.StatusCode}]\t{id}\t{response.RequestCharge} RU");
Vuelva a guardar el archivo CosmosHandler.cs.
De nuevo en el terminal, ejecute la aplicación una vez más para que lea el elemento único.
dotnet run -- --name 'Mica Pereira' --state 'Washington' --country 'United States'
La salida del comando debería indicar que la consulta requería una única RU.
[OK] mica-pereira 1 RUs
Creación de una transacción con el SDK
Por último, seleccionará el elemento que creó, lo leerá y creará un elemento relacionado diferente como parte de una sola transacción mediante Azure SDK para .NET.
Vuelva al archivo CosmosHandler.cs o ábralo.
Elimine estas líneas de código del método
ManageCustomerAsync
.var response = await container.ReadItemAsync<dynamic>( id: id, partitionKey: partitionKey ); Console.WriteLine($"[{response.StatusCode}]\t{id}\t{response.RequestCharge} RUs");
Para los pasos siguientes, agregue este nuevo código dentro del método
ManageCustomerAsync
.Cree un nuevo elemento con tipo anónimo mediante los parámetros de método
name
,state
ycountry
, junto con la variableid
. Almacene el elemento como una variable denominadacustomerCart
. Este elemento representa un carro de la compra en tiempo real para el cliente que está vacío actualmente.var customerCart = new { id = $"{Guid.NewGuid()}", customerId = id, items = new string[] {}, address = new { state = state, country = country } };
Cree otro nuevo elemento de tipo anónimo mediante los parámetros de método
name
,state
ycountry
, y la variableid
. Almacene el elemento como una variable denominadacustomerCart
. Este elemento representa la información de envío y contacto del cliente.var customerContactInfo = new { id = $"{id}-contact", customerId = id, email = email, location = $"{state}, {country}", address = new { state = state, country = country } };
Cree un nuevo lote mediante el método
CreateTransactionalBatch
del contenedor pasando la variablepartitionKey
. Almacene el lote como una variable denominadabatch
. Use métodos fluidos para realizar las siguientes acciones:Método Parámetro ReadItem
variable de cadena id
CreateItem
variable de tipo anónimo customerCart
CreateItem
variable de tipo anónimo customerContactInfo
var batch = container.CreateTransactionalBatch(partitionKey) .ReadItem(id) .CreateItem(customerCart) .CreateItem(customerContactInfo);
Use el método
ExecuteAsync
del lote para iniciar la transacción. Guarde el resultado en una variable denominadaresponse
.using var response = await batch.ExecuteAsync();
Escriba los valores de las propiedades
StatusCode
yRequestCharge
de la variableresponse
en la consola. Escriba también el valor de la variableid
.Console.WriteLine($"[{response.StatusCode}]\t{response.RequestCharge} RUs");
Vuelva a guardar el archivo CosmosHandler.cs.
De nuevo en el terminal, ejecute la aplicación una vez más para que lea el elemento único.
dotnet run -- --name 'Mica Pereira' --state 'Washington' --country 'United States'
La salida del comando debe mostrar las unidades de solicitud usadas para toda la transacción.
[OK] 16.05 RUs
Nota
El cargo asociado a la solicitud puede variar.
Validación de los datos finales en Data Explorer
En resumen, usará Data Explorer en Azure Portal para ver los datos y el contenedor que creó en este tutorial.
Vaya a la cuenta de API for NoSQL en Azure Portal.
En el menú de recursos, seleccione Explorador de datos.
En la página de Data Explorer, expanda la base de datos
cosmicworks
y seleccione el contenedorcustomers
.En la barra de comandos, seleccione New SQL query.
En el editor de consultas, fíjese en esta cadena de consulta SQL.
SELECT * FROM c
Seleccione Ejecutar consulta para efectuar la consulta y ver los resultados.
Los resultados deben incluir una matriz JSON con tres elementos creados en este tutorial. Observe que todos los elementos tienen el mismo valor de clave de partición jerárquica, pero campos de identificador únicos. La salida de ejemplo incluida se ha acortado para mayor brevedad.
[ { "id": "mica-pereira", "name": "Mica Pereira", "address": { "state": "Washington", "country": "United States" }, ... }, { "id": "33d03318-6302-4559-b5c0-f3cc643b2f38", "customerId": "mica-pereira", "items": [], "address": { "state": "Washington", "country": "United States" }, ... }, { "id": "mica-pereira-contact", "customerId": "mica-pereira", "email": null, "location": "Washington, United States", "address": { "state": "Washington", "country": "United States" }, ... } ]
Limpieza de recursos
Elimine los recursos que utilizados en este artículo cuando ya no se necesiten. Para ello, vaya a la página de la cuenta, seleccione Data Explorer, la cosmicworks
base de datos y Eliminar.