将 ASPNET API 添加到现有的 Worker Service 项目

Adding an ASPNET API to an existing Worker Service project

我目前有一个 dotnet 5.0 Worker Service 项目,该项目托管一个后台服务,该服务定期执行业务流程。我已经设法通过在 CreateHostBuilder 方法中设置主机来摸索,这一切都很好 运行 作为 docker 容器中的可执行文件。

但是,我现在想添加一个 HTTP api / ui,这样我就可以公开一个“健康”端点和一些漂亮的网页,这些网页可以访问相同的进程内内存后台服务执行诸如显示内存中缓存的内容、逐出缓存条目、手动触发业务流程的 运行 等操作,我完全迷路了。

我想我只是以某种方式在 ConfigureServices 方法中配置了一个额外的托管服务,该方法绑定到我指定端口上的 ASPNET razor 项目中定义的 class,但经过几次尝试后我我对如何开始解决这个问题有点困惑,更不用说让它真正起作用了:-(。

具体来说,我有一个如下所示的 C# 项目:

MyWorker.csproj

<Project Sdk="Microsoft.NET.Sdk.Worker">

  <PropertyGroup>
    <TargetFramework>net5.0</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="5.0.0" />
    <PackageReference Include="Microsoft.Extensions.Hosting" Version="5.0.0" />
    <PackageReference Include="Serilog.Extensions.Hosting" Version="4.0.0-dev-00051" />
    <PackageReference Include="Serilog.Formatting.Compact" Version="1.1.1-dev-00940" />
    <PackageReference Include="Serilog.Sinks.Console" Version="4.0.0-dev-00839" />
  </ItemGroup>

  <ItemGroup>
    <ProjectReference Include="..\MyAppCode\MyAppCode.csproj" />
  </ItemGroup>

</Project>

和一个看起来像这样的 Program.cs

        public static void Main(string[] args)
        {

            Program.InitSerilog();
            Program.CreateHostBuilder(args).Build().Run();

        }

        public static void InitSerilog()
        {
            ... do stuff ...
        }

        public static IHostBuilder CreateHostBuilder(string[] args)
        {
            return new HostBuilder()
                // worker service config
                .ConfigureLogging((context, builder) =>
                {
                    builder.SetMinimumLevel(LogLevel.Trace);
                })
                .ConfigureServices(services =>
                {
                    services.AddHostedService<MyAppService>();
                    services.AddSingleton<AppSettings>(
                        serviceProvider => { return Program.CreateAppSettings(); }
                    );
                })
                .UseSerilog();
        }

        private static AppSettings CreateAppSettings()
        {
            ... bind to environment variables and return ...
        }

    }

最后,我现有的后台服务是这样的:

    public sealed class MyAppService: BackgroundService
    {

        public MyAppService(ILogger<MyAppService> logger, AppSettings appSettings)
            : base()
        {
            ... do stuff ...
        }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            ... keep doing the main business process in a timed loop ...
        }

        #endregion
    }

我找到了很多关于如何将辅助服务添加到现有 ASPNET 项目或如何将 ASPNET 项目作为 Windows 服务托管的示例,但没有关于如何添加 ASPNET 的示例现有工作人员服务的站点侦听器。

喜欢 能够做的是在新的 C# 中构建 ui 网络 ui / api项目并以某种方式将它连接到现有的 Program.cs,以便它在主 BackgroundService 处于 运行ning 时侦听指定端口,但也许我只是在处理这一切错误?

注意 - 我可能在修补时取消了 CreateHostBuilder 方法中一些默认的“正常工作”魔法,所以请随时告诉我将其恢复为默认设置(如果这很容易)答案:-).

感谢任何帮助/指点...

首先,我建议你把你的 <Project Sdk="Microsoft.NET.Sdk.Worker"> 变成 <Project Sdk="Microsoft.NET.Sdk.Web">

然后,将您的 CreateHostBuilder 更改为使用 Startup class:

public static IHostBuilder CreateHostBuilder(string[] args)
{
    return new HostBuilder()
        .ConfigureLogging((context, builder) =>
        {
            builder.SetMinimumLevel(LogLevel.Trace);
        })
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.UseStartup<Startup>();
        })
        .UseSerilog();
}

并且在您的 Startup 中,您可以处理后台和其他服务的配置:

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }
    
    public IConfiguration Configuration { get; }
    
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddHttpContextAccessor();
        services.AddAuthorization();

        // worker service config
        services.AddHostedService<MyAppService>();
        services.AddSingleton<AppSettings>(
            serviceProvider => { return Program.CreateAppSettings(); } // this method could be relocated too
        );

        // example for health checks
        services.AddHealthChecks();
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        
        app.UseRouting();
        app.UseAuthorization();
        app.UseEndpoints(endpoints =>
        {
            // example for health checks
            endpoints.MapHealthChecks("/health", new HealthCheckOptions
            {
                Predicate = _ => true,
                ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
            });
        });
    }
}