【问题标题】:.NET Core 2.0 IServiceCollection missing AddHostedService?.NET Core 2.0 IServiceCollection 缺少 AddHostedService?
【发布时间】:2018-09-07 20:21:59
【问题描述】:

尝试使用:

Startup.cs

public void ConfigureServices(IServiceCollection services) {
  services.AddHostedService<LifetimeEvents>();
    .
    .
    .
}

LifeTimeEvents 类从 IHostedService 继承。我收到此错误:

'IServiceCollection' does not contain a definition for 'AddHostedService' and no extension method 'AddHostedService' accepting a first argument of type 'IServiceCollection' could be found (are you missing a using directive or an assembly reference?)

我似乎找不到要使用的正确命名空间或要包含的 nuget 包以使其正常工作,但它在 .NET Core 2.1 中开箱即用,这在 .NET Core 2.0 中是否不可用?有什么办法让它工作吗?

更新:

作为一种解决方法,我更改了代码以使用:

Startup.cs

public void ConfigureServices(IServiceCollection services) {
  services.AddSingleton<LifetimeEvents>();
    .
    .
    .
}

public void Configure(IApplicationBuilder appBuilder, IHostingEnvironment envHost, LifetimeEvents appEvents)  {
  appEvents.StartAsync(new CancellationToken(false));
    .
    .
    .
}

这似乎已经完成了工作。没有回答我最初的问题,我不确定它是怎样的“最佳实践”,但它确实让我开始重构这个 .NET Core 2.0 应用程序。

【问题讨论】:

    标签: c# asp.net-core-2.0


    【解决方案1】:

    这只是在 .NET Core 2.0 中不可用吗?

    ServiceCollectionHostedServiceExtensions.AddHostedService(IServiceCollection) Method如API参考中所示

    适用于
    ASP.NET 核心
    2.1

    但源代码可在 GitHub 上找到。您可以轻松地在那里查看并将本地版本复制到您的 2.0 项目中

    namespace Microsoft.Extensions.DependencyInjection
    {
        public static class ServiceCollectionHostedServiceExtensions
        {
            /// <summary>
            /// Add an <see cref="IHostedService"/> registration for the given type.
            /// </summary>
            /// <typeparam name="THostedService">An <see cref="IHostedService"/> to register.</typeparam>
            /// <param name="services">The <see cref="IServiceCollection"/> to register with.</param>
            /// <returns>The original <see cref="IServiceCollection"/>.</returns>
            public static IServiceCollection AddHostedService<THostedService>(this IServiceCollection services)
                where THostedService : class, IHostedService
                => services.AddTransient<IHostedService, THostedService>();
        }
    }
    

    Source code

    理想情况下,您可以将项目更新到 2.1,以便扩展可用。

    【讨论】:

      【解决方案2】:

      我相信这是我之前回答的重复问题。

      Where am I supposed to start persistent background tasks in ASP.NET Core?

      下面是答案,复制+粘贴。

      我相信你正在寻找这个

      https://blogs.msdn.microsoft.com/cesardelatorre/2017/11/18/implementing-background-tasks-in-microservices-with-ihostedservice-and-the-backgroundservice-class-net-core-2-x/

      我对自己进行了 2 小时自称获奖的黑客马拉松,以了解这一点。

      https://github.com/nixxholas/nautilus

      您可以在此处参考注入并从那里实现摘要。

      许多 MVC 项目并不真正需要操作持久的后台任务。这就是为什么您看不到它们通过模板融入新项目的原因。最好为开发者提供一个界面,让他们可以点击并继续使用它。

      此外,关于为此类后台任务打开该套接字连接,我还没有为此建立解决方案。据我所知/所做的,我只能将有效负载广播到连接到我自己的 socketmanager 的客户端,所以你必须在别处寻找。如果 IHostedService 中有任何关于 websockets 的信息,我肯定会发出哔哔声。

      好吧,这就是发生的事情。

      把它放在你的项目中,它更像是一个让你重载以创建自己的任务的界面

      /// 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
          {
              protected readonly IServiceScopeFactory _scopeFactory;
              private Task _executingTask;
              private readonly CancellationTokenSource _stoppingCts =
                                                             new CancellationTokenSource();
      
              public BackgroundService(IServiceScopeFactory scopeFactory) {
                  _scopeFactory = scopeFactory;
              }
      
              protected abstract Task ExecuteAsync(CancellationToken stoppingToken);
      
              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();
              }
          }
      

      这是你如何实际使用它的方法

      public class IncomingEthTxService : BackgroundService
          {
              public IncomingEthTxService(IServiceScopeFactory scopeFactory) : base(scopeFactory)
              {
              }
      
              protected override async Task ExecuteAsync(CancellationToken stoppingToken)
              {
      
                  while (!stoppingToken.IsCancellationRequested)
                  {
                      using (var scope = _scopeFactory.CreateScope())
                      {
                          var dbContext = scope.ServiceProvider.GetRequiredService<NautilusDbContext>();
      
                          Console.WriteLine("[IncomingEthTxService] Service is Running");
      
                          // Run something
      
                          await Task.Delay(5, stoppingToken);
                      }
                  }
              }
          }
      

      如果你注意到了,那里有一个奖励。您必须使用服务范围才能访问数据库操作,因为它是单例的。

      注入你的服务

      // Background Service Dependencies
                  services.AddSingleton<IHostedService, IncomingEthTxService>();
      

      【讨论】:

        猜你喜欢
        • 2018-01-24
        • 1970-01-01
        • 2018-01-28
        • 2018-05-02
        • 1970-01-01
        • 1970-01-01
        • 2017-05-26
        • 2018-12-22
        • 1970-01-01
        相关资源
        最近更新 更多