1

I'm generating some JSON files in .NET Core app. I want to import a json file to Azure Cosmos DB as soon as it is created.

Is there some way to achieve it from a .NET Core code.

Thanks in advance!

Vishal modi
  • 1,571
  • 2
  • 12
  • 20
ashmit-001
  • 392
  • 4
  • 21

2 Answers2

2

According to my test, if you want to use Cosmos DB Bulk insert in .Net core application, you need to use the .Net CosmosDB SDK V3 and its version must be larger than 3.4.0. For more details, please refer to the document.

My.json file

[{
        "id": "1",
        "name": "test1",
        "age": "20"
    }, {
        "id": "2",
        "name": "test2",
        "age": "21"
    }, {
        "id": "3",
        "name": "test3",
        "age": "22"
    }, {
        "id": "4",
        "name": "test4",
        "age": "23"
    },
    {
        "id": "5",
        "name": "test5",
        "age": "24"
    }, {
        "id": "6",
        "name": "test6",
        "age": "25"
    }, {
        "id": "7",
        "name": "test7",
        "age": "26"
    }, {
        "id": "8",
        "name": "test8",
        "age": "27"
    }
]

My code

 private const string EndpointUrl = "";
        private const string AuthorizationKey = "";
        private const string DatabaseName = "testbulk";
        private const string ContainerName = "items";
        async static Task Main(string[] args)
        {
            string json = File.ReadAllText(@"E:\test.json");
            
            List<Item> lists = JsonConvert.DeserializeObject<List<Item>>(json);

            CosmosClientOptions options = new CosmosClientOptions() { AllowBulkExecution = true };
            CosmosClient cosmosClient = new CosmosClient(EndpointUrl, AuthorizationKey,options);
            
            Database database = await cosmosClient.CreateDatabaseIfNotExistsAsync(DatabaseName);
            Console.WriteLine(database.Id);
            Container container = await database.CreateContainerIfNotExistsAsync(ContainerName, "/id");
            Console.WriteLine(container.Id);
            
            List<Task> tasks = new List<Task>();
            foreach (Item item in lists)
            {
                tasks.Add(container.CreateItemAsync(item, new PartitionKey(item.Id))
                    .ContinueWith((Task<ItemResponse<Item>> task) =>
                    {


                        Console.WriteLine("Status: " + task.Result.StatusCode + "    Resource: "+ task.Result.Resource.Id );



                    }));


            }
            await Task.WhenAll(tasks);
}
class Item {

        [JsonProperty(PropertyName = "id")]
        public string Id { get; set; }

        [JsonProperty(PropertyName = "name")]
        public string Name { get; set; }

        [JsonProperty(PropertyName = "age")]
        public string Age { get; set; }
    }

enter image description here

For more details about how to develop your application, please refer to the blog


Update

I run my code in .Net 4.6.1 console application.

My code

 class Program
    {

        private const string EndpointUrl = "";
        private const string AuthorizationKey = "";
        private const string DatabaseName = "testbulk";
        private const string ContainerName = "items";
        async static Task Main(string[] args)
        {
            string json = File.ReadAllText(@"E:\test.json");

            List<Item> lists = JsonConvert.DeserializeObject<List<Item>>(json);

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

            Database database = await cosmosClient.CreateDatabaseIfNotExistsAsync(DatabaseName);
            Console.WriteLine(database.Id);
            Container container = await database.CreateContainerIfNotExistsAsync(ContainerName, "/id");
            Console.WriteLine(container.Id);

            List<Task> tasks = new List<Task>();
            foreach (Item item in lists)
            {
                tasks.Add(container.CreateItemAsync(item, new PartitionKey(item.Id))
                    .ContinueWith((Task<ItemResponse<Item>> task) =>
                    {


                        Console.WriteLine("Status: " + task.Result.StatusCode + "    Resource: " + task.Result.Resource.Id);



                    }));


            }
            await Task.WhenAll(tasks);
            Console.ReadLine();
        }
        class Item
        {

            [JsonProperty(PropertyName = "id")]
            public string Id { get; set; }

            [JsonProperty(PropertyName = "name")]
            public string Name { get; set; }

            [JsonProperty(PropertyName = "age")]
            public string Age { get; set; }
        }
    }

My package.json

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="Microsoft.Azure.Cosmos" version="3.4.1" targetFramework="net461" />
  <package id="Newtonsoft.Json" version="10.0.2" targetFramework="net461" />
  <package id="System.Buffers" version="4.4.0" targetFramework="net461" />
  <package id="System.Configuration.ConfigurationManager" version="4.5.0" targetFramework="net461" />
  <package id="System.Memory" version="4.5.1" targetFramework="net461" />
  <package id="System.Numerics.Vectors" version="4.4.0" targetFramework="net461" />
  <package id="System.Runtime.CompilerServices.Unsafe" version="4.5.1" targetFramework="net461" />
  <package id="System.Security.AccessControl" version="4.5.0" targetFramework="net461" />
  <package id="System.Security.Permissions" version="4.5.0" targetFramework="net461" />
  <package id="System.Security.Principal.Windows" version="4.5.0" targetFramework="net461" />
  <package id="System.ServiceModel.Primitives" version="4.5.0" targetFramework="net461" />
  <package id="System.Threading.Tasks.Extensions" version="4.5.1" targetFramework="net461" />
  <package id="System.ValueTuple" version="4.5.0" targetFramework="net461" />
</packages>

enter image description here

Community
  • 1
  • 1
Jim Xu
  • 21,610
  • 2
  • 19
  • 39
  • It is giving the following exception: **An unhandled exception of type 'Microsoft.Azure.Cosmos.CosmosException' occurred in mscorlib.dll. You need to find AsyncMethodBuilder.cs to view the source for the current call stack frame.** – ashmit-001 Nov 21 '19 at 05:19
  • @aarohi-001 Could you please provide me the code and tell me the .net core version and Cosmos SDK version? – Jim Xu Nov 21 '19 at 05:33
  • As of now I'm trying it from .Net 4.6.1. Hope the code is for .Net as well. I'm using the code which you've provided. – ashmit-001 Nov 21 '19 at 06:56
  • @aarohi-001 I run my application with ```.Net Core 2.2.0``` and ```Microsoft.Azure.Cosmos 3.4.1```. It has no problem. I will test it with .Net 4.6.1 – Jim Xu Nov 21 '19 at 07:24
  • @aarohi-001 I run my code in .Net 4.6.1. It is also OK for me. For more details, please see my update. – Jim Xu Nov 21 '19 at 08:32
  • I'm trying the exactly same code. It's giving build error ie. **Program does not contain a static 'Main' method suitable for an entry point ConsoleApp2.** – ashmit-001 Nov 22 '19 at 05:25
  • @aarohi-001 Have you tried to make the Main Method like ```async static Task Main(string[] args)```? – Jim Xu Nov 22 '19 at 05:50
  • Yes I'm doing exactly the same as your code. And using same versions of packages as you're using. – ashmit-001 Nov 22 '19 at 06:02
  • 1
    @aarohi-001 Have you referred to https://stackoverflow.com/questions/9208921/cant-specify-the-async-modifier-on-the-main-method-of-a-console-app? – Jim Xu Nov 22 '19 at 06:27
  • This 'async main' issue is fixed. Had to switch to c# 7.1 and above from c# 7.0 for it to work. However I'm still facing the earlier issue. – ashmit-001 Nov 22 '19 at 06:28
  • I'm getting this error : **Response status code does not indicate success: 503 Reason: – ashmit-001 Nov 22 '19 at 06:42
  • 1
    @aarohi-001 Regarding the issue, please try to add the code ```var options = new CosmosClientOptions() { ConnectionMode = ConnectionMode.Gateway };``` in your project to use the gateway connection. For more details, please refer to https://github.com/MicrosoftDocs/azure-docs/issues/40649 – Jim Xu Nov 22 '19 at 06:59
  • Jim Xu - Thanks so much. The container is getting created ie. the connection is getting established successfully but I'm getting **System.Aggregate Exception** in the foreach loop. – ashmit-001 Nov 22 '19 at 08:48
  • @aarohi-001 could you please describe your error in detail? – Jim Xu Nov 22 '19 at 08:50
  • I'm getting this : **Operation will NOT be retried. Current attempt 0, Status Code: BadRequest Exception thrown: 'Microsoft.Azure.Cosmos.CosmosException' in Microsoft.Azure.Cosmos.Client.dll DocDBTrace Error: 0 : Operation will NOT be retried. Current attempt 0, Status Code: BadRequest Exception thrown: 'Microsoft.Azure.Cosmos.CosmosException' in Microsoft.Azure.Cosmos.Client.dll Exception thrown: 'System.AggregateException' in mscorlib.dll** – ashmit-001 Nov 22 '19 at 08:54
  • @aarohi-001 Regarding the 400 status code, please refer to [the official website](https://learn.microsoft.com/en-us/rest/api/cosmos-db/http-status-codes-for-cosmosdb) to ensure your issue. You also can try to add one recode and it will make it easier for you to debug your code. – Jim Xu Nov 22 '19 at 09:06
  • The foreach loop is working but the task are not getting executed. Not able to understand the exact issue. I think I'll mark your answer as correct because this seems some issue at my end. I'll ask a new question regarding this. But this answer helped me a lot to get to the solution easily. You can make the 'Gateway' update if it seems important. Thank you. – ashmit-001 Nov 22 '19 at 09:32
  • If you find something regarding this issue. Please reply me over this question : https://stackoverflow.com/questions/58991914/exception-thrown-microsoft-azure-cosmos-cosmosexception-bad-request-while-bu – ashmit-001 Nov 22 '19 at 10:16
1

Here is how you can handle this scenario architecturally which will be scalable and as per the guideline:

  • From you .Net Core aplication , when you are creating the json file , store it in Azure blob storage
  • As a next step , you create an Azure Function with the Azure blob storage trigger, you can check this link for reference:

https://learn.microsoft.com/en-us/azure/azure-functions/functions-create-storage-blob-triggered-function

  • From azure function , you can configure to use BulkImport .net library for updating the records in cosmos db.

    BulkImportResponse bulkImportResponse = await bulkExecutor.BulkImportAsync(
      documents: documentsToImportInBatch,
      enableUpsert: true,
      disableAutomaticIdGeneration: true,
      maxConcurrencyPerPartitionKeyRange: null,
      maxInMemorySortingBatchSize: null,
      cancellationToken: token);

This .NET library provides two overloads of the bulk import API - one that accepts a list of serialized JSON documents and the other that accepts a list of deserialized POCO documents. To learn more about the definitions of each of these overloaded methods, refer to the API documentation.

Check this link for further reference:

https://learn.microsoft.com/en-us/azure/cosmos-db/bulk-executor-dot-net

Above software design meet the expectation for availability, scalability and Maintainability.

Feel free to tag me in your conversation, hope it helps.

Mohit Verma
  • 5,140
  • 2
  • 12
  • 27
  • Bulk Executor is aimed at the SDK V2, SDK V3 has Bulk as part of the SDK, no extra libraries required https://devblogs.microsoft.com/cosmosdb/introducing-bulk-support-in-the-net-sdk/ and https://learn.microsoft.com/en-us/azure/cosmos-db/tutorial-sql-api-dotnet-bulk-import – Matias Quaranta Nov 20 '19 at 19:33