在asp.net核心应用程序中实现了IHostedService,如何在IIS上运行它而不需要第一个请求



我已经在asp.net核心网站中实现了IHostedService。它工作得很好,但问题是我希望它在托管服务器启动或IIS服务重新启动时启动,但除非第一个请求到达网站,否则它不会启动。

  • 该网站托管在IIS 10.0.18版本上
  • AppPool处于"AlwaysRunning"模式
  • "PreloadEnabled"在网站上为"True">
  • 将".NET CLR版本"设置为"无托管代码"或"v4.0.xxxxxx"没有帮助
  • dotnet核心版本为2.2,并安装了dotnet核心托管捆绑包

更新1:"应用程序初始化模块",@Arthur建议没有帮助。既不在站点级别,也不在服务器级别。

我使用的配置:

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

UPDATE 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文件中的程序类:

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)
{
}
}

由于建议的"应用初始化模块";不起作用,你可以考虑自己打电话给之后的客户

模块启动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核心应用程序

将其托管在"OutOfProcess"中可以做到这一点,但请记住,这不是首选方式。我用给定的代码在GitHub上创建了一个repo,您可以在上次提交时检查更改。

来源: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.

以下是我如何创建webservices。在Startup.cs中,我注入了我的IHostedServices。CCD_ 4是CCD_ 5的一个类。我已经从一个现有的项目中复制了它,所以它不能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>();
}
...
}

最新更新