Normalmente, em um projeto .NET Core, eu criaria uma classe 'boostrap' para configurar meu serviço junto com os comandos de registro DI. Normalmente, esse é um método de extensão no IServiceCollection
qual eu posso chamar um método .AddCosmosDbService
e tudo o que é necessário é 'independente' na classe estática que contém esse método. A chave, porém, é que o método obtém um IConfiguration
da Startup
classe.
Eu trabalhei com DI no Azure Functions no passado, mas ainda não encontrei esse requisito específico.
Estou usando o IConfiguration
para vincular a uma classe concreta com propriedades que correspondem às configurações do meu local.settings.json
e do aplicativo de desenvolvimento / produção quando a Função é implantada no Azure.
CosmosDbClientSettings.cs
/// <summary>
/// Holds configuration settings from local.settings.json or application configuration
/// </summary>
public class CosmosDbClientSettings
{
public string CosmosDbDatabaseName { get; set; }
public string CosmosDbCollectionName { get; set; }
public string CosmosDbAccount { get; set; }
public string CosmosDbKey { get; set; }
}
BootstrapCosmosDbClient.cs
public static class BootstrapCosmosDbClient
{
/// <summary>
/// Adds a singleton reference for the CosmosDbService with settings obtained by injecting IConfiguration
/// </summary>
/// <param name="services"></param>
/// <param name="configuration"></param>
/// <returns></returns>
public static async Task<CosmosDbService> AddCosmosDbServiceAsync(
this IServiceCollection services,
IConfiguration configuration)
{
CosmosDbClientSettings cosmosDbClientSettings = new CosmosDbClientSettings();
configuration.Bind(nameof(CosmosDbClientSettings), cosmosDbClientSettings);
CosmosClientBuilder clientBuilder = new CosmosClientBuilder(cosmosDbClientSettings.CosmosDbAccount, cosmosDbClientSettings.CosmosDbKey);
CosmosClient client = clientBuilder.WithConnectionModeDirect().Build();
CosmosDbService cosmosDbService = new CosmosDbService(client, cosmosDbClientSettings.CosmosDbDatabaseName, cosmosDbClientSettings.CosmosDbCollectionName);
DatabaseResponse database = await client.CreateDatabaseIfNotExistsAsync(cosmosDbClientSettings.CosmosDbDatabaseName);
await database.Database.CreateContainerIfNotExistsAsync(cosmosDbClientSettings.CosmosDbCollectionName, "/id");
services.AddSingleton<ICosmosDbService>(cosmosDbService);
return cosmosDbService;
}
}
Startup.cs
public class Startup : FunctionsStartup
{
public override async void Configure(IFunctionsHostBuilder builder)
{
builder.Services.AddHttpClient();
await builder.Services.AddCosmosDbServiceAsync(**need IConfiguration reference**); <--where do I get IConfiguration?
}
}
Obviamente, adicionar um campo privado para IConfiguration
in Startup.cs
não funcionará, pois precisa ser preenchido com algo e também li que usar DI para IConfiguration
não é uma boa ideia .
Também tentei usar o padrão de opções descrito aqui e implementado da seguinte forma:
builder.Services.AddOptions<CosmosDbClientSettings>()
.Configure<IConfiguration>((settings, configuration) => configuration.Bind(settings));
Enquanto isso funcionaria para injetar um IOptions<CosmosDbClientSettings>
em uma classe não estática, estou usando uma classe estática para manter meu trabalho de configuração.
Alguma sugestão sobre como posso fazer isso funcionar ou uma possível solução alternativa? Eu preferiria manter toda a configuração em um só lugar (arquivo de inicialização).
host.json
parâmetros não são usados, em particular,routePrefix