ASP.NET 核心 6 - 我如何获得所需的服务

ASP.NET Core 6 - How do I get required service

我正在按照 MSDN 上排队服务的示例进行操作,但我不知道如何为 MonitorLoop 获取实例,因为 host.Services.GetRequiredService 未定义。如何在 ASP.NET Core 6 中检索它?

或者更好的做法是为 MonitorLoop 使用后台范围的服务? https://docs.microsoft.com/en-us/dotnet/core/extensions/scoped-service

public static class QueueServiceExtensions
{
    public static void AddQueueService(this IServiceCollection services, IConfiguration configuration)
    {
        services.AddSingleton<MonitorLoop>();
        services.AddHostedService<QueuedHostedService>();
        services.AddSingleton<IBackgroundTaskQueue>(_ =>
        {
            if (!int.TryParse(configuration["QueueCapacity"], out var queueCapacity))
            {
                queueCapacity = 100;
            }

            return new DefaultBackgroundTaskQueue(queueCapacity);
        });
        
        // TODO: host.Services is undefined
        MonitorLoop monitorLoop = host.Services.GetRequiredService<MonitorLoop>()!;
        monitorLoop.StartMonitorLoop();
    }
}

这就是我的 Program.cs 的样子

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Identity.Web;
using QSGEngine.Web.QueueService;
using QSGEngine.Web.SignalR;
using Serilog;

var builder = WebApplication.CreateBuilder(args);

// Logging
builder.Host.UseSerilog((context, configuration) =>
{
    configuration
        .ReadFrom.Configuration(context.Configuration)
        .Enrich.FromLogContext()
        .Enrich.WithMachineName()
        .Enrich.WithProperty("Environment", Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT"))
        .WriteTo.Console(
#if DEBUG
            restrictedToMinimumLevel: Serilog.Events.LogEventLevel.Verbose,
#else
            restrictedToMinimumLevel: Serilog.Events.LogEventLevel.Information,
#endif
            outputTemplate: builder.Configuration["Serilog:OutputTemplateConsole"]
        )
        .WriteTo.File(
            path: builder.Configuration["Serilog:LogFileLocation"], retainedFileCountLimit: 7, rollingInterval: RollingInterval.Day, buffered: false,
            outputTemplate: builder.Configuration["Serilog:OutputTemplateFile"]
        );
});

// CORS
builder.Services.AddCors(options =>
{
    options.AddPolicy("CorsPolicy", configurePolicy => configurePolicy
        .WithOrigins(builder.Configuration["Configuration:FrontEndUrl"])
        .AllowAnyMethod()
        .AllowAnyHeader()
        .AllowCredentials());
});

// Authentication & Authorization
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"));

// Services
//builder.Services.AddHostedService<PortfolioService>();
builder.Services.AddQueueService(builder.Configuration);

builder.Services.AddControllers();

// Swagger
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

// SignalR
//builder.Services.AddSignalR();
builder.Services.AddPortfolioSignalRService();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    // Swagger
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();

// CORS
app.UseCors("CorsPolicy");

// Web Sockets
var webSocketOptions = new WebSocketOptions()
{
    KeepAliveInterval = TimeSpan.FromSeconds(120)
};
app.UseWebSockets(webSocketOptions);

// Authentication & Authorization
app.UseAuthentication();
app.UseAuthorization();

app.MapControllers();

// SignalR
//app.MapHub<PortfolioHub>("/portfolios");
app.MapPortfolioSignalR();

app.Run();

我有类似的情况,这是我的具体工作实施:

    private static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);

        // I Create a new Service Colleciton
        var services = new ServiceCollection();
        
        // I Configure my services
        services.ConfigureServices();
        
        // I build a new service provider from the services collection
        using (ServiceProvider serviceProvider = services.BuildServiceProvider())
        {
            // Review the FormMain Singleton.
            var formMain = serviceProvider.GetRequiredService<FormMain>();
            Application.Run(formMain);
        }
    }

    private static void ConfigureServices(this IServiceCollection services)
    {
        services.AddSingleton<FormMain>();
        ...
        services.AddSingleton<MonitorService>();
    }

这也适用于基于网络的应用程序。以下是使用相同模式的 Blazor 应用程序示例:

Program.cs

    public static void Main(string[] args)
    {
        var logger = NLogBuilder.ConfigureNLog("nlog.config").GetCurrentClassLogger();
        logger.Debug($"Application Started {DateTime.Now}");

        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder
                .UseStartup<Startup>()
                .ConfigureLogging(logging =>
                {
                    logging.ClearProviders();
                    logging.SetMinimumLevel(LogLevel.Trace);
                })
                .UseNLog();
            }).UseWindowsService();

执行以下来自 Web 应用程序但使用相同概念的操作:

    public void ConfigureServices(IServiceCollection services)
    {
        ...
        services.AddScopred<ILoginService, LoginService>();
        
        using (ServiceProvider serviceProvider = services.BuildServiceProvider())
        {
            var loginService = serviceProvider.GetRequiredService<LoginService>();
            var task = loginService.LoginAsync("Test", "Test");

            var result = task.GetAwaiter().GetResult();
        }
        ...
    }