262 lines
8.3 KiB
C#
262 lines
8.3 KiB
C#
using Microsoft.AspNetCore.Mvc;
|
||
using Microsoft.AspNetCore.Server.Kestrel.Core;
|
||
using MongoDB.Driver;
|
||
using OnlyOneAccessTemplate.Services;
|
||
|
||
var builder = WebApplication.CreateBuilder(args);
|
||
|
||
// Configurações otimizadas para produção ARM64
|
||
if (builder.Environment.IsProduction())
|
||
{
|
||
// Configurar Kestrel para melhor performance
|
||
builder.WebHost.ConfigureKestrel(options =>
|
||
{
|
||
options.Limits.MaxConcurrentConnections = 100;
|
||
options.Limits.MaxConcurrentUpgradedConnections = 100;
|
||
options.Limits.MaxRequestBodySize = 10 * 1024 * 1024; // 10MB
|
||
options.Limits.MinRequestBodyDataRate = new MinDataRate(bytesPerSecond: 100, gracePeriod: TimeSpan.FromSeconds(10));
|
||
options.Limits.MinResponseDataRate = new MinDataRate(bytesPerSecond: 100, gracePeriod: TimeSpan.FromSeconds(10));
|
||
options.AddServerHeader = false;
|
||
});
|
||
|
||
// Configurações de logging otimizadas
|
||
builder.Logging.ClearProviders();
|
||
builder.Logging.AddConsole();
|
||
builder.Logging.SetMinimumLevel(LogLevel.Warning);
|
||
}
|
||
|
||
// Add services to the container.
|
||
builder.Services.AddControllersWithViews(options =>
|
||
{
|
||
if (builder.Environment.IsProduction())
|
||
{
|
||
// Configurações de cache para produção
|
||
options.CacheProfiles.Add("Default", new CacheProfile()
|
||
{
|
||
Duration = 300 // 5 minutos
|
||
});
|
||
}
|
||
});
|
||
|
||
// Configurar Response Caching
|
||
builder.Services.AddResponseCaching(options =>
|
||
{
|
||
options.MaximumBodySize = 1024 * 1024; // 1MB
|
||
options.UseCaseSensitivePaths = false;
|
||
});
|
||
|
||
// Configurar Response Compression
|
||
builder.Services.AddResponseCompression(options =>
|
||
{
|
||
options.EnableForHttps = true;
|
||
});
|
||
|
||
// Add services to the container
|
||
builder.Services.AddControllersWithViews();
|
||
|
||
// Session support
|
||
builder.Services.AddDistributedMemoryCache();
|
||
builder.Services.AddSession(options =>
|
||
{
|
||
options.IdleTimeout = TimeSpan.FromMinutes(30);
|
||
options.Cookie.HttpOnly = true;
|
||
options.Cookie.IsEssential = true;
|
||
});
|
||
|
||
// MongoDB Configuration
|
||
builder.Services.AddSingleton<IMongoClient>(sp =>
|
||
{
|
||
var connectionString = builder.Configuration.GetConnectionString("MongoDB");
|
||
return new MongoClient(connectionString);
|
||
});
|
||
|
||
|
||
// Rate Limiting Service
|
||
builder.Services.AddScoped<IRateLimitService, RateLimitService>();
|
||
|
||
// Configuration Service (para substituir o ISiteConfigurationService se necessário)
|
||
builder.Services.AddScoped<IConfigurationService, ConfigurationService>();
|
||
|
||
// Configuração de localização para SEO multi-idioma
|
||
builder.Services.Configure<RequestLocalizationOptions>(options =>
|
||
{
|
||
var supportedCultures = new[] { "pt-BR", "en-US", "es-ES" };
|
||
options.SetDefaultCulture(supportedCultures[0])
|
||
.AddSupportedCultures(supportedCultures)
|
||
.AddSupportedUICultures(supportedCultures);
|
||
});
|
||
|
||
builder.Services.AddScoped(sp =>
|
||
{
|
||
var client = sp.GetRequiredService<IMongoClient>();
|
||
var databaseName = builder.Configuration.GetValue<string>("MongoDB:DatabaseName");
|
||
return client.GetDatabase(databaseName);
|
||
});
|
||
|
||
// Custom Services
|
||
builder.Services.AddScoped<ISiteConfigurationService, SiteConfigurationService>();
|
||
builder.Services.AddScoped<ILanguageService, LanguageService>();
|
||
builder.Services.AddScoped<ISeoService, SeoService>();
|
||
builder.Services.AddScoped<IConversionService, ConversionService>();
|
||
|
||
// Converter Services - Registrar todos os conversores dispon<6F>veis
|
||
builder.Services.AddScoped<TextCaseConverterService>();
|
||
builder.Services.AddScoped<CsvToJsonConverterService>();
|
||
builder.Services.AddScoped<ImageToTextConverterService>();
|
||
|
||
// Substituindo UpperLowerConversorService por API com Polly
|
||
builder.Services.AddHttpClient<ITextConversionApiService, TextConversionApiService>();
|
||
builder.Services.AddScoped<ApiBasedSentenceConverterService>();
|
||
|
||
// HttpClient for external calls
|
||
builder.Services.AddHttpClient<ConversionService>();
|
||
builder.Services.AddHttpClient<ImageToTextConverterService>();
|
||
|
||
// Response Compression
|
||
builder.Services.AddResponseCompression(options =>
|
||
{
|
||
options.EnableForHttps = true;
|
||
});
|
||
|
||
// Response Caching
|
||
builder.Services.AddResponseCaching();
|
||
|
||
// Memory Cache
|
||
builder.Services.AddMemoryCache();
|
||
|
||
// Loggingbuilder.Logging.ClearProviders();
|
||
builder.Logging.AddConsole();
|
||
builder.Logging.AddDebug();
|
||
|
||
var app = builder.Build();
|
||
|
||
// Configure the HTTP request pipeline
|
||
if (!app.Environment.IsDevelopment())
|
||
{
|
||
app.UseExceptionHandler("/Home/Error");
|
||
app.UseHsts();
|
||
}
|
||
|
||
app.UseHttpsRedirection();
|
||
app.UseStaticFiles(new StaticFileOptions
|
||
{
|
||
OnPrepareResponse = ctx =>
|
||
{
|
||
// Cache estático por 1 hora
|
||
ctx.Context.Response.Headers.Append("Cache-Control", "public,max-age=3600");
|
||
}
|
||
});
|
||
|
||
// Session
|
||
app.UseSession();
|
||
|
||
// Response Compression & Caching
|
||
app.UseResponseCompression();
|
||
app.UseResponseCaching();
|
||
|
||
app.UseRequestLocalization();
|
||
|
||
// Middleware para detectar configuração por domínio
|
||
app.Use(async (context, next) =>
|
||
{
|
||
var host = context.Request.Host.Host;
|
||
var configService = context.RequestServices.GetRequiredService<IConfigurationService>();
|
||
var config = await configService.GetConfigurationAsync(host);
|
||
context.Items["SiteConfig"] = config;
|
||
|
||
// Se não encontrou config por domínio, usar fallback baseado no idioma da URL
|
||
if (config == null)
|
||
{
|
||
var pathSegments = context.Request.Path.Value?.Split('/', StringSplitOptions.RemoveEmptyEntries);
|
||
var language = "pt"; // default
|
||
|
||
if (pathSegments?.Length > 0 && new[] { "en", "es", "pt" }.Contains(pathSegments[0]))
|
||
{
|
||
language = pathSegments[0];
|
||
}
|
||
|
||
// Usar seu serviço existente como fallback
|
||
var siteConfigService = context.RequestServices.GetRequiredService<ISiteConfigurationService>();
|
||
var fallbackConfig = await siteConfigService.GetConfigurationAsync(language);
|
||
context.Items["SiteConfig"] = fallbackConfig;
|
||
}
|
||
|
||
await next();
|
||
});
|
||
|
||
|
||
app.UseRouting();
|
||
|
||
// Custom routing for multilingual support
|
||
app.MapControllerRoute(
|
||
name: "converter-api",
|
||
pattern: "converter/api/{action}/{converterType?}",
|
||
defaults: new { controller = "Converter" });
|
||
|
||
app.MapControllerRoute(
|
||
name: "converter-config",
|
||
pattern: "converter/config/{converterType}",
|
||
defaults: new { controller = "Converter", action = "GetConverterConfig" });
|
||
|
||
// Rotas específicas por idioma
|
||
app.MapControllerRoute(
|
||
name: "converter_localized_specific",
|
||
pattern: "{language:regex(^(pt|en|es)$)}/{converter}",
|
||
defaults: new { controller = "Converter", action = "Index" });
|
||
|
||
// Rota para home localizada
|
||
app.MapControllerRoute(
|
||
name: "home_localized",
|
||
pattern: "{language:regex(^(pt|en|es)$)}",
|
||
defaults: new { controller = "Home", action = "Index" });
|
||
|
||
// Manter suas rotas de API existentes (não mexer)
|
||
// Rota padrão para português (fallback)
|
||
app.MapControllerRoute(
|
||
name: "default",
|
||
pattern: "{controller=Home}/{action=Index}/{id?}");
|
||
|
||
// SEO Routes
|
||
app.MapGet("/sitemap.xml", async (ISiteConfigurationService siteConfig) =>
|
||
{
|
||
var sitemap = await siteConfig.GenerateSitemapAsync();
|
||
return Results.Content(sitemap, "application/xml");
|
||
});
|
||
|
||
app.MapGet("/robots.txt", async (ISiteConfigurationService siteConfig) =>
|
||
{
|
||
var robots = await siteConfig.GenerateRobotsAsync();
|
||
return Results.Content(robots, "text/plain");
|
||
});
|
||
|
||
// Health check endpoint
|
||
app.MapGet("/health", () => Results.Ok(new { status = "healthy", timestamp = DateTime.UtcNow }));
|
||
|
||
// Initialize default data on startup (only in development)
|
||
if (app.Environment.IsDevelopment())
|
||
{
|
||
using var scope = app.Services.CreateScope();
|
||
var siteConfigService = scope.ServiceProvider.GetRequiredService<ISiteConfigurationService>();
|
||
var logger = scope.ServiceProvider.GetRequiredService<ILogger<Program>>();
|
||
|
||
try
|
||
{
|
||
// Verificar se j<> existem configura<72><61>es
|
||
var languages = new[] { "pt", "en", "es" };
|
||
foreach (var lang in languages)
|
||
{
|
||
var configExists = await siteConfigService.ConfigurationExistsAsync(lang);
|
||
if (!configExists)
|
||
{
|
||
logger.LogInformation("Criando configura<72><61>o padr<64>o para idioma: {Language}", lang);
|
||
_ = await siteConfigService.GetConfigurationAsync(lang); // Isso criar<61> a configura<72><61>o padr<64>o
|
||
}
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
logger.LogError(ex, "Erro ao inicializar dados padr<64>o");
|
||
}
|
||
}
|
||
|
||
app.Run(); |