Console에서 IHost 사용

만들고자하는 것은 .NET 5 Console Application에서 Azure Service Bus의 Queue데이터를 1초 간격으로 POP하는 것입니다.

구글링해서 IHost를 통해 설정파일을 가져오는 것까지는 성공했습니다.
하지만 서비스를 Singleton으로 등록했더니 Service를 호출하기 전까지는 생성자가 호출되는 것도 볼 수 없었고, 그렇다고 Main 함수에 RunAsync를 하기전에 while 무한루프를 돌리자니 이건 아닌거 같습니다. 어떻게 구현 할 수 있을까요?

    class Program
    {
        static async Task Main(string[] args)
        {
            using IHost host = CreateHostBuilder(args).UseConsoleLifetime().Build();
            await host.RunAsync();
        }

        static IHostBuilder CreateHostBuilder(string[] args)
        {
            IHostBuilder rtnValue = Host.CreateDefaultBuilder(args)
                .ConfigureAppConfiguration((hostingContext, configuration) =>
                {
                    configuration.Sources.Clear();

                    IHostEnvironment env = hostingContext.HostingEnvironment;

                    configuration.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath);
                    configuration.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
                    //configuration.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);

                    IConfigurationRoot configurationRoot = configuration.Build();
                    AzureServiceBusSettings settings = new();
                    configurationRoot.GetSection(nameof(AzureServiceBusSettings)).Bind(settings);

                    Console.WriteLine($"AzureServiceBus Key={settings.Endpoint}");
                    Console.WriteLine($"AzureSerivceBus QueueName={settings.QueueName}");
                })
                .ConfigureServices((context, services) =>
                {
                    services.Configure<AzureServiceBusSettings>(context.Configuration);
                    services.AddSingleton<AzureServiceBusService>();
                });

            return rtnValue;
        }
    }
        //
        // 요약:
        //     Adds a singleton service of the type specified in serviceType with an instance
        //     specified in implementationInstance to the specified Microsoft.Extensions.DependencyInjection.IServiceCollection.
        //
        // 매개 변수:
        //   services:
        //     The Microsoft.Extensions.DependencyInjection.IServiceCollection to add the service
        //     to.
        //
        //   serviceType:
        //     The type of the service to register.
        //
        //   implementationInstance:
        //     The instance of the service.
        //
        // 반환 값:
        //     A reference to this instance after the operation has completed.
        public static IServiceCollection AddSingleton(this IServiceCollection services, Type serviceType, object implementationInstance);

이 메소드를 써보세요

AzureServiceBusService 라는 클래스가

    public AzureServiceBusService(
            ILogger<AzureServiceBusService> logger,
            IHostApplicationLifetime appLifetime,
            IOptions<AzureServiceBusSettings> settings)
        {
            _logger = logger;
            _appLifetime = appLifetime;
            connString = settings.Value.Endpoint;
            queueName = settings.Value.QueueName;
            timerState = new TimerState { Counter = TimerStateEnum.Run };
            popTimer = new Timer(
                callback: new TimerCallback(PopData),
                state: timerState,
                dueTime: 0,
                period: 1000);
        }

위와 같은 생성자를 지니고 있습니다… 기본 생성자를 만들자니, 파라미터를 서비스 등록 시 받지 못하는 점이 있습니다. 이렇게하면 static으로 settings값들을 받아서 넘겨줘야할거같은데, 그렇게 하는 방법 밖에 없을까요…?

아… 인스턴스를 넘겨주는 방식입니다. 원하는 개체를 생성후 인자로 넘겨주면 되어요

저도 주말에 크론작업이 필요해 Quartz.net 이나 Hangfire 알아보다 가벼운 서비스가 필요해서 Hangfire Cronos보고 간단히 쓰고 있습니다. 필요하신게 맞는건지는 모르겠네요.

IHostedService를 통해 서비스를 singleton으로 생성하고 Cron Expression을 이용해 타이머를 조작합니다.
일부 수정해서 사용해보니 잘 작동합니다.

https://codeburst.io/schedule-cron-jobs-using-hostedservice-in-asp-net-core-e17c47ba06

좋아요 2

아…Quartz.NET 이 뭔지 모르겠는데 나중에 찾아봐야겠군요.
IHostedService에서 힌트를 얻어서 다음과 같이 작성했더니 원하는 대로 동작합니다!!
감사합니다.

    class Program
    {
        static async Task Main(string[] args)
        {
            using IHost host = CreateHostBuilder(args).Build();
            await host.RunAsync();
        }

        static IHostBuilder CreateHostBuilder(string[] args)
        {
            IHostBuilder rtnValue = Host.CreateDefaultBuilder(args)
                .UseConsoleLifetime()
                .ConfigureAppConfiguration((hostingContext, configuration) =>
                {
                    configuration.Sources.Clear();

                    IHostEnvironment env = hostingContext.HostingEnvironment;

                    configuration.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath);
                    configuration.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
                    //configuration.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);

                    IConfigurationRoot configurationRoot = configuration.Build();
                    AzureServiceBusSettings settings = new();
                    configurationRoot.GetSection(nameof(AzureServiceBusSettings)).Bind(settings);

                    Console.WriteLine($"AzureServiceBus Key={settings.Endpoint}");
                    Console.WriteLine($"AzureSerivceBus QueueName={settings.QueueName}");
                })
                .ConfigureServices((context, services) =>
                {
                    services.Configure<AzureServiceBusSettings>(context.Configuration.GetSection(AzureServiceBusSettings.Settings)); // 여기 수정했습니다.
                    services.AddHostedService<AzureServiceBusService>(); // 여기 수정했습니다. Singleton -> AddHostedService
                });

            return rtnValue;
        }
    }
좋아요 1