- Add Hangfire packages (AspNetCore, Core, InMemory, SqlServer) with configurable storage (InMemory vs SQL Server) - Configure Hangfire dashboard at /hangfire with AllowAllDashboardAuthorizationFilter (no auth for development) - Add Microsoft.Extensions.Hosting.WindowsServices package with conditional UseWindowsService() based on HostingOptions:UseWindowsService config - Create ProfileManager BackgroundService with IServiceScopeFactory for scoped service resolution per iteration - Create AllowAllDashboardAuthorizationFilter for Hangfire dashboard access - Create DtoExtensions with JobId() and ToJob() helper methods - Configure Serilog with file sink (Production: Logs/log-.txt, daily rolling, 30 day retention) and console sink (Development) - Add Serilog enrichers: FromLogContext, WithMachineName, WithThreadId - Update appsettings.json with Hangfire:InMemory flag, HostingOptions:UseWindowsService flag, and Serilog configuration - Create appsettings.Development.json with console-specific Serilog configuration
112 lines
3.1 KiB
C#
112 lines
3.1 KiB
C#
using ECMJobRunner.Application;
|
|
using ECMJobRunner.Infrastructure;
|
|
using ECMJobRunner.WebCron;
|
|
using Hangfire;
|
|
using Hangfire.SqlServer;
|
|
using Microsoft.Data.SqlClient;
|
|
using Serilog;
|
|
|
|
// Configure Serilog from appsettings.json
|
|
Log.Logger = new LoggerConfiguration()
|
|
.ReadFrom.Configuration(new ConfigurationBuilder()
|
|
.AddJsonFile("appsettings.json")
|
|
.AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"}.json", optional: true)
|
|
.Build())
|
|
.CreateLogger();
|
|
|
|
try
|
|
{
|
|
Log.Information("Starting ECMJobRunner.WebCron application");
|
|
|
|
var builder = WebApplication.CreateBuilder(args);
|
|
|
|
// Use Serilog for logging
|
|
builder.Host.UseSerilog();
|
|
|
|
// Configure Windows Service hosting if enabled
|
|
if (builder.Configuration.GetValue<bool>("HostingOptions:UseWindowsService"))
|
|
{
|
|
builder.Host.UseWindowsService();
|
|
}
|
|
|
|
// Add services to the container.
|
|
builder.Services.AddControllers();
|
|
builder.Services.AddHostedService<ProfileManager>();
|
|
|
|
// Register services
|
|
var cnnStr = builder.Configuration.GetConnectionString("SDD-VMP04-SQL17")
|
|
?? throw new InvalidOperationException("Connection string 'SDD-VMP04-SQL17' not found.");
|
|
builder.Services.AddJobRunnerInfrastructure(cnnStr);
|
|
|
|
var recClientApiUrl = builder.Configuration.GetValue<string>("ReC:ApiUrl")
|
|
?? throw new InvalidOperationException("ReC:ApiUrl not found.");
|
|
builder.Services.AddJobRunnerServices(recClientApiUrl);
|
|
|
|
// Get Hangfire storage configuration
|
|
var useInMemory = builder.Configuration.GetValue<bool>("Hangfire:InMemory");
|
|
|
|
// Add Hangfire services with configurable storage
|
|
builder.Services.AddHangfire(configuration =>
|
|
{
|
|
configuration
|
|
.SetDataCompatibilityLevel(CompatibilityLevel.Version_180)
|
|
.UseSimpleAssemblyNameTypeSerializer()
|
|
.UseRecommendedSerializerSettings();
|
|
|
|
// Configure storage based on appsettings
|
|
if (useInMemory)
|
|
{
|
|
configuration.UseInMemoryStorage();
|
|
}
|
|
else // Use SQL Server storage
|
|
{
|
|
configuration.UseSqlServerStorage(cnnStr, new SqlServerStorageOptions
|
|
{
|
|
CommandBatchMaxTimeout = TimeSpan.FromMinutes(5),
|
|
SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5),
|
|
QueuePollInterval = TimeSpan.Zero,
|
|
UseRecommendedIsolationLevel = true,
|
|
DisableGlobalLocks = true,
|
|
SqlClientFactory = SqlClientFactory.Instance
|
|
});
|
|
}
|
|
});
|
|
|
|
// Add Hangfire server
|
|
builder.Services.AddHangfireServer();
|
|
|
|
builder.Services.AddEndpointsApiExplorer();
|
|
builder.Services.AddSwaggerGen();
|
|
|
|
var app = builder.Build();
|
|
|
|
// Configure the HTTP request pipeline.
|
|
if (app.Environment.IsDevelopment())
|
|
{
|
|
app.UseSwagger();
|
|
app.UseSwaggerUI();
|
|
}
|
|
|
|
app.UseHttpsRedirection();
|
|
|
|
app.UseAuthorization();
|
|
|
|
// Add Hangfire Dashboard with no authentication (for development)
|
|
app.UseHangfireDashboard("/hangfire", new DashboardOptions
|
|
{
|
|
Authorization = new[] { new AllowAllDashboardAuthorizationFilter() }
|
|
});
|
|
|
|
app.MapControllers();
|
|
|
|
app.Run();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.Fatal(ex, "Application terminated unexpectedly");
|
|
}
|
|
finally
|
|
{
|
|
Log.CloseAndFlush();
|
|
}
|