Bir hizmeti yapılandırırken Azure İşlev V3'te Bağımlılık Enjeksiyonu ile IConfiguration nasıl enjekte edilir veya kullanılır


10

Normalde bir .NET Core projesinde, hizmetimi DI kayıt komutlarıyla birlikte yapılandırmak için bir 'boostrap' sınıfı oluştururdum. Bu genellikle IServiceCollectionböyle bir yöntemi çağırabileceğim bir uzatma yöntemidir .AddCosmosDbServiceve gereken her şey bu yöntemi içeren statik sınıfta 'kendi kendine yeten' dir. Anahtar rağmen yöntem alır olduğunu IConfigurationgelen Startupsınıfı.

Geçmişte Azure İşlevleri'nde DI ile çalıştım ancak henüz bu özel gereksinimle karşılaşmadım.

İşlev Azure'da dağıtıldığında IConfigurationhem benim local.settings.jsonhem de dev / üretim uygulama ayarlarından eşleşen özelliklerle somut bir sınıfa bağlanmak için kullanıyorum .

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?
    }
}

İçin Açıkçası özel alan ekleyerek IConfigurationde Startup.csolmaz işler o şey ile doldurulması gerekir ve ben de okumuştum olarak için DI kullanarak IConfigurationiyi bir fikir değildir .

Ben de burada açıklandığı gibi seçenekler desen kullanarak denedim ve böyle uygulanır:

builder.Services.AddOptions<CosmosDbClientSettings>()
    .Configure<IConfiguration>((settings, configuration) => configuration.Bind(settings));

Bu IOptions<CosmosDbClientSettings>statik olmayan bir sınıfa enjekte etmek için çalışırken, yapılandırma çalışmalarımı tutmak için statik bir sınıf kullanıyorum.

Bu işi veya olası bir çözümü nasıl yapabileceğime dair herhangi bir öneriniz var mı? Tüm yapılandırmayı tek bir yerde (bootstrap dosyası) tutmayı tercih ederim.

Yanıtlar:


6

Bağlantılı örnek zayıf (Bence) tasarlanmıştır. Sıkı bağlantıyı ve asenkron bekleme ve engelleme çağrılarının karıştırılmasını teşvik eder.

IConfigurationbir parçası olarak, varsayılan olarak hizmet koleksiyona eklenir O kadar bağımlılıkları ertelenen kararın yararlanmak için tasarım kadar değişen öneririm böylece, başlangıç IConfigurationinşa yoluyla çözülebilir IServiceProviderbir fabrika temsilci kullanarak.

public static class BootstrapCosmosDbClient {

    private static event EventHandler initializeDatabase = delegate { };

    public static IServiceCollection AddCosmosDbService(this IServiceCollection services) {

        Func<IServiceProvider, ICosmosDbService> factory = (sp) => {
            //resolve configuration
            IConfiguration configuration = sp.GetService<IConfiguration>();
            //and get the configured settings (Microsoft.Extensions.Configuration.Binder.dll)
            CosmosDbClientSettings cosmosDbClientSettings = configuration.Get<CosmosDbClientSettings>();
            string databaseName = cosmosDbClientSettings.CosmosDbDatabaseName;
            string containerName = cosmosDbClientSettings.CosmosDbCollectionName;
            string account = cosmosDbClientSettings.CosmosDbAccount;
            string key = cosmosDbClientSettings.CosmosDbKey;

            CosmosClientBuilder clientBuilder = new CosmosClientBuilder(account, key);
            CosmosClient client = clientBuilder.WithConnectionModeDirect().Build();
            CosmosDbService cosmosDbService = new CosmosDbService(client, databaseName, containerName);

            //async event handler
            EventHandler handler = null;
            handler = async (sender, args) => {
                initializeDatabase -= handler; //unsubscribe
                DatabaseResponse database = await client.CreateDatabaseIfNotExistsAsync(databaseName);
                await database.Database.CreateContainerIfNotExistsAsync(containerName, "/id");
            };
            initializeDatabase += handler; //subscribe
            initializeDatabase(null, EventArgs.Empty); //raise the event to initialize db

            return cosmosDbService;
        };
        services.AddSingleton<ICosmosDbService>(factory);
        return service;
    }
}

async voidEşzamansız olmayan bir olay işleyicisinde kullanmak zorunda kalmanın üstesinden gelmek için alınan yaklaşıma dikkat edin .

Referans Eşzamansız / Bekliyor - Eşzamansız Programlamada En İyi Uygulamalar .

Böylece şimdi Configuredüzgün bir şekilde çağrılabilir.

public class Startup : FunctionsStartup {

    public override void Configure(IFunctionsHostBuilder builder) =>
        builder.Services
            .AddHttpClient()
            .AddCosmosDbService();
}

5

İşte kamçılayabildiğim bir örnek; merkezi yapılandırma ve özellik yönetimi için Azure Uygulama Yapılandırması ile bağlantı kurar . Bir ASP.NET Core denetleyicisinde olduğu gibi IConfigurationve gibi tüm DI özelliklerini kullanabilmelidir IOptions<T>.

NuGet Bağımlılıkları

  • Install-Package Microsoft.Azure.Functions.Extensions
  • Install-Package Microsoft.Extensions.Configuration.AzureAppConfiguration

Startup.cs

[assembly: FunctionsStartup(typeof(Startup))]

public class Startup : FunctionsStartup
{
    public override void Configure(IFunctionsHostBuilder hostBuilder) {
        var serviceProvider = hostBuilder.Services.BuildServiceProvider();
        var configurationRoot = serviceProvider.GetService<IConfiguration>();
        var configurationBuilder = new ConfigurationBuilder();
        var appConfigEndpoint = configuration["AppConfigEndpoint"];

        if (configurationRoot is IConfigurationRoot) {
            configurationBuilder.AddConfiguration(configurationRoot);
        }

        if (!string.IsNullOrEmpty(appConfigEndpoint)) {
            configurationBuilder.AddAzureAppConfiguration(appConfigOptions => {
                // possible to run this locally if refactored to use ClientSecretCredential or DefaultAzureCredential
                appConfigOptions.Connect(new Uri(appConfigEndpoint), new ManagedIdentityCredential());
            });
        }

        var configuration = configurationBuilder.Build();

        hostBuilder.Services.Replace(ServiceDescriptor.Singleton(typeof(IConfiguration), configuration));

        // Do more stuff with Configuration here...
    }
}

public sealed class HelloFunction
{
    private IConfiguration Configuration { get; }

    public HelloFunction(IConfiguration configuration) {
        Configuration = configuration;
    }

    [FunctionName("HelloFunction")]
    public void Run([TimerTrigger("0 */1 * * * *")]TimerInfo myTimer, ILogger log) {
        log.LogInformation($"Timer Trigger Fired: 'Hello {Configuration["Message"]}!'");
    }
}

Bu yaklaşımla, host.jsonözellikle parametrelerin kullanılmadığı bir sorunum varroutePrefix
Andrii

1
@Andrii İlginç, biraz araştırma yapmam gerekecek ve bir çözüm bulunursa yazımı düzenleyeceğim; kafalar için bir ton teşekkürler!
Kittoes0124
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.