using CMSMicroservice.Infrastructure.Persistence; using CMSMicroservice.Infrastructure.Data.Seeding; using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Logging; using Serilog.Core; using Serilog; using System.Reflection; using Microsoft.OpenApi.Models; using CMSMicroservice.WebApi.Common.Behaviours; using Hangfire; using Hangfire.SqlServer; var builder = WebApplication.CreateBuilder(args); var levelSwitch = new LoggingLevelSwitch(); var logger = new LoggerConfiguration() //.WriteTo.Console() //.WriteTo.MSSqlServer(builder.Configuration.GetConnectionString("LogConnection"), // sinkOptions: new MSSqlServerSinkOptions // { // TableName = "LogCMSEvents", // SchemaName = "Log", // AutoCreateSqlTable = true // }) .WriteTo.Seq("https://seq.afrino.co", apiKey: "oxpvpUzU1pZxMS4s3Fqq", controlLevelSwitch: levelSwitch) .CreateLogger(); builder.Logging.AddSerilog(logger); #if DEBUG Serilog.Debugging.SelfLog.Enable(msg => Console.WriteLine(msg)); #endif // Additional configuration is required to successfully run gRPC on macOS. // For instructions on how to configure Kestrel and gRPC clients on macOS, visit https://go.microsoft.com/fwlink/?linkid=2099682 // Add services to the container. builder.Services.AddGrpc(options => { options.Interceptors.Add(); options.Interceptors.Add(); //options.Interceptors.Add(); options.EnableDetailedErrors = true; options.MaxReceiveMessageSize = 1000 * 1024 * 1024; // 1 GB options.MaxSendMessageSize = 1000 * 1024 * 1024; // 1 GB }).AddJsonTranscoding(); builder.Services.AddApplicationServices(); builder.Services.AddInfrastructureServices(builder.Configuration); builder.Services.AddPresentationServices(builder.Configuration); builder.Services.AddProtobufServices(); #region Configure Hangfire builder.Services.AddHangfire(config => config .SetDataCompatibilityLevel(CompatibilityLevel.Version_180) .UseSimpleAssemblyNameTypeSerializer() .UseRecommendedSerializerSettings() .UseSqlServerStorage(builder.Configuration["ConnectionStrings:DefaultConnection"])); builder.Services.AddHangfireServer(); #endregion #region Configure Health Checks builder.Services.AddHealthChecks() .AddDbContextCheck("database"); #endregion // Add Controllers for REST APIs builder.Services.AddControllers(); #region Configure Cors builder.Services.AddCors(options => { options.AddPolicy("AllowAll", builder => builder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader().WithExposedHeaders("Grpc-Status", "Grpc-Message", "Grpc-Encoding", "Grpc-Accept-Encoding", "validation-errors-text")); }); #endregion builder.Services.AddGrpcSwagger(); builder.Services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo { Title = "gRPC transcoding", Version = "v1" }); c.CustomSchemaIds(type=>type.ToString()); c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme { In = ParameterLocation.Header, Description = "Please insert JWT with Bearer into field", Name = "Authorization", Type = SecuritySchemeType.ApiKey }); c.AddSecurityRequirement(new OpenApiSecurityRequirement { { new OpenApiSecurityScheme { Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" } }, new string[] { } } }); }); var app = builder.Build(); // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { app.UseDeveloperExceptionPage(); app.UseMigrationsEndPoint(); // Initialise and seed database using (var scope = app.Services.CreateScope()) { var initialiser = scope.ServiceProvider.GetRequiredService(); await initialiser.InitialiseAsync(); await initialiser.SeedAsync(); // Run Migration: ParentId → NetworkParentId (فقط یکبار اجرا می‌شود) var migrationLogger = scope.ServiceProvider.GetRequiredService>(); var dbContext = scope.ServiceProvider.GetRequiredService(); var migrationSeeder = new NetworkParentIdMigrationSeeder(dbContext, migrationLogger); await migrationSeeder.SeedAsync(); } } else { // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. app.UseHsts(); } app.UseRouting(); app.UseCors("AllowAll"); app.UseAuthentication(); app.UseAuthorization(); // Map Health Check endpoints app.MapHealthChecks("/health"); app.MapHealthChecks("/health/ready", new Microsoft.AspNetCore.Diagnostics.HealthChecks.HealthCheckOptions { Predicate = check => check.Tags.Contains("ready") }); app.MapHealthChecks("/health/live", new Microsoft.AspNetCore.Diagnostics.HealthChecks.HealthCheckOptions { Predicate = _ => false }); app.MapControllers(); app.UseGrpcWeb(new GrpcWebOptions { DefaultEnabled = true }); // Configure the HTTP request pipeline. app.ConfigureGrpcEndpoints(Assembly.GetExecutingAssembly(), endpoints => { // endpoints.MapGrpcService(); }); app.MapGet("/", () => "Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909"); app.UseSwagger(); app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1"); }); // Configure Hangfire Dashboard app.UseHangfireDashboard("/hangfire", new Hangfire.DashboardOptions { // TODO: برای production از Authorization filter استفاده کنید Authorization = Array.Empty() }); // Configure Recurring Jobs using (var scope = app.Services.CreateScope()) { var recurringJobManager = scope.ServiceProvider.GetRequiredService(); // Weekly Commission Calculation: Every Sunday at 00:05 (UTC) recurringJobManager.AddOrUpdate( recurringJobId: "weekly-commission-calculation", methodCall: job => job.ExecuteAsync(CancellationToken.None), cronExpression: "5 0 * * 0", // Sunday at 00:05 options: new RecurringJobOptions { TimeZone = TimeZoneInfo.Utc }); app.Logger.LogInformation("✅ Hangfire recurring job 'weekly-commission-calculation' registered (Cron: 5 0 * * 0 - Sunday 00:05 UTC)"); // Daya Loan Check: Every 15 minutes CMSMicroservice.WebApi.Workers.DayaLoanCheckWorker.Schedule(recurringJobManager); app.Logger.LogInformation("✅ Hangfire recurring job 'daya-loan-check' registered (Cron: */15 * * * * - Every 15 minutes)"); } app.Run();