Tuesday, 30 May 2023

Access and insert data to Azure Cosmos database using C# console app

In the below code example, I insert datd to Azure Cosmos DB using C# console app. The code read a JSON file and serialize JSON to C# object callled Model and Product.


using System;

using System.Collections.Generic;

using System.Diagnostics;

using System.Linq;

using System.Threading.Tasks;

using System.Text.Json;

using System.IO;

using Microsoft.Azure.Cosmos;

 

namespace AzCosmosDB

{

    internal class Program

    {

        // in prod below variable must be stored in app settings

        private const string EndpointUrl = "https://demo-cosmosdb-retail.documents.azure.com:443/";

        private const string AuthorizationKey = "eKXwigOPIGlu7NHzBEEr1lqc8zRACDbaJ0t9Q==";

        private const string DatabaseName = "Retail";

        private const string ContainerName = "Online";

        private const string PartitionKey = "/Category";

        private const string JsonFilePath = "D:\\Project\\Azure\\AzCosmosDB\\models.json";

 

        static private int amountToInsert;

        static List<Model> models;

        static async Task Main(string[] args)

        {

            try

            {

                // <CreateClient>

                CosmosClient cosmosClient = new CosmosClient(EndpointUrl, AuthorizationKey, new CosmosClientOptions() { AllowBulkExecution = true });

                // </CreateClient>

                // <Initialize>

                Console.WriteLine($"Creating a database if not already exists...");

                Database database = await cosmosClient.CreateDatabaseIfNotExistsAsync(Program.DatabaseName);

 

                // Configure indexing policy to exclude all attributes to maximize RU/s usage

                Console.WriteLine($"Creating a container if not already exists...");

                await database.DefineContainer(Program.ContainerName, PartitionKey)

                        .WithIndexingPolicy()

                            .WithIndexingMode(IndexingMode.Consistent)

                            .WithIncludedPaths()

                                .Attach()

                            .WithExcludedPaths()

                                .Path("/*")

                                .Attach()

                        .Attach()

                    .CreateAsync();

                // </Initialize>

 

                using (StreamReader reader = new StreamReader(File.OpenRead(JsonFilePath)))

                {

                    string json = await reader.ReadToEndAsync();

                    models = JsonSerializer.Deserialize<List<Model>>(json);

                    amountToInsert = models.Count;

                }

 

                // Prepare items for insertion

                Console.WriteLine($"Preparing {amountToInsert} items to insert...");

 

                // Create the list of Tasks

                Console.WriteLine($"Starting...");

                Stopwatch stopwatch = Stopwatch.StartNew();

                // <ConcurrentTasks>

                Container container = database.GetContainer(ContainerName);

 

                List<Task> tasks = new List<Task>(amountToInsert);

                foreach (Model model in models)

                {

                    tasks.Add(container.CreateItemAsync(model, new PartitionKey(model.Category))

                        .ContinueWith(itemResponse =>

                        {

                            if (!itemResponse.IsCompletedSuccessfully)

                            {

                                AggregateException innerExceptions = itemResponse.Exception.Flatten();

                                if (innerExceptions.InnerExceptions.FirstOrDefault(innerEx => innerEx is CosmosException) is CosmosException cosmosException)

                                {

                                    Console.WriteLine($"Received {cosmosException.StatusCode} ({cosmosException.Message}).");

                                }

                                else

                                {

                                    Console.WriteLine($"Exception {innerExceptions.InnerExceptions.FirstOrDefault()}.");

                                }

                            }

                        }));

                }

                // Wait until all are done

                await Task.WhenAll(tasks);

                // </ConcurrentTasks>

                stopwatch.Stop();

 

                Console.WriteLine($"Finished writing {amountToInsert} items in {stopwatch.Elapsed}.");

            }

            catch (Exception ex)

            {

                Console.WriteLine(ex);

            }

        }

    }

    public class Model

        {

            public string id { get; set; }

            public string Name { get; set; }

            public string Category { get; set; }

            public string Description { get; set; }

            public string Photo { get; set; }

            public IList<Product> Products { get; set; }

        }

 

    public class Product

        {

            public string id { get; set; }

            public string Name { get; set; }

            public string Number { get; set; }

            public string Category { get; set; }

            public string Color { get; set; }

            public string Size { get; set; }

            public decimal? Weight { get; set; }

            public decimal ListPrice { get; set; }

            public string Photo { get; set; }

        }

}


JSON Example:

[

  {

    "id": "0481d7e1-4970-4efa-a560-020f6579918d",

    "Name": "LL Fork",

    "Category": "Forks",

    "Description": "Stout design absorbs shock and offers more precise steering.",

    "Products": [

      {

        "id": "fb8502be-07eb-4134-ab06-c3a9959a52ae",

        "Name": "LL Fork",

        "Number": "FK-1639",

        "Category": "Forks",

        "Color": null,

        "Size": null,

        "Weight": null,

        "ListPrice": 148.22,

        "Photo": "fork.jpg"

      }

    ],

    "Photo": "fork.jpg"

  },

  {

    "id": "ca18ecfd-2023-4fa7-a556-0321153bca34",

    "Name": "ML Road Frame-W",

    "Category": "Road Frames",

    "Description": "Made from the same aluminum alloy as our top-of-the line HL frame, the ML features a lightweight down-tube milled to the perfect diameter for optimal strength. Women's version.",

    "Products": [

      {

        "id": "22df26f2-60bc-493e-a14a-5500633e9f7e",

        "Name": "ML Road Frame-W - Yellow, 40",

        "Number": "FR-R72Y-40",

        "Category": "Road Frames",

        "Color": "Yellow",

        "Size": "40",

        "Weight": 1006.97,

        "ListPrice": 594.83,

        "Photo": "no_image_available.jpg"

      },

      {

        "id": "207b54da-5404-415d-8578-9a45082e3bf1",

        "Name": "ML Road Frame-W - Yellow, 42",

        "Number": "FR-R72Y-42",

        "Category": "Road Frames",

        "Color": "Yellow",

        "Size": "42",

        "Weight": 1025.11,

        "ListPrice": 594.83,

        "Photo": "no_image_available.jpg"

      },

      {

        "id": "22976fa7-0ad0-40f9-b4f9-ba10279ea1a3",

        "Name": "ML Road Frame-W - Yellow, 38",

        "Number": "FR-R72Y-38",

        "Category": "Road Frames",

        "Color": "Yellow",

        "Size": "38",

        "Weight": 988.83,

        "ListPrice": 594.83,

        "Photo": "no_image_available.jpg"

      },

      {

        "id": "a0fad492-ac24-4fcf-8d2a-d21d06386ae1",

        "Name": "ML Road Frame-W - Yellow, 44",

        "Number": "FR-R72Y-44",

        "Category": "Road Frames",

        "Color": "Yellow",

        "Size": "44",

        "Weight": 1043.26,

        "ListPrice": 594.83,

        "Photo": "no_image_available.jpg"

      },

      {

        "id": "8487bfe0-2138-471e-9c6d-fdb3a67e7d86",

        "Name": "ML Road Frame-W - Yellow, 48",

        "Number": "FR-R72Y-48",

        "Category": "Road Frames",

        "Color": "Yellow",

        "Size": "48",

        "Weight": 1061.4,

        "ListPrice": 594.83,

        "Photo": "no_image_available.jpg"

      }

    ],

    "Photo": "no_image_available.jpg"

  }

 ]


Monday, 29 May 2023

Create, read and write Blobs in Azure Blob storage / containers using C# .NET

using Azure.Storage;

using Azure.Storage.Blobs;

using Azure.Storage.Blobs.Models;

using System;

using System.Threading.Tasks;

 

namespace BlobStorage

{  

 internal class Program

 {

        private const string blobServiceEndpoint = "https://mediastorrp.blob.core.windows.net/";

        private const string storageAccountName = "mediastorrp";

        private const string storageAccountKey = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";

        public static async Task Main(string[] args)

        {

        StorageSharedKeyCredential accountCredentials = new StorageSharedKeyCredential(storageAccountName, storageAccountKey);

        BlobServiceClient serviceClient = new BlobServiceClient(new Uri(blobServiceEndpoint), accountCredentials);

 

            //1 get blob storage account details

        AccountInfo info = await serviceClient.GetAccountInfoAsync();

        await Console.Out.WriteLineAsync($"Connected to Azure Storage Account");

        await Console.Out.WriteLineAsync($"Account name:\t{storageAccountName}");

        await Console.Out.WriteLineAsync($"Account kind:\t{info?.AccountKind}");

        await Console.Out.WriteLineAsync($"Account sku:\t{info?.SkuName}");

 

            //2 Call iterate method for all containers in the account

        await EnumerateContainersAsync(serviceClient);

 

            //2 call method to enumerate all blobs in a container

        string existingContainerName = "raster-graphics";

        await EnumerateBlobsAsync(serviceClient, existingContainerName);

 

        // read blob

        string newContainerName = "vector-graphics";

        BlobContainerClient containerClient = await GetContainerAsync(serviceClient, newContainerName);

        string uploadedBlobName = "graph.svg";

        BlobClient blobClient = await GetBlobAsync(containerClient, uploadedBlobName);

        await Console.Out.WriteLineAsync($"Blob Url:\t{blobClient.Uri}");

        }

 

        // Iterate all containers in the account

        private static async Task EnumerateContainersAsync(BlobServiceClient client)

        {

        await foreach (BlobContainerItem container in client.GetBlobContainersAsync())

        {

            await Console.Out.WriteLineAsync($"Container:\t{container.Name}");

        }

        }

 

        // Iterate all blobs in the container

        private static async Task EnumerateBlobsAsync(BlobServiceClient client, string containerName)

        {

        BlobContainerClient container = client.GetBlobContainerClient(containerName);

        await Console.Out.WriteLineAsync($"Searching:\t{container.Name}");

        await foreach (BlobItem blob in container.GetBlobsAsync())

        {

            await Console.Out.WriteLineAsync($"Existing Blob:\t{blob.Name}");

        }

        }

 

        // get or create container if not exists

    private static async Task<BlobContainerClient> GetContainerAsync(BlobServiceClient client, string containerName)

    {

        BlobContainerClient container = client.GetBlobContainerClient(containerName);

        await container.CreateIfNotExistsAsync(PublicAccessType.Blob);

        await Console.Out.WriteLineAsync($"New Container:\t{container.Name}");

        return container;

    }

    private static async Task<BlobClient> GetBlobAsync(BlobContainerClient client, string blobName)

    {

        BlobClient blob = client.GetBlobClient(blobName);

        await Console.Out.WriteLineAsync($"Blob Found:\t{blob.Name}");

        return blob;

    }

 }

}