update Docker configuration and Visual Studio solution for improved compatibility and build process

This commit is contained in:
2026-01-31 15:29:48 +03:30
parent 3720288bed
commit 8ecbbf6975
6 changed files with 83 additions and 126 deletions

View File

@@ -1,4 +1,5 @@
using System.Reflection;
using System.Net;
using System.Reflection;
using _0_Framework.Application.Sms;
using _0_Framework.Application;
using AccountManagement.Configuration;
@@ -31,6 +32,7 @@ using GozareshgirProgramManager.Application.Interfaces;
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;
@@ -40,24 +42,23 @@ using ServiceHost.Conventions;
using ServiceHost.Filters;
// ====================================================================
// FIX: Disable Static Web Assets in Docker/Production
// This prevents the error: DirectoryNotFoundException for NuGet packages path
// Static web assets are only needed in development, not in published apps
// FIX REMOVED: این بخش باعث می‌شد فایل‌های استاتیک در داکر پیدا نشوند
// ====================================================================
Environment.SetEnvironmentVariable("ASPNETCORE_HOSTINGSTARTUPASSEMBLIES", "");
// Environment.SetEnvironmentVariable("ASPNETCORE_HOSTINGSTARTUPASSEMBLIES", "");
var builder = WebApplication.CreateBuilder(args);
// Disable static web assets explicitly for non-development environments
if (!builder.Environment.IsDevelopment())
{
builder.Configuration["Microsoft.AspNetCore.Hosting.StaticWebAssets.UseStaticWebAssets"] = "false";
}
// ❌ این بخش هم حذف شد چون مانع لود شدن استاتیک فایل‌ها در پروداکشن می‌شود
// 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
@@ -97,12 +98,10 @@ Log.Logger = new LoggerConfiguration()
outputTemplate:
"{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level}] {Message}{NewLine}{Exception}"
)
// ✅ Console logging برای Docker - با فرمت پیش‌فرض ASP.NET Core
// ✅ Console logging برای Docker
.WriteTo.Console()
.CreateLogger();
#endregion
builder.Services.AddProgramManagerApplication();
@@ -110,6 +109,7 @@ 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");
@@ -137,8 +137,6 @@ builder.Services.AddTransient<IGoogleRecaptcha, GoogleRecaptcha>();
builder.Services.AddTransient<ISmsService, SmsService>();
builder.Services.AddTransient<IUidService, UidService>();
builder.Services.AddTransient<IFaceEmbeddingNotificationService, FaceEmbeddingNotificationService>();
//services.AddSingleton<IWorkingTest, WorkingTest>();
//services.AddHostedService<JobWorker>();
#region Mahan
@@ -160,7 +158,6 @@ builder.Services.Configure<FormOptions>(options =>
builder.Services.Configure<CookiePolicyOptions>(options =>
{
options.CheckConsentNeeded = context => true;
//options.MinimumSameSitePolicy = SameSiteMode.Strict;
});
var domain = builder.Configuration["Domain"];
@@ -184,8 +181,6 @@ builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationSc
o.ExpireTimeSpan = TimeSpan.FromHours(10);
o.SlidingExpiration = true;
});
//services.AddAuthorization(options =>
// options.AddPolicy("AdminArea", builder =>builder.RequireRole(Roles.role)));
builder.Services.AddAuthorization(options =>
{
@@ -217,14 +212,6 @@ builder.Services.AddAuthorization(options =>
builder => builder.RequireClaim("AdminAreaPermission", new List<string> { "true" }));
});
//services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
// .AddCookie(option =>
// {
// option.LoginPath = "/Index";
// option.LogoutPath = "/Index";
// option.ExpireTimeSpan = TimeSpan.FromDays(1);
// });
builder.Services.AddControllers(options =>
{
@@ -236,11 +223,6 @@ builder.Services.AddControllers(options =>
options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
});
//builder.Services.AddControllers(
//options=> {
// options.Filters.Add(new ApiJsonEnumFilter());
//});
builder.Services.AddRazorPages(options =>
options.Conventions.AuthorizeAreaFolder("Admin", "/", "AdminArea"));
@@ -256,21 +238,6 @@ builder.Services.AddSignalR();
#endregion
#region PWA
//old
//builder.Services.AddProgressiveWebApp();
//new
//builder.Services.AddProgressiveWebApp(new PwaOptions
//{
// RegisterServiceWorker = true,
// RegisterWebmanifest = true,
// Strategy = ServiceWorkerStrategy.NetworkFirst,
//});
#endregion
#region Swagger
builder.Services.AddSwaggerGen(options =>
@@ -282,7 +249,6 @@ builder.Services.AddSwaggerGen(options =>
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
options.IncludeXmlComments(xmlPath);
// Get XML comments from the class library
var classLibraryXmlFile = "CompanyManagment.App.Contracts.xml";
var classLibraryXmlPath = Path.Combine(AppContext.BaseDirectory, classLibraryXmlFile);
options.IncludeXmlComments(classLibraryXmlPath);
@@ -297,33 +263,6 @@ builder.Services.AddSwaggerGen(options =>
options.DocInclusionPredicate((docName, apiDesc) =>
string.Equals(docName, apiDesc.GroupName, StringComparison.OrdinalIgnoreCase));
// اضافه کردن پشتیبانی از JWT در Swagger
// options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
// {
// Name = "Authorization",
// Type = SecuritySchemeType.ApiKey,
// Scheme = "Bearer",
// BearerFormat = "JWT",
// In = ParameterLocation.Header,
// Description = "لطفاً 'Bearer [space] token' را وارد کنید."
// });
//
// options.AddSecurityRequirement(new OpenApiSecurityRequirement
// {
// {
// new Microsoft.OpenApi.Models.OpenApiSecurityScheme
// {
// Reference = new Microsoft.OpenApi.Models.OpenApiReference
// {
// Type = Microsoft.OpenApi.Models.ReferenceType.SecurityScheme,
// Id = "Bearer"
// }
// },
// Array.Empty<string>()
// }
// });
options.EnableAnnotations();
});
@@ -358,23 +297,6 @@ builder.Services.AddCors(options =>
});
});
//builder.Services.AddCors(options =>
//{
// options.AddPolicy("AllowAny", policy =>
// {
// policy.AllowAnyOrigin()
// .AllowAnyHeader()
// .AllowAnyMethod();
// });
// options.AddPolicy("AllowSpecificOrigins", policy =>
// {
// policy.WithOrigins("http://localhost:3000", "http://localhost:3001", "https://gozareshgir.ir", "https://dad-mehr.ir")
// .AllowAnyHeader()
// .AllowAnyMethod()
// .AllowCredentials();
// });
//});
#endregion
builder.Services.AddExceptionHandler<CustomExceptionHandler>();
@@ -406,7 +328,6 @@ builder.Host.UseSerilog((context, services, configuration) =>
.ReadFrom.Services(services)
.Enrich.FromLogContext();
// ✅ File logging (همیشه فعال)
logConfig.WriteTo.File(
path: Path.Combine(logDirectory, "gozareshgir_log.txt"),
rollingInterval: RollingInterval.Day,
@@ -415,20 +336,36 @@ builder.Host.UseSerilog((context, services, configuration) =>
outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level}] {Message}{NewLine}{Exception}"
);
// ✅ Console logging (برای Docker و Development) - با فرمت پیش‌فرض ASP.NET Core
logConfig.WriteTo.Console();
}, writeToProviders: true);
Log.Information("SERILOG STARTED SUCCESSFULLY");
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();
app.UseCors("AllowSpecificOrigins");
#region InternalProgarmManagerApi
app.Use(async (context, next) =>
{
var host = context.Request.Host.Host?.ToLower() ?? "";
@@ -449,21 +386,12 @@ app.Use(async (context, next) =>
await next.Invoke();
});
#endregion
#region Mahan
//app.UseStatusCodePagesWithRedirects("/error/{0}");
//the backend Tester
if (builder.Environment.IsDevelopment())
{
using var scope = app.Services.CreateScope();
var tester = scope.ServiceProvider.GetRequiredService<Tester>();
@@ -487,32 +415,26 @@ if (app.Environment.IsDevelopment())
}
#endregion
//Create Http Pipeline
#region Create Http Pipeline
app.UseForwardedHeaders();
if (builder.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
// The default HSTS value is 30 days. You may want to change this for pro
// The default HSTS value is 30 days.
app.UseHsts();
}
app.UseExceptionHandler(options => { }); // این خط CustomExceptionHandler رو فعال می‌کنه
app.UseRouting();
app.UseWebSockets();
app.UseAuthentication();
app.UseAuthorization();
app.UseExceptionHandler(options => { });
app.UseHttpsRedirection();
// ✅ FIX: UseStaticFiles must be BEFORE Routing and Auth
app.UseStaticFiles();
// Static files برای فایل‌های آپلود شده
@@ -528,13 +450,21 @@ app.UseStaticFiles(new StaticFileOptions
RequestPath = "/storage",
OnPrepareResponse = ctx =>
{
// Cache برای فایل‌ها (30 روز)
ctx.Context.Response.Headers.Append("Cache-Control", "public,max-age=2592000");
}
});
// ✅ Routing comes after Static Files
app.UseRouting();
app.UseWebSockets();
// ✅ Cookie Policy should be before Auth
app.UseCookiePolicy();
// ✅ Auth comes after Routing
app.UseAuthentication();
app.UseAuthorization();
#region Mahan
@@ -550,7 +480,6 @@ app.MapHub<CreateContractTarckingHub>("/trackingHub");
app.MapHub<SendAccountMessage>("/trackingSmsHub");
app.MapHub<HolidayApiHub>("/trackingHolidayHub");
app.MapHub<CheckoutHub>("/trackingCheckoutHub");
// app.MapHub<FaceEmbeddingHub>("/trackingFaceEmbeddingHub");
app.MapHub<SendSmsHub>("/trackingSendSmsHub");
app.MapHub<ProjectBoardHub>("api/pm/board");
app.MapRazorPages();
@@ -561,4 +490,4 @@ app.MapGet("/health", () => Results.Ok(new { status = "Healthy", timestamp = Dat
#endregion
app.Run();
app.Run();