QrRapido/Program.cs
2025-07-28 18:22:47 -03:00

252 lines
7.5 KiB
C#

using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.Google;
using Microsoft.AspNetCore.Authentication.MicrosoftAccount;
using Microsoft.AspNetCore.Localization;
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Localization;
using MongoDB.Driver;
using QRRapidoApp.Data;
using QRRapidoApp.Middleware;
using QRRapidoApp.Services;
using QRRapidoApp.Services.Monitoring;
using QRRapidoApp.Services.HealthChecks;
using StackExchange.Redis;
using Stripe;
using System.Globalization;
using Serilog;
using Serilog.Events;
using Serilog.Sinks.SystemConsole.Themes;
var builder = WebApplication.CreateBuilder(args);
// Configure Serilog
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(builder.Configuration)
.Enrich.FromLogContext()
.Enrich.WithEnvironmentName()
.Enrich.WithProcessId()
.Enrich.WithThreadId()
.Enrich.WithProperty("ApplicationName", builder.Configuration["ApplicationName"] ?? "QRRapido")
.WriteTo.Async(a => a.Console(
outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj} {Properties:j}{NewLine}{Exception}",
theme: AnsiConsoleTheme.Code))
.WriteTo.Async(a => {
var seqUrl = builder.Configuration["Serilog:SeqUrl"];
var apiKey = builder.Configuration["Serilog:ApiKey"];
if (!string.IsNullOrEmpty(seqUrl))
{
try
{
// Temporarily skip Seq until packages are installed
Console.WriteLine($"Seq configured for: {seqUrl}");
}
catch (Exception ex)
{
Console.WriteLine($"Failed to configure Seq sink: {ex.Message}");
// Continue without Seq - will still log to console
}
}
})
.CreateLogger();
builder.Host.UseSerilog();
// Add services to the container
builder.Services.AddControllersWithViews();
// Add HttpClient for health checks
builder.Services.AddHttpClient();
// MongoDB Configuration - optional for development
var mongoConnectionString = builder.Configuration.GetConnectionString("MongoDB");
if (!string.IsNullOrEmpty(mongoConnectionString))
{
try
{
builder.Services.AddSingleton<IMongoClient>(serviceProvider =>
{
return new MongoClient(mongoConnectionString);
});
builder.Services.AddScoped<MongoDbContext>();
}
catch
{
// MongoDB not available - services will handle gracefully
builder.Services.AddScoped<MongoDbContext>();
}
}
else
{
// Development mode without MongoDB
builder.Services.AddScoped<MongoDbContext>();
}
// Cache Configuration - use Redis if available, otherwise memory cache
var redisConnectionString = builder.Configuration.GetConnectionString("Redis");
if (!string.IsNullOrEmpty(redisConnectionString))
{
try
{
builder.Services.AddStackExchangeRedisCache(options =>
{
options.Configuration = redisConnectionString;
});
}
catch
{
// Fallback to memory cache if Redis fails
builder.Services.AddMemoryCache();
builder.Services.AddSingleton<IDistributedCache, QRRapidoApp.Services.MemoryDistributedCacheWrapper>();
}
}
else
{
// Use memory cache when Redis is not configured
builder.Services.AddMemoryCache();
builder.Services.AddSingleton<IDistributedCache, MemoryDistributedCacheWrapper>();
}
// Authentication Configuration
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(options =>
{
options.LoginPath = "/Account/Login";
options.LogoutPath = "/Account/Logout";
options.ExpireTimeSpan = TimeSpan.FromDays(30);
options.SlidingExpiration = true;
})
.AddGoogle(GoogleDefaults.AuthenticationScheme, options =>
{
options.ClientId = builder.Configuration["Authentication:Google:ClientId"];
options.ClientSecret = builder.Configuration["Authentication:Google:ClientSecret"];
})
.AddMicrosoftAccount(MicrosoftAccountDefaults.AuthenticationScheme, options =>
{
options.ClientId = builder.Configuration["Authentication:Microsoft:ClientId"];
options.ClientSecret = builder.Configuration["Authentication:Microsoft:ClientSecret"];
});
// Stripe Configuration
StripeConfiguration.ApiKey = builder.Configuration["Stripe:SecretKey"];
// Localization
builder.Services.AddLocalization(options => options.ResourcesPath = "Resources");
builder.Services.Configure<RequestLocalizationOptions>(options =>
{
var supportedCultures = new[]
{
new CultureInfo("pt-BR"),
new CultureInfo("es"),
new CultureInfo("en")
};
options.DefaultRequestCulture = new RequestCulture("pt-BR");
options.SupportedCultures = supportedCultures;
options.SupportedUICultures = supportedCultures;
options.RequestCultureProviders.Insert(0, new QueryStringRequestCultureProvider());
options.RequestCultureProviders.Insert(1, new CookieRequestCultureProvider());
});
// Custom Services
builder.Services.AddScoped<IQRCodeService, QRRapidoService>();
builder.Services.AddScoped<IUserService, UserService>();
builder.Services.AddScoped<AdDisplayService>();
builder.Services.AddScoped<StripeService>();
// Background Services
builder.Services.AddHostedService<HistoryCleanupService>();
// Monitoring Services
if (builder.Configuration.GetValue<bool>("ResourceMonitoring:Enabled", true))
{
builder.Services.AddHostedService<ResourceMonitoringService>();
}
if (builder.Configuration.GetValue<bool>("MongoDbMonitoring:Enabled", true))
{
builder.Services.AddHostedService<MongoDbMonitoringService>();
}
// CORS for API endpoints
builder.Services.AddCors(options =>
{
options.AddPolicy("AllowSpecificOrigins", policy =>
{
policy.WithOrigins("https://qrrapido.site", "https://www.qrrapido.site")
.AllowAnyHeader()
.AllowAnyMethod();
});
});
// Health checks with custom implementations
builder.Services.AddScoped<MongoDbHealthCheck>();
builder.Services.AddScoped<SeqHealthCheck>();
builder.Services.AddScoped<ResourceHealthCheck>();
builder.Services.AddScoped<ExternalServicesHealthCheck>();
builder.Services.AddHealthChecks()
.AddCheck<MongoDbHealthCheck>("mongodb")
.AddCheck<SeqHealthCheck>("seq")
.AddCheck<ResourceHealthCheck>("resources")
.AddCheck<ExternalServicesHealthCheck>("external_services");
var app = builder.Build();
// Configure the HTTP request pipeline
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors("AllowSpecificOrigins");
// Localization middleware
app.UseRequestLocalization();
app.UseAuthentication();
app.UseAuthorization();
// Custom middleware
app.UseMiddleware<LastLoginUpdateMiddleware>();
// Health check endpoint
app.MapHealthChecks("/health");
// Controller routes
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
// API routes
app.MapControllerRoute(
name: "api",
pattern: "api/{controller}/{action=Index}/{id?}");
// Language routes
app.MapControllerRoute(
name: "localized",
pattern: "{culture:regex(^(pt-BR|es|en)$)}/{controller=Home}/{action=Index}/{id?}");
try
{
Log.Information("Starting QRRapido application");
app.Run();
}
catch (Exception ex)
{
Log.Fatal(ex, "QRRapido application terminated unexpectedly");
}
finally
{
Log.CloseAndFlush();
}