Reputation: 6353
I'm following the example for queued services on MSDN but I don't know how to get an instance for MonitorLoop
, because host.Services.GetRequiredService
is undefined. How can I retrieve it in ASP.NET Core 6?
Or may a better practice be to use a background scoped service for the MonitorLoop
? https://learn.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();
}
}
This is what my Program.cs looks like
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();
Upvotes: 17
Views: 66766
Reputation: 838
You get the required services from the app
instance,
var app = builder.Build();
var monitorLoop = app.Services.GetRequiredService<MonitorLoop>();
monitorLoop.StartMonitorLoop();
Upvotes: 25
Reputation: 2598
I have a similar situation and this is my exact working implementation:
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>();
}
This also works for web based applications. Here is an example of a Blazor application that uses the same pattern:
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();
Do the following is from a Web Application but uses same concept:
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();
}
...
}
Upvotes: 8