5

我有一个托管服务,每分钟检查一个电子邮件帐户。我还将 MVC 与 Web API 2.1 一起使用。为了让我的托管服务启动,我必须通过调用 API 方法来“唤醒它”。在 Web API 一段时间不活动后,托管服务进入睡眠状态并停止检查电子邮件。就像它正在收集垃圾一样。如何让它连续运行?

协助将不胜感激。

启动.cs:

public void ConfigureServices(IServiceCollection services)
    {
        services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new Info {Title = "CAS API", Version = "v1"});

                // Set the comments path for the Swagger JSON and UI.
                var xmlFile = $"{Assembly.GetEntryAssembly().GetName().Name}.xml";
                var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
                c.IncludeXmlComments(xmlPath);
            })

            .AddCors(options =>
            {
                options.AddPolicy("CorsPolicy",
                    builder => builder.WithOrigins(Configuration["uiOrigin"])
                        .AllowAnyMethod()
                        .AllowAnyHeader()
                        .AllowCredentials());
            })
            .AddHostedService<EmailReceiverHostedService>()
            .Configure<EmailSettings>(Configuration.GetSection("IncomingMailSettings"))
            .AddSingleton<IEmailProcessor, MailKitProcessor>()
            .AddSingleton<IEmailRepository, EmailRepository>()


          ...

EmailReceiverHostedService.cs:

using CasEmailProcessor.Options;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System;
using System.Threading;
using System.Threading.Tasks;

public class EmailReceiverHostedService : IHostedService, IDisposable
{
    private readonly ILogger _logger;
    private readonly Timer _timer;
    private readonly IEmailProcessor _processor;
    private readonly EmailSettings _emailConfig;


    public EmailReceiverHostedService(ILoggerFactory loggerFactory,
        IOptions<EmailSettings> settings,
        IEmailProcessor emailProcessor)
    {
        _logger = loggerFactory.CreateLogger("EmailReceiverHostedService");
        _processor = emailProcessor;
        _emailConfig = settings.Value;
        _timer = new Timer(DoWork, null, Timeout.Infinite, Timeout.Infinite);
    }

    public Task StartAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Timed Background Service is starting.");
        StartTimer();
        return Task.CompletedTask;
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Timed Background Service is stopping.");
        StopTimer();

        return Task.CompletedTask;
    }

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

    private void StopTimer()
    {
        _timer?.Change(Timeout.Infinite, 0);
    }
    private void StartTimer() { _timer.Change(TimeSpan.FromSeconds(_emailConfig.TimerIntervalInSeconds), TimeSpan.FromSeconds(_emailConfig.TimerIntervalInSeconds)); }

    private void DoWork(object state)
    {
        StopTimer();
        _processor.Process();
        StartTimer();
    }
}
4

2 回答 2

8

如您所想,根本原因是在 IIS 中托管时,由于应用程序池回收,您的主机可能会被关闭。这已在下面指出:

请务必注意,部署 ASP.NET Core WebHost 或 .NET Core 主机的方式可能会影响最终解决方案。例如,如果您将 WebHost 部署在 IIS 或常规 Azure App Service 上,您的主机可能会因为应用程序池回收而关闭。

部署注意事项和要点

对于可能的解决方法,您可以尝试将空闲超时设置为零以禁用默认回收。

由于 IIS 默认回收,您可以考虑不同的托管方法:

  • 使用 Windows 服务

  • 使用 Docker 容器(Windows 容器),但为此,您需要 Windows Server 2016 或更高版本。

  • 使用 Azure 函数

对于您的方案,您可以尝试在 Windows 服务中托管 ASP.NET Core

于 2018-09-20T07:22:27.090 回答
1

我在 Windows 事件计划程序上创建任务以访问 URL 以唤醒服务。

powershell.exe -command {Invoke-WebRequest http://localhost:8080 }

于 2019-01-23T10:46:28.033 回答