2025-09-27 08:46:36 +03:30
using CMSMicroservice.Infrastructure.Persistence ;
2025-11-30 20:18:10 +03:30
using CMSMicroservice.Infrastructure.Data.Seeding ;
2025-09-27 08:46:36 +03:30
using Microsoft.AspNetCore.Builder ;
using Microsoft.Extensions.DependencyInjection ;
using Microsoft.Extensions.Hosting ;
using Microsoft.AspNetCore.Hosting ;
2025-11-30 20:18:10 +03:30
using Microsoft.Extensions.Logging ;
2025-09-27 08:46:36 +03:30
using Serilog.Core ;
using Serilog ;
using System.Reflection ;
2025-12-06 22:24:28 +03:30
using System.Runtime.InteropServices ;
2025-09-27 08:46:36 +03:30
using Microsoft.OpenApi.Models ;
using CMSMicroservice.WebApi.Common.Behaviours ;
2025-12-01 20:52:18 +03:30
using Hangfire ;
using Hangfire.SqlServer ;
2025-12-06 22:24:28 +03:30
using Microsoft.AspNetCore.Server.Kestrel.Core ;
2025-09-27 08:46:36 +03:30
var builder = WebApplication . CreateBuilder ( args ) ;
2025-12-06 22:24:28 +03:30
if ( RuntimeInformation . IsOSPlatform ( OSPlatform . OSX ) )
{
builder . WebHost . ConfigureKestrel ( options = >
{
// Setup a HTTP/2 endpoint without TLS.
options . ListenLocalhost ( 5000 , o = > o . Protocols =
HttpProtocols . Http2 ) ;
} ) ;
}
2025-09-27 08:46:36 +03:30
var levelSwitch = new LoggingLevelSwitch ( ) ;
2025-12-05 19:32:28 +00:00
// Read Seq configuration from appsettings.json
var seqServerUrl = builder . Configuration [ "Seq:ServerUrl" ] ? ? "http://seq-svc:5341" ;
var seqApiKey = builder . Configuration [ "Seq:ApiKey" ] ;
2025-09-27 08:46:36 +03:30
var logger = new LoggerConfiguration ( )
2025-12-05 19:32:28 +00:00
. WriteTo . Console ( )
2025-09-27 10:23:45 +03:30
//.WriteTo.MSSqlServer(builder.Configuration.GetConnectionString("LogConnection"),
// sinkOptions: new MSSqlServerSinkOptions
// {
// TableName = "LogCMSEvents",
// SchemaName = "Log",
// AutoCreateSqlTable = true
// })
2025-12-05 19:32:28 +00:00
. WriteTo . Seq ( seqServerUrl ,
apiKey : string . IsNullOrEmpty ( seqApiKey ) ? null : seqApiKey ,
2025-09-27 10:23:45 +03:30
controlLevelSwitch : levelSwitch )
2025-09-27 08:46:36 +03:30
. 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 < LoggingBehaviour > ( ) ;
options . Interceptors . Add < PerformanceBehaviour > ( ) ;
2025-11-13 21:40:14 +03:30
//options.Interceptors.Add<ExceptionHandlingBehaviour>();
2025-09-27 08:46:36 +03:30
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 ( ) ;
2025-12-01 20:52:18 +03:30
#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 < ApplicationDbContext > ( "database" ) ;
#endregion
// Add Controllers for REST APIs
builder . Services . AddControllers ( ) ;
2025-09-27 08:46:36 +03:30
#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 < ApplicationDbContextInitialiser > ( ) ;
await initialiser . InitialiseAsync ( ) ;
await initialiser . SeedAsync ( ) ;
2025-11-30 20:18:10 +03:30
// Run Migration: ParentId → NetworkParentId (فقط یکبار اجرا میشود)
var migrationLogger = scope . ServiceProvider . GetRequiredService < ILogger < NetworkParentIdMigrationSeeder > > ( ) ;
var dbContext = scope . ServiceProvider . GetRequiredService < ApplicationDbContext > ( ) ;
var migrationSeeder = new NetworkParentIdMigrationSeeder ( dbContext , migrationLogger ) ;
await migrationSeeder . SeedAsync ( ) ;
2025-09-27 08:46:36 +03:30
}
}
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 ( ) ;
2025-12-01 20:52:18 +03:30
// 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 ( ) ;
2025-09-27 08:46:36 +03:30
app . UseGrpcWeb ( new GrpcWebOptions { DefaultEnabled = true } ) ; // Configure the HTTP request pipeline.
app . ConfigureGrpcEndpoints ( Assembly . GetExecutingAssembly ( ) , endpoints = >
{
// endpoints.MapGrpcService<ExampleService>();
} ) ;
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" ) ;
} ) ;
2025-12-01 20:52:18 +03:30
// Configure Hangfire Dashboard
app . UseHangfireDashboard ( "/hangfire" , new Hangfire . DashboardOptions
{
// TODO: برای production از Authorization filter استفاده کنید
Authorization = Array . Empty < Hangfire . Dashboard . IDashboardAuthorizationFilter > ( )
} ) ;
// Configure Recurring Jobs
using ( var scope = app . Services . CreateScope ( ) )
{
var recurringJobManager = scope . ServiceProvider . GetRequiredService < IRecurringJobManager > ( ) ;
// Weekly Commission Calculation: Every Sunday at 00:05 (UTC)
recurringJobManager . AddOrUpdate < CMSMicroservice . Infrastructure . BackgroundJobs . WeeklyCommissionJob > (
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)" ) ;
2025-12-02 03:30:36 +03:30
// 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)" ) ;
2025-12-01 20:52:18 +03:30
}
2025-09-27 08:46:36 +03:30
app . Run ( ) ;