Skip to content

Instantly share code, notes, and snippets.

@ealsur
Created April 16, 2021 17:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ealsur/01b99715c98e11a6bd0ce7c4ea5e80dd to your computer and use it in GitHub Desktop.
Save ealsur/01b99715c98e11a6bd0ce7c4ea5e80dd to your computer and use it in GitHub Desktop.
Create and initialize CosmosClient
List<(string, string)> containers = new List<(string, string)>
{
("DatabaseNameForContainer1", "ContainerName1"),
("DatabaseNameForContainer2", "ContainerName2")
};
CosmosClientOptions cosmosClientOptions = new CosmosClientOptions
{
ApplicationName = "MyApplicationName",
// any other setting I want to customize
};
CosmosClient cosmosClient = await CosmosClient.CreateAndInitializeAsync(connectionString, containers, cosmosClientOptions);
@cannehag
Copy link

Any suggestion on how to configure this using CosmosClientBuilder or IServiceCollection registration?

@ealsur
Copy link
Author

ealsur commented Apr 26, 2021

@cannehag, There is no alternative for CosmosClientBuilder currently. For IServiceCollection you can initialize and then place the CosmosClient resulting object with AddSingleton?

@cannehag
Copy link

Well, not when using the serviceprovider to get the connectionstring from another service.
I've been using the AddSingleton(IServiceProvider) method which will not work in this case.
But, at least I know the options, thanks!

@ealsur
Copy link
Author

ealsur commented Apr 26, 2021

@cannehag Could you share how you are initializing the client now with IServiceProvider? No real credentials please. Ideally you should be able to replace the place you are doing new CosmosClient(.. with CosmosClient.CreateAndInitializeAsync, both will return the client instance.

@cannehag
Copy link

Sure. This is what I have today. This is a Functions app and from my FunctionsStartup.Configure(IFunctionsHostBuilder) I call this extension method:

internal static class ServiceCollectionExtensions
{
    public static void AddCosmosDbClient(this IServiceCollection services)
    {
        services.AddSingleton(serviceProvider =>
        {
            var config = serviceProvider.GetRequiredService<IConfig>();
             var clientBuilder = new CosmosClientBuilder(config.CosmosDbConnectionString);
            var client = clientBuilder
                .WithConnectionModeDirect()
                .WithSerializerOptions(new CosmosSerializationOptions
                {
                    IgnoreNullValues = false,
                    PropertyNamingPolicy = CosmosPropertyNamingPolicy.CamelCase
                })
                .Build();
            return client;
        });
    }
}

@ealsur
Copy link
Author

ealsur commented Apr 27, 2021

This might work on that case:

internal static class ServiceCollectionExtensions
{
    public static void AddCosmosDbClient(this IServiceCollection services)
    {
        services.AddSingleton(serviceProvider =>
        {
            List<(string, string)> containers = new List<(string, string)> 
	    {
		  ("DatabaseNameForContainer1", "ContainerName1"),
		  ("DatabaseNameForContainer2", "ContainerName2")
	    };

            var config = serviceProvider.GetRequiredService<IConfig>();
			var options = new CosmosClientOptions();
			options.SerializerOptions = new CosmosSerializationOptions
                {
                    IgnoreNullValues = false,
                    PropertyNamingPolicy = CosmosPropertyNamingPolicy.CamelCase
                };
            var client = CosmosClient.CreateAndInitializeAsync(config.CosmosDbConnectionString, containers, options).GetAwaiter().GetResult();
            return client;
        });
    }
}

@cannehag
Copy link

Yes that is the way to configure it, but it won't really do anything until I request a CosmosClient from the ServiceProvider which is not done in the startup.
One option would be to, the last thing, build the serviceprovider and request a client, but that sounds like a bad idea...

@ealsur
Copy link
Author

ealsur commented Apr 28, 2021

You can build the client before?

internal static class ServiceCollectionExtensions
{
    public static void AddCosmosDbClient(this IServiceCollection services)
    {
		List<(string, string)> containers = new List<(string, string)> 
		{
		  ("DatabaseNameForContainer1", "ContainerName1"),
		  ("DatabaseNameForContainer2", "ContainerName2")
		};

		var config = serviceProvider.GetRequiredService<IConfig>();
		var options = new CosmosClientOptions();
		options.SerializerOptions = new CosmosSerializationOptions
			{
				IgnoreNullValues = false,
				PropertyNamingPolicy = CosmosPropertyNamingPolicy.CamelCase
			};
		var client = CosmosClient.CreateAndInitializeAsync(config.CosmosDbConnectionString, containers, options).GetAwaiter().GetResult();
	
        services.AddSingleton(serviceProvider =>
        {
            return client;
        });
    }
}

@cannehag
Copy link

This is kind of getting to my point with the post :)
If you try that code you see that you don't have access to the serviceProvider at that stage.

I understand that my question might be tricky to solve, but at least to me, this looks like a pretty normal setup of a client.

@ealsur
Copy link
Author

ealsur commented Apr 29, 2021

I see what you mean, you cannot read the config because in your case it comes from serviceProvider.

I've seen cases from it coming from the Configuration, which is built before the services are added (so it's available there).

@cannehag
Copy link

cannehag commented May 3, 2021

Yes, I went with that option instead. That works too :)
Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment