Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-core/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何在没有http请求的情况下在MVC核心应用程序中启动HostedService_C#_Asp.net Core_Asp.net Core Hosted Services - Fatal编程技术网

C# 如何在没有http请求的情况下在MVC核心应用程序中启动HostedService

C# 如何在没有http请求的情况下在MVC核心应用程序中启动HostedService,c#,asp.net-core,asp.net-core-hosted-services,C#,Asp.net Core,Asp.net Core Hosted Services,在我的MVC.NETCore2.2应用程序中,有一个HostedService正在做后台工作 它在Startap类的ConfigureServices方法中注册 services.AddHostedService<Engines.KontolerTimer>(); services.AddHostedService(); 由于这是独立于用户请求的后台服务,我想在应用程序启动时立即启动后台服务。 现在是我的HostedService在第一个用户请求后启动的情况 当MVC核心应用程序

在我的MVC.NETCore2.2应用程序中,有一个HostedService正在做后台工作

它在Startap类的ConfigureServices方法中注册

services.AddHostedService<Engines.KontolerTimer>();
services.AddHostedService();
由于这是独立于用户请求的后台服务,我想在应用程序启动时立即启动后台服务。 现在是我的HostedService在第一个用户请求后启动的情况

当MVC核心应用程序启动时,启动HostedService的正确方式是什么

我的球衣看起来像这个

内部类TimedHostedService:IHostedService,IDisposable
{
专用只读ILogger\u记录器;
私人定时器;
公共TimedHostedService(ILogger记录器)
{
_记录器=记录器;
}
公共任务StartSync(CancellationToken CancellationToken)
{
_logger.LogInformation(“定时后台服务正在启动”);
_计时器=新计时器(DoWork、null、TimeSpan.Zero、,
时间跨度从秒(5)开始;
返回Task.CompletedTask;
}
私有无效工作(对象状态)
{
_logger.LogInformation(“定时后台服务正在工作。”);
}
公共任务StopAsync(CancellationToken CancellationToken)
{
_logger.LogInformation(“定时后台服务正在停止”);
_计时器?更改(Timeout.Infinite,0);
返回Task.CompletedTask;
}
公共空间处置()
{
_计时器?.Dispose();
}
}

看起来我在启动应用程序时遇到了问题

我的字母C看起来像

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


        }

        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
            .UseSerilog((ctx, config) => { config.ReadFrom.Configuration(ctx.Configuration); })
            .UseStartup<Startup>();
    }
公共类程序
{
公共静态void Main(字符串[]args)
{
CreateWebHostBuilder(args.Build().Run();
}
公共静态IWebHostBuilder CreateWebHostBuilder(字符串[]args)=>
WebHost.CreateDefaultBuilder(args)
.useserlog((ctx,config)=>{config.ReadFrom.Configuration(ctx.Configuration);})
.UseStartup();
}
在第一次用户请求之前,我没有遇到任何断点。 我错过了什么吗?这是VS2017创建的默认.Net核心应用程序

这是我的starup.cs

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

        public IConfiguration Configuration { get; }
        private Models.Configuration.SerialPortConfiguration serialPortConfiguration;

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.Configure<CookiePolicyOptions>(options =>
            {
                // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                options.CheckConsentNeeded = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });

            services.AddDbContext<ApplicationDbContext>(options =>
                options.UseSqlServer(
                    Configuration.GetConnectionString("DefaultConnection")));

            services.AddIdentity<ApplicationUser, ApplicationRole>(options => options.Stores.MaxLengthForKeys = 128)
                .AddDefaultUI(UIFramework.Bootstrap4)
                .AddEntityFrameworkStores<ApplicationDbContext>()
                .AddDefaultTokenProviders();

            services.AddDbContext<Data.Parking.parkingContext>(options =>
                options.UseSqlServer(
                    Configuration.GetConnectionString("DefaultConnection")));


         services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
            services.AddHostedService<Engines.KontolerTimer>();}
公共类启动
{
公共启动(IConfiguration配置)
{
配置=配置;
}
公共IConfiguration配置{get;}
private Models.Configuration.SerialPortConfiguration SerialPortConfiguration;
//此方法由运行时调用。请使用此方法将服务添加到容器中。
public void配置服务(IServiceCollection服务)
{
配置(选项=>
{
//此lambda确定给定请求是否需要非必要cookie的用户同意。
options.checkApprovered=context=>true;
options.MinimumSameSitePolicy=SameSiteMode.None;
});
services.AddDbContext(选项=>
options.UseSqlServer(
GetConnectionString(“DefaultConnection”);
services.AddIdentity(options=>options.Stores.MaxLengthForKeys=128)
.AddDefaultUI(UIFramework.Bootstrap4)
.AddEntityFrameworkStores()
.AddDefaultTokenProviders();
services.AddDbContext(选项=>
options.UseSqlServer(
GetConnectionString(“DefaultConnection”);
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddHostedService();}
主机启动时,托管服务确实会启动。使用WebHost,托管服务将启动。这意味着如果正确实施,您的托管服务将运行,而无需请求


当我在一个新的ASP.NET核心应用程序上尝试您的示例托管服务时,它工作得很好,因此如果它不适合您,那么您的实际实现显然是不正确的。

如果您想让一个服务执行后台任务(类似于旧的Windows服务)我建议您使用:而不是WebHost


WebHost添加了很多您可能不需要的东西,因为这似乎是一项简单的后台工作(假设读取您的代码)。

后台服务在您的应用程序启动时启动,然后由您来同步

您可以通过使用命名空间
Microsoft.Extensions.Hosting
Microsoft.Extensions.Hosting.Abstractions
程序集)中的
BackgroundService
类来实现backhround服务:

首先,声明服务的接口(在本例中是空的,不漂亮,但干净):

然后,声明您的服务。以下代码段声明了一个服务,该服务在启动时持续5秒,然后每2分半执行一个任务:

internal sealed class MyService : BackgroundService, IMyService
{
    private const int InitialDelay = 5 * 1000;  //5 seconds;
    private const int Delay = (5 * 60 * 1000) / 2; // 2.5 minutes

    private readonly ILogger<MyService> m_Logger;

    public MyService(ILogger<MyService> logger, IServiceProvider serviceProvider)
    {
        if (logger == null)
            throw new ArgumentNullException(nameof(logger));
        if (serviceProvider == null)
            throw new ArgumentNullException(nameof(serviceProvider));

        this.m_Logger = logger;
        this.m_ServiceProvider = serviceProvider;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        try
        {
            m_Logger.LogDebug($"MyService is starting.");

            stoppingToken.Register(() => m_Logger.LogDebug($"MyService background task is stopping because cancelled."));

            if (!stoppingToken.IsCancellationRequested)
            {
                m_Logger.LogDebug($"MyService is waiting to be scheduled.");
                await Task.Delay(InitialDelay, stoppingToken);
            }

            m_Logger.LogDebug($"MyService is working.");

            while (!stoppingToken.IsCancellationRequested)
            {
                await DoSomethingAsync();

                await Task.Delay(Delay);
            }

            m_Logger.LogDebug($"MyService background task is stopping.");
        }
        catch (Exception ex)
        {
            m_Logger.LogDebug("MyService encountered a fatal error while w task is stopping: {Exception}.", ex.ToString());
        }
    }

    private async Task DoSomrthingAsync()
    {
         // do something here
         await Task.Delay(1000);
    }

}
这就足以启动服务。请记住,如果您的应用程序托管在IIS中,您的应用程序可能会在以后实际启动:每次回收程序集时,您的应用程序都会(重新)启动。相反,使用Kestrel提供了一个不会回收的单实例应用程序

对于那些使用.Net Core 2.1或更低版本的用户,后台类不可用,但您可以从github获得定义(我将过去使用的内容发布为github存储库可以移动):

//从.NET Core 2.1中借用(我们目前的目标是2.0.3)
//版权(C).NET基金会,在Apache许可下授权,版本2。
/// 
///用于实现长时间运行的基类。
/// 
公共抽象类后台服务:IHostedService,IDisposable
{
私有任务(executingTask);;
私有只读取消令牌源\u停止CTS=
新的CancellationTokenSource();
受保护的抽象任务ExecuteAsync(CancellationToken CancellationToken);
public interface IMyService : IHostedService
{
}
internal sealed class MyService : BackgroundService, IMyService
{
    private const int InitialDelay = 5 * 1000;  //5 seconds;
    private const int Delay = (5 * 60 * 1000) / 2; // 2.5 minutes

    private readonly ILogger<MyService> m_Logger;

    public MyService(ILogger<MyService> logger, IServiceProvider serviceProvider)
    {
        if (logger == null)
            throw new ArgumentNullException(nameof(logger));
        if (serviceProvider == null)
            throw new ArgumentNullException(nameof(serviceProvider));

        this.m_Logger = logger;
        this.m_ServiceProvider = serviceProvider;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        try
        {
            m_Logger.LogDebug($"MyService is starting.");

            stoppingToken.Register(() => m_Logger.LogDebug($"MyService background task is stopping because cancelled."));

            if (!stoppingToken.IsCancellationRequested)
            {
                m_Logger.LogDebug($"MyService is waiting to be scheduled.");
                await Task.Delay(InitialDelay, stoppingToken);
            }

            m_Logger.LogDebug($"MyService is working.");

            while (!stoppingToken.IsCancellationRequested)
            {
                await DoSomethingAsync();

                await Task.Delay(Delay);
            }

            m_Logger.LogDebug($"MyService background task is stopping.");
        }
        catch (Exception ex)
        {
            m_Logger.LogDebug("MyService encountered a fatal error while w task is stopping: {Exception}.", ex.ToString());
        }
    }

    private async Task DoSomrthingAsync()
    {
         // do something here
         await Task.Delay(1000);
    }

}
services.AddSingleton<Microsoft.Extensions.Hosting.IHostedService, MyService>();
//borrowed from .NET Core 2.1 (we are currently targeting 2.0.3)
// Copyright (c) .NET Foundation. Licensed under the Apache License, Version 2.0.
/// <summary>
/// Base class for implementing a long running <see cref="IHostedService"/>.
/// </summary>
public abstract class BackgroundService : IHostedService, IDisposable
{
    private Task _executingTask;

    private readonly CancellationTokenSource _stoppingCts =
                                                   new CancellationTokenSource();

    protected abstract Task ExecuteAsync(CancellationToken cancellationToken);

    public virtual Task StartAsync(CancellationToken cancellationToken)
    {
        // Store the task we're executing
        _executingTask = ExecuteAsync(_stoppingCts.Token);

        // If the task is completed then return it,
        // this will bubble cancellation and failure to the caller
        if (_executingTask.IsCompleted)
        {
            return _executingTask;
        }

        // Otherwise it's running
        return Task.CompletedTask;
    }

    public virtual async Task StopAsync(CancellationToken cancellationToken)
    {
        // Stop called without start
        if (_executingTask == null)
        {
            return;
        }

        try
        {
            // Signal cancellation to the executing method
            _stoppingCts.Cancel();
        }
        finally
        {
            // Wait until the task completes or the stop token triggers
            await Task.WhenAny(_executingTask, Task.Delay(Timeout.Infinite,
                                                          cancellationToken));
        }
    }

    public virtual void Dispose()
    {
        _stoppingCts.Cancel();
    }
}