change program.cs logger and docker file
This commit is contained in:
@@ -33,45 +33,22 @@ using GozareshgirProgramManager.Application.Modules.Users.Commands.CreateUser;
|
||||
using GozareshgirProgramManager.Infrastructure;
|
||||
using GozareshgirProgramManager.Infrastructure.Persistence.Seed;
|
||||
using Microsoft.AspNetCore.HttpOverrides;
|
||||
using Microsoft.OpenApi;
|
||||
using Serilog;
|
||||
using Serilog.Events;
|
||||
using ServiceHost.Hubs.ProgramManager;
|
||||
using ServiceHost.Notifications.ProgramManager;
|
||||
using ServiceHost.Conventions;
|
||||
using ServiceHost.Filters;
|
||||
using Microsoft.Extensions.FileProviders;
|
||||
using Microsoft.OpenApi; // Corrected using for PhysicalFileProvider
|
||||
|
||||
// ====================================================================
|
||||
// ❌ FIX REMOVED: این بخش باعث میشد فایلهای استاتیک در داکر پیدا نشوند
|
||||
// ✅ BEST PRACTICE: Use two-stage Serilog initialization to log startup errors.
|
||||
// ====================================================================
|
||||
// Environment.SetEnvironmentVariable("ASPNETCORE_HOSTINGSTARTUPASSEMBLIES", "");
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
// ❌ این بخش هم حذف شد چون مانع لود شدن استاتیک فایلها در پروداکشن میشود
|
||||
// if (!builder.Environment.IsDevelopment())
|
||||
// {
|
||||
// builder.Configuration["Microsoft.AspNetCore.Hosting.StaticWebAssets.UseStaticWebAssets"] = "false";
|
||||
// }
|
||||
|
||||
builder.WebHost.ConfigureKestrel(serverOptions => { serverOptions.Limits.MaxRequestBodySize = long.MaxValue; });
|
||||
|
||||
builder.Services.AddRazorPages()
|
||||
.AddRazorRuntimeCompilation();
|
||||
|
||||
//Register Services
|
||||
//test
|
||||
#region Register Services
|
||||
|
||||
builder.Services.AddHttpContextAccessor();
|
||||
builder.Services.AddHttpClient("holidayApi", c => c.BaseAddress = new System.Uri("https://api.github.com"));
|
||||
var connectionString = builder.Configuration.GetConnectionString("MesbahDb");
|
||||
var connectionStringTestDb = builder.Configuration.GetConnectionString("TestDb");
|
||||
|
||||
#region Serilog
|
||||
// Use Docker-compatible log path
|
||||
var logDirectory = builder.Environment.IsDevelopment()
|
||||
? @"C:\Logs\Gozareshgir\"
|
||||
var logDirectory = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == Environments.Development
|
||||
? @"C:\Logs\Gozareshgir\"
|
||||
: "/app/Logs";
|
||||
|
||||
if (!Directory.Exists(logDirectory))
|
||||
@@ -79,415 +56,342 @@ if (!Directory.Exists(logDirectory))
|
||||
Directory.CreateDirectory(logDirectory);
|
||||
}
|
||||
|
||||
// Bootstrap logger: Catches errors during host configuration
|
||||
Log.Logger = new LoggerConfiguration()
|
||||
//NO EF Core log
|
||||
.MinimumLevel.Override("Microsoft.EntityFrameworkCore", LogEventLevel.Warning)
|
||||
|
||||
//NO DbCommand log
|
||||
.MinimumLevel.Override("Microsoft.EntityFrameworkCore.Database.Command", LogEventLevel.Warning)
|
||||
|
||||
//NO Microsoft Public log
|
||||
.MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
|
||||
|
||||
//.MinimumLevel.Information()
|
||||
.WriteTo.File(
|
||||
path: Path.Combine(logDirectory, "gozareshgir_log.txt"),
|
||||
rollingInterval: RollingInterval.Day,
|
||||
retainedFileCountLimit: 30,
|
||||
shared: true,
|
||||
outputTemplate:
|
||||
"{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level}] {Message}{NewLine}{Exception}"
|
||||
)
|
||||
// ✅ Console logging برای Docker
|
||||
.MinimumLevel.Information()
|
||||
.WriteTo.Console()
|
||||
.CreateLogger();
|
||||
.CreateBootstrapLogger();
|
||||
|
||||
#endregion
|
||||
Log.Information("Starting web host...");
|
||||
|
||||
builder.Services.AddProgramManagerApplication();
|
||||
builder.Services.AddProgramManagerInfrastructure(builder.Configuration);
|
||||
builder.Services.AddValidatorsFromAssemblyContaining<CreateUserCommandValidators>();
|
||||
builder.Services.AddScoped<IDataSeeder, DataSeeder>();
|
||||
builder.Services.AddScoped<IBoardNotificationPublisher, SignalRBoardNotificationPublisher>();
|
||||
|
||||
#region MongoDb
|
||||
|
||||
var mongoConnectionSection = builder.Configuration.GetSection("MongoDb");
|
||||
var mongoDbSettings = mongoConnectionSection.Get<MongoDbConfig>();
|
||||
var mongoClient = new MongoClient(mongoDbSettings.ConnectionString);
|
||||
var mongoDatabase = mongoClient.GetDatabase(mongoDbSettings.DatabaseName);
|
||||
|
||||
builder.Services.AddSingleton<IMongoDatabase>(mongoDatabase);
|
||||
|
||||
#endregion
|
||||
|
||||
builder.Services.AddSingleton<IActionResultExecutor<JsonResult>, CustomJsonResultExecutor>();
|
||||
PersonalBootstrapper.Configure(builder.Services, connectionString);
|
||||
TestDbBootStrapper.Configure(builder.Services, connectionStringTestDb);
|
||||
|
||||
AccountManagementBootstrapper.Configure(builder.Services, connectionString);
|
||||
WorkFlowBootstrapper.Configure(builder.Services, connectionString);
|
||||
QueryBootstrapper.Configure(builder.Services);
|
||||
|
||||
|
||||
builder.Services.AddSingleton<IPasswordHasher, PasswordHasher>();
|
||||
builder.Services.AddTransient<IFileUploader, FileUploader>();
|
||||
builder.Services.AddTransient<IAuthHelper, AuthHelper>();
|
||||
builder.Services.AddTransient<IGoogleRecaptcha, GoogleRecaptcha>();
|
||||
builder.Services.AddTransient<ISmsService, SmsService>();
|
||||
builder.Services.AddTransient<IUidService, UidService>();
|
||||
builder.Services.AddTransient<IFaceEmbeddingNotificationService, FaceEmbeddingNotificationService>();
|
||||
|
||||
#region Mahan
|
||||
|
||||
builder.Services.AddTransient<Tester>();
|
||||
builder.Services.Configure<AppSettingConfiguration>(builder.Configuration);
|
||||
|
||||
#endregion
|
||||
|
||||
builder.Services.Configure<FormOptions>(options =>
|
||||
try
|
||||
{
|
||||
options.ValueCountLimit = int.MaxValue;
|
||||
options.KeyLengthLimit = int.MaxValue;
|
||||
options.ValueLengthLimit = int.MaxValue;
|
||||
options.MultipartBodyLengthLimit = long.MaxValue;
|
||||
options.MemoryBufferThreshold = int.MaxValue;
|
||||
options.MultipartHeadersLengthLimit = int.MaxValue;
|
||||
});
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
builder.Services.Configure<CookiePolicyOptions>(options =>
|
||||
{
|
||||
options.CheckConsentNeeded = context => true;
|
||||
});
|
||||
var domain = builder.Configuration["Domain"];
|
||||
|
||||
builder.Services.ConfigureApplicationCookie(options =>
|
||||
{
|
||||
//options.Cookie.Name = "GozarAuth";
|
||||
options.Cookie.HttpOnly = true;
|
||||
options.Cookie.SameSite = SameSiteMode.None; // مهم ✅
|
||||
options.Cookie.SecurePolicy = CookieSecurePolicy.Always; // فقط روی HTTPS کار میکنه ✅
|
||||
options.Cookie.Domain = domain; // دامنه مشترک بین پدر و سابدامینها ✅
|
||||
});
|
||||
|
||||
|
||||
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
|
||||
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, o =>
|
||||
{
|
||||
o.LoginPath = new PathString("/");
|
||||
o.LogoutPath = new PathString("/index");
|
||||
o.AccessDeniedPath = new PathString("/AccessDenied");
|
||||
|
||||
o.ExpireTimeSpan = TimeSpan.FromHours(10);
|
||||
o.SlidingExpiration = true;
|
||||
});
|
||||
|
||||
builder.Services.AddAuthorization(options =>
|
||||
{
|
||||
options.AddPolicy("AdminArea",
|
||||
builder => builder.RequireClaim("AccountId"));
|
||||
options.AddPolicy("AdminArea",
|
||||
builder => builder.RequireClaim("AdminAreaPermission", new List<string> { "true" }));
|
||||
});
|
||||
|
||||
builder.Services.AddAuthorization(options =>
|
||||
{
|
||||
options.AddPolicy("ClientArea",
|
||||
builder => builder.RequireClaim("AccountId"));
|
||||
options.AddPolicy("ClientArea",
|
||||
builder => builder.RequireClaim("ClientAriaPermission", new List<string> { "true" }));
|
||||
});
|
||||
|
||||
builder.Services.AddAuthorization(options =>
|
||||
{
|
||||
options.AddPolicy("CameraArea",
|
||||
builder => builder.RequireClaim("AccountId"));
|
||||
});
|
||||
|
||||
builder.Services.AddAuthorization(options =>
|
||||
{
|
||||
options.AddPolicy("AdminNewArea",
|
||||
builder => builder.RequireClaim("AccountId"));
|
||||
options.AddPolicy("AdminNewArea",
|
||||
builder => builder.RequireClaim("AdminAreaPermission", new List<string> { "true" }));
|
||||
});
|
||||
|
||||
|
||||
builder.Services.AddControllers(options =>
|
||||
{
|
||||
options.Conventions.Add(new ParameterBindingConvention());
|
||||
options.Filters.Add(new OperationResultFilter());
|
||||
})
|
||||
.AddJsonOptions(options =>
|
||||
{
|
||||
options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
|
||||
});
|
||||
|
||||
|
||||
builder.Services.AddRazorPages(options =>
|
||||
options.Conventions.AuthorizeAreaFolder("Admin", "/", "AdminArea"));
|
||||
builder.Services.AddRazorPages(options =>
|
||||
options.Conventions.AuthorizeAreaFolder("Client", "/", "ClientArea"))
|
||||
.AddMvcOptions(options => options.Filters.Add<SecurityPageFilter>());
|
||||
builder.Services.AddRazorPages(options =>
|
||||
options.Conventions.AuthorizeAreaFolder("Camera", "/", "CameraArea"));
|
||||
builder.Services.AddRazorPages(options =>
|
||||
options.Conventions.AuthorizeAreaFolder("AdminNew", "/", "AdminNewArea"));
|
||||
builder.Services.AddMvc();
|
||||
builder.Services.AddSignalR();
|
||||
|
||||
#endregion
|
||||
|
||||
#region Swagger
|
||||
|
||||
builder.Services.AddSwaggerGen(options =>
|
||||
{
|
||||
options.UseInlineDefinitionsForEnums();
|
||||
options.CustomSchemaIds(type => type.FullName);
|
||||
|
||||
var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
|
||||
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
|
||||
options.IncludeXmlComments(xmlPath);
|
||||
|
||||
var classLibraryXmlFile = "CompanyManagment.App.Contracts.xml";
|
||||
var classLibraryXmlPath = Path.Combine(AppContext.BaseDirectory, classLibraryXmlFile);
|
||||
options.IncludeXmlComments(classLibraryXmlPath);
|
||||
|
||||
|
||||
options.SwaggerDoc("General", new OpenApiInfo { Title = "API - General", Version = "v1" });
|
||||
options.SwaggerDoc("Admin", new OpenApiInfo { Title = "API - Admin", Version = "v1" });
|
||||
options.SwaggerDoc("Client", new OpenApiInfo { Title = "API - Client", Version = "v1" });
|
||||
options.SwaggerDoc("Camera", new OpenApiInfo { Title = "API - Camera", Version = "v1" });
|
||||
options.SwaggerDoc("ProgramManager", new OpenApiInfo { Title = "API - ProgramManager", Version = "v1" });
|
||||
|
||||
options.DocInclusionPredicate((docName, apiDesc) =>
|
||||
string.Equals(docName, apiDesc.GroupName, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
options.EnableAnnotations();
|
||||
});
|
||||
|
||||
#endregion
|
||||
|
||||
#region CORS
|
||||
|
||||
builder.Services.AddCors(options =>
|
||||
{
|
||||
options.AddPolicy("AllowSpecificOrigins", policy =>
|
||||
{
|
||||
policy.WithOrigins(
|
||||
"http://localhost:3000",
|
||||
"http://localhost:4000",
|
||||
"http://localhost:4001",
|
||||
"http://localhost:4002",
|
||||
"http://localhost:3001",
|
||||
"https://gozareshgir.ir",
|
||||
"https://dad-mehr.ir",
|
||||
"https://admin.dad-mehr.ir",
|
||||
"https://client.dad-mehr.ir",
|
||||
"https://admin.gozareshgir.ir",
|
||||
"https://client.gozareshgir.ir",
|
||||
"https://admin.dadmehrg.ir",
|
||||
"https://client.dadmehrg.ir",
|
||||
"http://localhost:3300"
|
||||
|
||||
)
|
||||
.AllowAnyHeader()
|
||||
.AllowAnyMethod()
|
||||
.AllowCredentials();
|
||||
});
|
||||
});
|
||||
|
||||
#endregion
|
||||
|
||||
builder.Services.AddExceptionHandler<CustomExceptionHandler>();
|
||||
|
||||
var sepehrTerminalId = builder.Configuration.GetValue<long>("SepehrGateWayTerminalId");
|
||||
|
||||
builder.Services.AddParbad().ConfigureGateways(gateways =>
|
||||
{
|
||||
gateways.AddSepehr().WithAccounts(accounts =>
|
||||
{
|
||||
accounts.AddInMemory(account =>
|
||||
{
|
||||
account.TerminalId = sepehrTerminalId;
|
||||
account.Name="Sepehr Account";
|
||||
});
|
||||
});
|
||||
}).ConfigureHttpContext(httpContext=>httpContext.UseDefaultAspNetCore())
|
||||
.ConfigureStorage(storage =>
|
||||
{
|
||||
storage.UseMemoryCache();
|
||||
});
|
||||
|
||||
|
||||
// Configure Serilog for both Development and Production
|
||||
builder.Host.UseSerilog((context, services, configuration) =>
|
||||
{
|
||||
var logConfig = configuration
|
||||
.ReadFrom.Configuration(context.Configuration)
|
||||
// ====================================================================
|
||||
// ✅ STANDARD SERILOG CONFIGURATION FOR PRODUCTION
|
||||
// ====================================================================
|
||||
builder.Host.UseSerilog((context, services, configuration) => configuration
|
||||
.ReadFrom.Configuration(context.Configuration) // Optional: Allows config from appsettings.json
|
||||
.ReadFrom.Services(services)
|
||||
.Enrich.FromLogContext();
|
||||
.Enrich.FromLogContext()
|
||||
.MinimumLevel.Information() // Default minimum level for your application's own logs
|
||||
.MinimumLevel.Override("Microsoft", LogEventLevel.Warning) // Suppress noisy Microsoft logs
|
||||
.MinimumLevel.Override("Microsoft.Hosting.Lifetime", LogEventLevel.Information) // ✅ KEEP THIS: Shows "Now listening on..."
|
||||
.MinimumLevel.Override("Microsoft.EntityFrameworkCore.Database.Command", LogEventLevel.Warning) // Suppresses EF query logs
|
||||
.WriteTo.Console(outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}")
|
||||
.WriteTo.File(
|
||||
path: Path.Combine(logDirectory, "gozareshgir_log.txt"),
|
||||
rollingInterval: RollingInterval.Day,
|
||||
retainedFileCountLimit: 30,
|
||||
shared: true,
|
||||
outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] [{SourceContext}] {Message:lj}{NewLine}{Exception}"
|
||||
));
|
||||
|
||||
logConfig.WriteTo.File(
|
||||
path: Path.Combine(logDirectory, "gozareshgir_log.txt"),
|
||||
rollingInterval: RollingInterval.Day,
|
||||
retainedFileCountLimit: 30,
|
||||
shared: true,
|
||||
outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level}] {Message}{NewLine}{Exception}"
|
||||
);
|
||||
builder.WebHost.ConfigureKestrel(serverOptions => { serverOptions.Limits.MaxRequestBodySize = long.MaxValue; });
|
||||
|
||||
logConfig.WriteTo.Console();
|
||||
builder.Services.AddRazorPages()
|
||||
.AddRazorRuntimeCompilation();
|
||||
|
||||
}, writeToProviders: true);
|
||||
#region Register Services
|
||||
|
||||
Log.Information("SERILOG STARTED SUCCESSFULLY");
|
||||
builder.Services.AddHttpContextAccessor();
|
||||
builder.Services.AddHttpClient("holidayApi", c => c.BaseAddress = new Uri("https://api.github.com"));
|
||||
var connectionString = builder.Configuration.GetConnectionString("MesbahDb");
|
||||
var connectionStringTestDb = builder.Configuration.GetConnectionString("TestDb");
|
||||
|
||||
builder.Services.AddProgramManagerApplication();
|
||||
builder.Services.AddProgramManagerInfrastructure(builder.Configuration);
|
||||
builder.Services.AddValidatorsFromAssemblyContaining<CreateUserCommandValidators>();
|
||||
builder.Services.AddScoped<IDataSeeder, DataSeeder>();
|
||||
builder.Services.AddScoped<IBoardNotificationPublisher, SignalRBoardNotificationPublisher>();
|
||||
|
||||
builder.Services.Configure<ForwardedHeadersOptions>(options =>
|
||||
{
|
||||
options.ForwardedHeaders =
|
||||
ForwardedHeaders.XForwardedFor |
|
||||
ForwardedHeaders.XForwardedProto;
|
||||
#region MongoDb
|
||||
var mongoConnectionSection = builder.Configuration.GetSection("MongoDb");
|
||||
var mongoDbSettings = mongoConnectionSection.Get<MongoDbConfig>();
|
||||
var mongoClient = new MongoClient(mongoDbSettings.ConnectionString);
|
||||
var mongoDatabase = mongoClient.GetDatabase(mongoDbSettings.DatabaseName);
|
||||
builder.Services.AddSingleton<IMongoDatabase>(mongoDatabase);
|
||||
#endregion
|
||||
|
||||
var proxies = builder.Configuration["KNOWN_PROXIES"];
|
||||
if (!string.IsNullOrWhiteSpace(proxies))
|
||||
builder.Services.AddSingleton<IActionResultExecutor<JsonResult>, CustomJsonResultExecutor>();
|
||||
PersonalBootstrapper.Configure(builder.Services, connectionString);
|
||||
TestDbBootStrapper.Configure(builder.Services, connectionStringTestDb);
|
||||
AccountManagementBootstrapper.Configure(builder.Services, connectionString);
|
||||
WorkFlowBootstrapper.Configure(builder.Services, connectionString);
|
||||
QueryBootstrapper.Configure(builder.Services);
|
||||
|
||||
builder.Services.AddSingleton<IPasswordHasher, PasswordHasher>();
|
||||
builder.Services.AddTransient<IFileUploader, FileUploader>();
|
||||
builder.Services.AddTransient<IAuthHelper, AuthHelper>();
|
||||
builder.Services.AddTransient<IGoogleRecaptcha, GoogleRecaptcha>();
|
||||
builder.Services.AddTransient<ISmsService, SmsService>();
|
||||
builder.Services.AddTransient<IUidService, UidService>();
|
||||
builder.Services.AddTransient<IFaceEmbeddingNotificationService, FaceEmbeddingNotificationService>();
|
||||
|
||||
#region Mahan
|
||||
builder.Services.AddTransient<Tester>();
|
||||
builder.Services.Configure<AppSettingConfiguration>(builder.Configuration);
|
||||
#endregion
|
||||
|
||||
builder.Services.Configure<FormOptions>(options =>
|
||||
{
|
||||
foreach (var proxy in proxies.Split(',', StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
options.KnownProxies.Add(IPAddress.Parse(proxy.Trim()));
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
var app = builder.Build();
|
||||
app.UseCors("AllowSpecificOrigins");
|
||||
|
||||
#region InternalProgarmManagerApi
|
||||
|
||||
app.Use(async (context, next) =>
|
||||
{
|
||||
var host = context.Request.Host.Host?.ToLower() ?? "";
|
||||
|
||||
string baseUrl;
|
||||
|
||||
if (host.Contains("localhost"))
|
||||
baseUrl = builder.Configuration["InternalApi:Local"];
|
||||
else if (host.Contains("dadmehrg.ir"))
|
||||
baseUrl = builder.Configuration["InternalApi:Dadmehrg"];
|
||||
else if (host.Contains("gozareshgir.ir"))
|
||||
baseUrl = builder.Configuration["InternalApi:Gozareshgir"];
|
||||
else
|
||||
baseUrl = builder.Configuration["InternalApi:Local"]; // fallback
|
||||
|
||||
InternalApiCaller.SetBaseUrl(baseUrl);
|
||||
|
||||
await next.Invoke();
|
||||
});
|
||||
|
||||
#endregion
|
||||
|
||||
#region Mahan
|
||||
|
||||
//the backend Tester
|
||||
if (builder.Environment.IsDevelopment())
|
||||
{
|
||||
using var scope = app.Services.CreateScope();
|
||||
var tester = scope.ServiceProvider.GetRequiredService<Tester>();
|
||||
await tester.Test();
|
||||
}
|
||||
|
||||
|
||||
if (app.Environment.IsDevelopment())
|
||||
{
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI(options =>
|
||||
{
|
||||
options.DocExpansion(DocExpansion.None);
|
||||
options.SwaggerEndpoint("/swagger/General/swagger.json", "API - General");
|
||||
options.SwaggerEndpoint("/swagger/Admin/swagger.json", "API - Admin");
|
||||
options.SwaggerEndpoint("/swagger/Client/swagger.json", "API - Client");
|
||||
options.SwaggerEndpoint("/swagger/Camera/swagger.json", "API - Camera");
|
||||
options.SwaggerEndpoint("/swagger/ProgramManager/swagger.json", "API - ProgramManager");
|
||||
|
||||
options.ValueCountLimit = int.MaxValue;
|
||||
options.KeyLengthLimit = int.MaxValue;
|
||||
options.ValueLengthLimit = int.MaxValue;
|
||||
options.MultipartBodyLengthLimit = long.MaxValue;
|
||||
options.MemoryBufferThreshold = int.MaxValue;
|
||||
options.MultipartHeadersLengthLimit = int.MaxValue;
|
||||
});
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Create Http Pipeline
|
||||
|
||||
app.UseForwardedHeaders();
|
||||
|
||||
if (builder.Environment.IsDevelopment())
|
||||
{
|
||||
app.UseDeveloperExceptionPage();
|
||||
}
|
||||
else
|
||||
{
|
||||
// The default HSTS value is 30 days.
|
||||
app.UseHsts();
|
||||
}
|
||||
|
||||
app.UseExceptionHandler(options => { });
|
||||
|
||||
//app.UseHttpsRedirection();
|
||||
|
||||
// ✅ FIX: UseStaticFiles must be BEFORE Routing and Auth
|
||||
app.UseStaticFiles();
|
||||
|
||||
// Static files برای فایلهای آپلود شده
|
||||
var uploadsPath = builder.Configuration["FileStorage:LocalPath"] ?? Path.Combine(Directory.GetCurrentDirectory(), "Storage");
|
||||
if (!Directory.Exists(uploadsPath))
|
||||
{
|
||||
Directory.CreateDirectory(uploadsPath);
|
||||
}
|
||||
|
||||
app.UseStaticFiles(new StaticFileOptions
|
||||
{
|
||||
FileProvider = new Microsoft.Extensions.FileProviders.PhysicalFileProvider(uploadsPath),
|
||||
RequestPath = "/storage",
|
||||
OnPrepareResponse = ctx =>
|
||||
builder.Services.Configure<CookiePolicyOptions>(options =>
|
||||
{
|
||||
ctx.Context.Response.Headers.Append("Cache-Control", "public,max-age=2592000");
|
||||
options.CheckConsentNeeded = context => true;
|
||||
});
|
||||
|
||||
var domain = builder.Configuration["Domain"];
|
||||
builder.Services.ConfigureApplicationCookie(options =>
|
||||
{
|
||||
options.Cookie.HttpOnly = true;
|
||||
options.Cookie.SameSite = SameSiteMode.None;
|
||||
options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
|
||||
options.Cookie.Domain = domain;
|
||||
});
|
||||
|
||||
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
|
||||
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, o =>
|
||||
{
|
||||
o.LoginPath = new PathString("/");
|
||||
o.LogoutPath = new PathString("/index");
|
||||
o.AccessDeniedPath = new PathString("/AccessDenied");
|
||||
o.ExpireTimeSpan = TimeSpan.FromHours(10);
|
||||
o.SlidingExpiration = true;
|
||||
});
|
||||
|
||||
builder.Services.AddAuthorization(options =>
|
||||
{
|
||||
options.AddPolicy("AdminArea", builder => builder.RequireClaim("AccountId").RequireClaim("AdminAreaPermission", "true"));
|
||||
options.AddPolicy("ClientArea", builder => builder.RequireClaim("AccountId").RequireClaim("ClientAriaPermission", "true"));
|
||||
options.AddPolicy("CameraArea", builder => builder.RequireClaim("AccountId"));
|
||||
options.AddPolicy("AdminNewArea", builder => builder.RequireClaim("AccountId").RequireClaim("AdminAreaPermission", "true"));
|
||||
});
|
||||
|
||||
builder.Services.AddControllers(options =>
|
||||
{
|
||||
options.Conventions.Add(new ParameterBindingConvention());
|
||||
options.Filters.Add(new OperationResultFilter());
|
||||
})
|
||||
.AddJsonOptions(options =>
|
||||
{
|
||||
options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
|
||||
});
|
||||
|
||||
builder.Services.AddRazorPages(options =>
|
||||
options.Conventions.AuthorizeAreaFolder("Admin", "/", "AdminArea"));
|
||||
builder.Services.AddRazorPages(options =>
|
||||
options.Conventions.AuthorizeAreaFolder("Client", "/", "ClientArea"))
|
||||
.AddMvcOptions(options => options.Filters.Add<SecurityPageFilter>());
|
||||
builder.Services.AddRazorPages(options =>
|
||||
options.Conventions.AuthorizeAreaFolder("Camera", "/", "CameraArea"));
|
||||
builder.Services.AddRazorPages(options =>
|
||||
options.Conventions.AuthorizeAreaFolder("AdminNew", "/", "AdminNewArea"));
|
||||
builder.Services.AddMvc();
|
||||
builder.Services.AddSignalR();
|
||||
|
||||
#endregion
|
||||
|
||||
#region Swagger
|
||||
builder.Services.AddSwaggerGen(options =>
|
||||
{
|
||||
options.UseInlineDefinitionsForEnums();
|
||||
options.CustomSchemaIds(type => type.FullName);
|
||||
|
||||
var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
|
||||
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
|
||||
options.IncludeXmlComments(xmlPath);
|
||||
|
||||
var classLibraryXmlFile = "CompanyManagment.App.Contracts.xml";
|
||||
var classLibraryXmlPath = Path.Combine(AppContext.BaseDirectory, classLibraryXmlFile);
|
||||
options.IncludeXmlComments(classLibraryXmlPath);
|
||||
|
||||
options.SwaggerDoc("General", new OpenApiInfo { Title = "API - General", Version = "v1" });
|
||||
options.SwaggerDoc("Admin", new OpenApiInfo { Title = "API - Admin", Version = "v1" });
|
||||
options.SwaggerDoc("Client", new OpenApiInfo { Title = "API - Client", Version = "v1" });
|
||||
options.SwaggerDoc("Camera", new OpenApiInfo { Title = "API - Camera", Version = "v1" });
|
||||
options.SwaggerDoc("ProgramManager", new OpenApiInfo { Title = "API - ProgramManager", Version = "v1" });
|
||||
|
||||
options.DocInclusionPredicate((docName, apiDesc) =>
|
||||
string.Equals(docName, apiDesc.GroupName, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
options.EnableAnnotations();
|
||||
});
|
||||
#endregion
|
||||
|
||||
#region CORS
|
||||
builder.Services.AddCors(options =>
|
||||
{
|
||||
options.AddPolicy("AllowSpecificOrigins", policy =>
|
||||
{
|
||||
policy.WithOrigins(
|
||||
"http://localhost:3000", "http://localhost:4000", "http://localhost:4001",
|
||||
"http://localhost:4002", "http://localhost:3001", "https://gozareshgir.ir",
|
||||
"https://dad-mehr.ir", "https://admin.dad-mehr.ir", "https://client.dad-mehr.ir",
|
||||
"https://admin.gozareshgir.ir", "https://client.gozareshgir.ir",
|
||||
"https://admin.dadmehrg.ir", "https://client.dadmehrg.ir", "http://localhost:3300"
|
||||
)
|
||||
.AllowAnyHeader()
|
||||
.AllowAnyMethod()
|
||||
.AllowCredentials();
|
||||
});
|
||||
});
|
||||
#endregion
|
||||
|
||||
builder.Services.AddExceptionHandler<CustomExceptionHandler>();
|
||||
|
||||
var sepehrTerminalId = builder.Configuration.GetValue<long>("SepehrGateWayTerminalId");
|
||||
builder.Services.AddParbad().ConfigureGateways(gateways =>
|
||||
{
|
||||
gateways.AddSepehr().WithAccounts(accounts =>
|
||||
{
|
||||
accounts.AddInMemory(account =>
|
||||
{
|
||||
account.TerminalId = sepehrTerminalId;
|
||||
account.Name = "Sepehr Account";
|
||||
});
|
||||
});
|
||||
}).ConfigureHttpContext(httpContext => httpContext.UseDefaultAspNetCore())
|
||||
.ConfigureStorage(storage =>
|
||||
{
|
||||
storage.UseMemoryCache();
|
||||
});
|
||||
|
||||
builder.Services.Configure<ForwardedHeadersOptions>(options =>
|
||||
{
|
||||
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
|
||||
var proxies = builder.Configuration["KNOWN_PROXIES"];
|
||||
if (!string.IsNullOrWhiteSpace(proxies))
|
||||
{
|
||||
foreach (var proxy in proxies.Split(',', StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
options.KnownProxies.Add(IPAddress.Parse(proxy.Trim()));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// ====================================================================
|
||||
// ✅ HTTP PIPELINE CONFIGURATION
|
||||
// ====================================================================
|
||||
|
||||
app.UseCors("AllowSpecificOrigins");
|
||||
|
||||
#region InternalProgarmManagerApi
|
||||
app.Use(async (context, next) =>
|
||||
{
|
||||
var host = context.Request.Host.Host?.ToLower() ?? "";
|
||||
string baseUrl = host switch
|
||||
{
|
||||
var h when h.Contains("localhost") => builder.Configuration["InternalApi:Local"],
|
||||
var h when h.Contains("dadmehrg.ir") => builder.Configuration["InternalApi:Dadmehrg"],
|
||||
var h when h.Contains("gozareshgir.ir") => builder.Configuration["InternalApi:Gozareshgir"],
|
||||
_ => builder.Configuration["InternalApi:Local"]
|
||||
};
|
||||
InternalApiCaller.SetBaseUrl(baseUrl);
|
||||
await next.Invoke();
|
||||
});
|
||||
#endregion
|
||||
|
||||
#region Mahan
|
||||
if (builder.Environment.IsDevelopment())
|
||||
{
|
||||
using var scope = app.Services.CreateScope();
|
||||
var tester = scope.ServiceProvider.GetRequiredService<Tester>();
|
||||
await tester.Test();
|
||||
}
|
||||
});
|
||||
|
||||
// ✅ Routing comes after Static Files
|
||||
app.UseRouting();
|
||||
app.UseWebSockets();
|
||||
if (app.Environment.IsDevelopment())
|
||||
{
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI(options =>
|
||||
{
|
||||
options.DocExpansion(DocExpansion.None);
|
||||
options.SwaggerEndpoint("/swagger/General/swagger.json", "API - General");
|
||||
options.SwaggerEndpoint("/swagger/Admin/swagger.json", "API - Admin");
|
||||
options.SwaggerEndpoint("/swagger/Client/swagger.json", "API - Client");
|
||||
options.SwaggerEndpoint("/swagger/Camera/swagger.json", "API - Camera");
|
||||
options.SwaggerEndpoint("/swagger/ProgramManager/swagger.json", "API - ProgramManager");
|
||||
});
|
||||
}
|
||||
#endregion
|
||||
|
||||
// ✅ Cookie Policy should be before Auth
|
||||
app.UseCookiePolicy();
|
||||
app.UseForwardedHeaders();
|
||||
|
||||
// ✅ Auth comes after Routing
|
||||
app.UseAuthentication();
|
||||
app.UseAuthorization();
|
||||
if (builder.Environment.IsDevelopment())
|
||||
{
|
||||
app.UseDeveloperExceptionPage();
|
||||
}
|
||||
else
|
||||
{
|
||||
app.UseHsts();
|
||||
}
|
||||
|
||||
app.UseExceptionHandler(options => { });
|
||||
|
||||
#region Mahan
|
||||
app.Use(async (context, next) =>
|
||||
{
|
||||
if (context.Request.Path.HasValue)
|
||||
{
|
||||
context.Request.Path = context.Request.Path.Value.ToLowerInvariant();
|
||||
}
|
||||
await next();
|
||||
});
|
||||
|
||||
//app.UseLoginHandlerMiddleware();
|
||||
app.UseStaticFiles();
|
||||
|
||||
//app.UseCheckTaskMiddleware();
|
||||
app.UseMiddleware<RazorJsonEnumOverrideMiddleware>();
|
||||
var uploadsPath = builder.Configuration["FileStorage:LocalPath"] ?? Path.Combine(Directory.GetCurrentDirectory(), "Storage");
|
||||
if (!Directory.Exists(uploadsPath))
|
||||
{
|
||||
Directory.CreateDirectory(uploadsPath);
|
||||
}
|
||||
app.UseStaticFiles(new StaticFileOptions
|
||||
{
|
||||
FileProvider = new PhysicalFileProvider(uploadsPath),
|
||||
RequestPath = "/storage",
|
||||
OnPrepareResponse = ctx =>
|
||||
{
|
||||
ctx.Context.Response.Headers.Append("Cache-Control", "public,max-age=2592000");
|
||||
}
|
||||
});
|
||||
|
||||
#endregion
|
||||
app.UseRouting();
|
||||
app.UseWebSockets();
|
||||
app.UseCookiePolicy();
|
||||
app.UseAuthentication();
|
||||
app.UseAuthorization();
|
||||
|
||||
#region Mahan
|
||||
app.UseMiddleware<RazorJsonEnumOverrideMiddleware>();
|
||||
#endregion
|
||||
|
||||
app.MapHub<CreateContractTarckingHub>("/trackingHub");
|
||||
app.MapHub<SendAccountMessage>("/trackingSmsHub");
|
||||
app.MapHub<HolidayApiHub>("/trackingHolidayHub");
|
||||
app.MapHub<CheckoutHub>("/trackingCheckoutHub");
|
||||
app.MapHub<SendSmsHub>("/trackingSendSmsHub");
|
||||
app.MapHub<ProjectBoardHub>("api/pm/board");
|
||||
app.MapRazorPages();
|
||||
app.MapControllers();
|
||||
app.MapHub<CreateContractTarckingHub>("/trackingHub");
|
||||
app.MapHub<SendAccountMessage>("/trackingSmsHub");
|
||||
app.MapHub<HolidayApiHub>("/trackingHolidayHub");
|
||||
app.MapHub<CheckoutHub>("/trackingCheckoutHub");
|
||||
app.MapHub<SendSmsHub>("/trackingSendSmsHub");
|
||||
app.MapHub<ProjectBoardHub>("api/pm/board");
|
||||
app.MapRazorPages();
|
||||
app.MapControllers();
|
||||
|
||||
// Health check endpoint for Docker
|
||||
app.MapGet("/health", () => Results.Ok(new { status = "Healthy", timestamp = DateTime.UtcNow }));
|
||||
app.MapGet("/health", () => Results.Ok(new { status = "Healthy", timestamp = DateTime.UtcNow }));
|
||||
|
||||
#endregion
|
||||
|
||||
app.Run();
|
||||
app.Run();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Fatal(ex, "Host terminated unexpectedly");
|
||||
}
|
||||
finally
|
||||
{
|
||||
Log.CloseAndFlush();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user