web-dev-qa-db-ja.com

asp.netコアアプリにIHostedServiceを実装しました。IISで最初の要求なしにそれを実行する方法は?

IHostedServiceをasp.netコアWebサイトに実装しました。それはうまく機能しますが、問題は、ホスティングサーバーの起動時またはIISサービスの再起動時に開始されるようにしたいのですが、Webサイトへの最初の要求が来ない限り開始されません。

  • WebサイトはIISバージョン10.0.18でホストされています
  • AppPoolは "AlwaysRunning"モードです
  • 「PreloadEnabled」はWebサイトで「True」です。
  • 「.NET CLRバージョン」を「マネージコードなし」または「v4.0.xxxxxx」に設定しても、効果はありませんでした。
  • dotnetコアのバージョンは2.2で、dotnetコアホスティングバンドルがインストールされています。

PDATE 1:「アプリケーション初期化モジュール」、@ Arthurの提案は役に立ちませんでした。サイトレベルでもサーバーレベルでもありません。

私が使用した構成:

    <applicationInitialization
         doAppInitAfterRestart="true"
         skipManagedModules="false"
         remapManagedRequestsTo="init.htm">
        <add initializationPage="/init.htm" hostName="localhost"/>
    </applicationInitialization>

PDATE 2:インターフェースの実装方法は次のとおりです

internal class PaymentQueueService : IHostedService, IDisposable
{
    private readonly ILogger _logService;
    private Timer _timerEnqueue;

    public PaymentQueueService(ILogger logService)
    {
        _logService = logService;
    }

    public Task StartAsync(CancellationToken cancellationToken)
    {
        _logService.LogInformation("Starting processing payments.");

        _timerEnqueue = new Timer(EnqueuePayments, null, TimeSpan.Zero,
            TimeSpan.FromSeconds(10));

        return Task.CompletedTask;
    }

    private void EnqueuePayments(object state)
    {
        _logService.LogInformation("Enqueueing Payments.");
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        _logService.LogInformation("Stopping processing payments.");

        _timerEnqueue?.Change(Timeout.Infinite, 0);

        return Task.CompletedTask;
    }

    public void Dispose()
    {
        _timerEnqueue?.Dispose();
    }
}

Main.csファイルのProgramクラス:

public class Program
    {
        public static void Main(string[] args)
        {
            CreateWebHostBuilder(args).Build().Run();
        }

        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args).ConfigureServices(services =>
            {
                services.AddHostedService<PaymentQueueService>();
            }).Configure((IApplicationBuilder app) =>
            {

                app.UseMvc();
            })
                .UseStartup<Startup>();
    }

スタートアップクラス:

public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {

        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostEnvironment env)
        {

        }
    }
6
desmati

提案された「アプリケーション初期化モジュール」が機能しなかったため、クライアントで自分で呼び出すことを検討できます。

モジュールは、最初のリクエストが到着したときにASP.NET Coreアプリのプロセスを開始し、シャットダウンまたはクラッシュした場合にアプリを再起動します。

public class Program {
    static Lazy<HttpClient> client = new Lazy<HttpClient>();
    public static async Task Main(string[] args) {
        var Host = CreateWebHostBuilder(args).Start();//non blocking start
        using (Host) {
            bool started = false;
            do {
                var response = await client.Value.GetAsync("site root");
                started = response.IsSuccessStatusCode;
                await Task.Delay(someDelayHere);
            } while (!started);

            Host.WaitForShutdown();
        }
    }

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .ConfigureServices(services => {
                services.AddHostedService<PaymentQueueService>();
            })
            .Configure((IApplicationBuilder app) => {
                app.UseMvc();
            })
            .UseStartup<Startup>();
}

注:

アウトプロセスでホストされているアプリがタイムアウトしないようにするには、次のいずれかの方法を使用します。

  • アプリを実行し続けるために、外部サービスからアプリにpingします。
  • アプリがバックグラウンドサービスのみをホストする場合は、IISホスティングを避け、Windowsサービスを使用してASP.NET Coreアプリをホストします。
1
Nkosi

これがwebservicesを作成する方法です。の中に Startup.csIHostedServicesを注入します。 ContainerStructureMapのクラスです。既存のプロジェクトからコピーしたため、サンプルに100%適合しません。

public class Program
{
    public static void Main(string[] args)
    {
        Config.Directories.EnsureDirectoryTree();

        var isService = !(Debugger.IsAttached || args.Contains("--console"));
        var webHostService = MyWebHostService.BuildWebHostService(args.Where(arg => arg != "--console").ToArray());

        if (isService)
        {
            ServiceBase.Run(webHostService);
        }
        else
        {
            webHostService.InitializeBackend();
            webHostService.Host.Run();
        }
    }
}

public class MyWebHostService : WebHostService
{
    public static readonly Logger Logger = LogManager.GetCurrentClassLogger();

    public IWebHost Host { get; }

    public static ZlsWebHostService BuildWebHostService(string[] args)
    {
        ConfigureNLog();

        Logger.Info("{0} (v{1}) starting...", Config.ServiceName, GetApplicationVersion());

        // restore config files
        Config.Files.EnsureRestored();

        var Host = CreateWebHostBuilder(args).Build();
        return new ZlsWebHostService(Host);
    }

    public static IWebHostBuilder CreateWebHostBuilder(string[] args)
    {
        var pathToExe = Assembly.GetExecutingAssembly().Location;
        var pathToContentRoot = Path.GetDirectoryName(pathToExe);

        return WebHost.CreateDefaultBuilder()
            .UseKestrel()
            .UseContentRoot(pathToContentRoot)
            .ConfigureAppConfiguration((context, config) =>
            {
                config.SetBasePath(Config.Directories.ActiveConfig);
                config.AddJsonFile(Config.Files.KestrelConfig.RelativePath, true, true);})
            .ConfigureLogging((hostingContext, logging) =>
            {
                logging.ClearProviders();
                logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
                logging.AddConsole();
                if(hostingContext.HostingEnvironment.IsDevelopment())
                    logging.AddDebug();
            })
            .UseNLog()
            .UseStartup<Startup>();
    }

    public MyWebHostService(IWebHost Host) : base(Host)
    {
        this.Host = Host;
    }

    protected override void OnStarting(string[] args)
    {
        InitializeBackend();

        base.OnStarting(args);
    }

    protected override void OnStarted()
    {
        Logger.Info("{0} started...", Config.ServiceName);
        base.OnStarted();
    }

    protected override void OnStopped()
    {
        Logger.Info("{0} stopped...", Config.ServiceName);
        base.OnStopped();
    }

...

}

public class Startup
{
...

    // This method gets called by the runtime. Use this method to add services to the container.
    // For more information on how to configure your application, visit https://go.Microsoft.com/fwlink/?LinkID=398940
    public IServiceProvider ConfigureServices(IServiceCollection services)
    {
        ...

        services.AddSingleton<PaymentQueueService>();

        ...

        var container = new Container(c =>
        {
            c.IncludeRegistry<MyFooRegistry>();
            c.Populate(services);
        });
        return container.GetInstance<IServiceProvider>();
    }

...

}
0
Dominic Jonas

"OutOfProcess"をホストすることでトリックは実現しますが、推奨される方法ではないことに注意してください。指定されたコードでGitHubにリポジトリを作成しました。最後のコミットで変更を確認できます。

ソース: https://github.com/tvdias/SO58831661

InProcessとOutOfProcessの違いに関する詳細な説明については、このページをお読みになることをお勧めします。 https://weblog.west-wind.com/posts/2019/Mar/16/ASPNET-Core-Hosting-on-IIS -with-ASPNET-Core-22

0
tvdias