서비스를 구성 할 때 종속성 주입을 사용하여 Azure Function V3에서 IConfiguration을 주입하거나 사용하는 방법

제이슨 셰 이브

일반적으로 .NET Core 프로젝트에서 DI 등록 명령과 함께 내 서비스를 구성하기 위해 '부 스트랩'클래스를 만듭니다. 이것은 일반적으로 같은 메서드를 IServiceCollection호출 할 수 있는 확장 메서드이며 .AddCosmosDbService필요한 모든 것은 해당 메서드를 포함하는 정적 클래스에서 '자체 포함'됩니다. 그러나 핵심은 메서드가 클래스 IConfiguration에서 가져 오는 것 입니다 Startup.

과거에 Azure Functions에서 DI로 작업했지만 아직이 특정 요구 사항을 만나지 못했습니다.

내가 사용하고 IConfiguration속성 모두에서 설정 내 일치하는 구체적인 클래스에 바인딩하는 local.settings.json기능이 푸른에 배포 할 때뿐만 아니라 dev에 / 생산 응용 프로그램 설정을.

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

분명히 IConfigurationin에 대한 비공개 필드를 추가하는 것은 Startup.cs무언가로 채워 져야하기 때문에 작동하지 않으며 DI를 사용 IConfiguration하는 것이 좋은 생각이 아니라는 것도 읽었습니다 .

또한 여기에 설명 된대로 옵션 패턴을 사용해 보았고 다음 과 같이 구현했습니다.

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

이것은 IOptions<CosmosDbClientSettings>비 정적 클래스 에 주입하는 작동하지만 정적 클래스를 사용하여 구성 작업을 유지하고 있습니다.

이 작업을 수행하거나 가능한 해결 방법에 대한 제안 사항이 있습니까? 모든 구성을 한곳 (부트 스트랩 파일)에 보관하고 싶습니다.

Nkosi

링크 된 예는 제대로 (제 생각에) 설계되었습니다. 긴밀한 결합과 비동기 대기 및 차단 호출의 혼합을 장려합니다.

IConfiguration기본적으로 시작의 일부로 서비스 컬렉션에 추가되므로 팩토리 위임을 사용 IConfiguration하여 빌드 IServiceProvider통해 해결할 수 있도록 지연된 종속성 확인을 활용하도록 디자인을 변경하는 것이 좋습니다 .

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 void비동기 이벤트 핸들러에서 사용해야하는 문제를 해결하기 위해 취한 접근 방식에 유의하십시오 .

참조 Async / Await-비동기 프로그래밍의 모범 사례 .

이제를 Configure제대로 호출 할 수 있습니다.

public class Startup : FunctionsStartup {

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

이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.

침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제

에서 수정
0

몇 마디 만하겠습니다

0리뷰
로그인참여 후 검토

관련 기사

Related 관련 기사

뜨겁다태그

보관