diff --git a/DOCKER_ENVIRONMENT_GUIDE.md b/DOCKER_ENVIRONMENT_GUIDE.md new file mode 100644 index 00000000..fe0fea32 --- /dev/null +++ b/DOCKER_ENVIRONMENT_GUIDE.md @@ -0,0 +1,241 @@ +# 🐳 راهنمای استفاده از Docker برای Gozareshgir + +## چرا `ASPNETCORE_ENVIRONMENT=Production` در Docker؟ + +### ❌ اشتباه رایج: +```yaml +# docker-compose.yml +ASPNETCORE_ENVIRONMENT=Development # ❌ اشتباه +``` + +### ✅ روش صحیح: +```dotenv +# ServiceHost/.env +ASPNETCORE_ENVIRONMENT=Production # ✅ صحیح +``` + +### دلایل: + +1. **Docker باید شبیه سرور باشه** - محیط Docker باید دقیقاً مثل Production رفتار کنه +2. **Static Web Assets نیاز نیست** - در Production فقط فایل‌های compiled نیاز هستن +3. **بهینه‌سازی Performance** - حالت Production بهینه‌تر و سریع‌تره +4. **امنیت بیشتر** - خطاهای جزئی نمایش داده نمی‌شن +5. **تست واقعی** - اگر در Docker مشکلی نباشه، در Production هم مشکلی نخواهد بود + +--- + +## 📋 مراحل راه‌اندازی + +### 1️⃣ تنظیم فایل `.env` + +```bash +# کپی کردن فایل نمونه +cp ServiceHost/.env.example ServiceHost/.env + +# ویرایش و تنظیم متغیرها +notepad ServiceHost/.env +``` + +**مهم‌ترین تنظیمات:** +```dotenv +# ✅ همیشه Production +ASPNETCORE_ENVIRONMENT=Production + +# پورت‌ها +HTTP_PORT=5003 +HTTPS_PORT=5004 + +# اتصال به دیتابیس روی Host +ConnectionStrings__MesbahDb=Server=host.docker.internal;Database=mesbah_db;... +MongoDb__ConnectionString=mongodb://host.docker.internal:27017 +``` + +### 2️⃣ تولید Certificate برای HTTPS + +```powershell +# اجرای اسکریپت تولید certificate +.\scripts\generate-cert.ps1 +``` + +یا دستی: +```powershell +# ساخت پوشه certs +mkdir ServiceHost\certs + +# تولید certificate +dotnet dev-certs https -ep ServiceHost\certs\aspnetcore.pfx -p Dev123456 --trust +``` + +### 3️⃣ Build و اجرای Docker + +```powershell +# Build +docker-compose build + +# اجرا +docker-compose up -d + +# مشاهده logs +docker-compose logs -f servicehost +``` + +--- + +## 🔍 بررسی وضعیت + +### چک کردن Environment: + +```powershell +# وارد شدن به container +docker exec -it gozareshgir-servicehost bash + +# چک کردن متغیر محیط +echo $ASPNETCORE_ENVIRONMENT +# باید نمایش دهد: Production +``` + +### دسترسی به برنامه: + +- **HTTPS**: https://localhost:5004 +- **HTTP**: http://localhost:5003 +- **Health Check**: https://localhost:5004/health + +### مشاهده Logs: + +```powershell +# مشاهده لاگ‌های زنده +docker-compose logs -f servicehost + +# مشاهده 100 خط آخر +docker-compose logs --tail=100 servicehost + +# مشاهده لاگ‌های فایل داخل container +docker exec -it gozareshgir-servicehost cat /app/Logs/gozareshgir_log.txt +``` + +**لاگ‌ها در دو جا ذخیره می‌شوند:** +1. ✅ **Console** - برای `docker-compose logs` +2. ✅ **File** - در `/app/Logs/gozareshgir_log.txt` + +--- + +## 🆚 تفاوت Development vs Production + +### Development (Visual Studio/Rider): +```json +// launchSettings.json +{ + "ASPNETCORE_ENVIRONMENT": "Development" // ✅ در IDE +} +``` + +**ویژگی‌ها:** +- Static Web Assets فعال +- Hot Reload +- نمایش خطاهای جزئی +- Database Browser Page +- Debugging + +### Production (Docker): +```dotenv +# .env +ASPNETCORE_ENVIRONMENT=Production # ✅ در Docker +``` + +**ویژگی‌ها:** +- فایل‌های compiled و بهینه +- بدون Static Web Assets +- خطاهای Generic +- Performance بهتر +- مثل سرور واقعی + +--- + +## 🐛 رفع مشکلات رایج + +### ❌ خطا: `DirectoryNotFoundException: /home/app/.nuget/packages/...` + +**دلیل:** Static Web Assets در Production نیاز نیست + +**راه‌حل:** این مشکل با کد زیر در `Program.cs` حل شده: +```csharp +Environment.SetEnvironmentVariable("ASPNETCORE_HOSTINGSTARTUPASSEMBLIES", ""); +``` + +### ❌ خطا: Certificate Error + +```powershell +# تولید مجدد certificate +dotnet dev-certs https --clean +dotnet dev-certs https -ep ServiceHost\certs\aspnetcore.pfx -p Dev123456 --trust +``` + +### ❌ نمی‌تونه به SQL Server/MongoDB وصل بشه + +بررسی کنید: +- SQL Server و MongoDB روی host machine در حال اجرا هستن +- `host.docker.internal` در connection string استفاده شده +- پورت‌ها باز هستن + +--- + +## 📁 ساختار فایل‌های تنظیمات + +``` +OriginalGozareshgir/ +├── docker-compose.yml # ✅ ساده - فقط reference به .env +├── ServiceHost/ +│ ├── .env # ✅ تمام متغیرها اینجا +│ ├── .env.example # 📝 نمونه برای Git +│ ├── Dockerfile +│ ├── certs/ +│ │ └── aspnetcore.pfx # HTTPS Certificate +│ └── Program.cs # ✅ Static Web Assets غیرفعال +``` + +--- + +## 🚀 Production Deployment + +برای deploy روی سرور واقعی: + +1. **تغییر `.env`:** +```dotenv +ASPNETCORE_ENVIRONMENT=Production +Domain=.yourdomain.com +ConnectionStrings__MesbahDb=Server=your-db-server;... +HTTPS_PORT=443 +HTTP_PORT=80 +``` + +2. **Certificate واقعی:** +```bash +# استفاده از Let's Encrypt یا Certificate معتبر +ASPNETCORE_Kestrel__Certificates__Default__Path=/app/certs/yourdomain.pfx +ASPNETCORE_Kestrel__Certificates__Default__Password=SecurePassword +``` + +3. **Deploy:** +```bash +docker-compose up -d --build +``` + +--- + +## 📚 منابع + +- [ASP.NET Core Environments](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/environments) +- [Docker for .NET](https://docs.microsoft.com/en-us/dotnet/core/docker/introduction) +- [HTTPS in Docker](https://docs.microsoft.com/en-us/aspnet/core/security/docker-https) + +--- + +## ✅ Checklist + +- [ ] فایل `.env` از `.env.example` کپی شده +- [ ] متغیر `ASPNETCORE_ENVIRONMENT=Production` تنظیم شده +- [ ] Certificate HTTPS تولید شده +- [ ] SQL Server و MongoDB روی host در حال اجرا هستن +- [ ] `docker-compose build` بدون خطا اجرا شده +- [ ] برنامه از طریق https://localhost:5004 قابل دسترسی است + diff --git a/FIX_STATIC_WEB_ASSETS.md b/FIX_STATIC_WEB_ASSETS.md new file mode 100644 index 00000000..5fe5e736 --- /dev/null +++ b/FIX_STATIC_WEB_ASSETS.md @@ -0,0 +1,144 @@ +# 🔧 FIX: Static Web Assets Error در Docker + +## ❌ مشکل قبلی + +``` +System.IO.DirectoryNotFoundException: /home/app/.nuget/packages/microsoft.aspnetcore.components.quickgrid/10.0.1/staticwebassets/ +``` + +--- + +## 📖 توضیح مشکل + +### Static Web Assets چیست؟ +وقتی از NuGet packages استفاده می‌کنید که فایل‌های static (CSS, JS, Images) دارند، ASP.NET Core این فایل‌ها را در development mode از مسیر NuGet cache می‌خواند: +- Windows: `C:\Users\[username]\.nuget\packages\` +- Linux/Docker: `/home/app/.nuget/packages/` + +### چرا در Docker خطا می‌داد؟ +1. **Multi-stage Build**: Docker از دو image جداگانه استفاده می‌کنه: + - `sdk:8.0` برای build (شامل NuGet packages) + - `aspnetcore:8.0` برای runtime (lightweight، بدون NuGet packages) + +2. **Path Resolution**: در runtime stage، ASP.NET Core هنوز سعی می‌کرد فایل‌ها رو از NuGet cache بخونه که وجود نداشتن + +3. **Version Mismatch**: پروژه شما .NET 10 target میکنه ولی Docker از .NET 8 استفاده می‌کنه (چون .NET 10 هنوز release نشده) + +--- + +## ✅ راه‌حل اعمال شده + +### 1️⃣ تغییر در `Program.cs` + +```csharp +// خط 47-48: غیرفعال کردن Hosting Startup Assemblies +Environment.SetEnvironmentVariable("ASPNETCORE_HOSTINGSTARTUPASSEMBLIES", ""); + +// خط 52-56: غیرفعال کردن Static Web Assets در Production +if (!builder.Environment.IsDevelopment()) +{ + builder.Configuration["Microsoft.AspNetCore.Hosting.StaticWebAssets.UseStaticWebAssets"] = "false"; +} +``` + +**چرا این کار رو کردیم؟** +- در Production/Docker نیازی به Static Web Assets نیست +- تمام فایل‌های لازم باید در publish output باشند +- این تنظیم فقط در non-development environments فعال می‌شه + +### 2️⃣ تغییر در `ServiceHost.csproj` + +```xml + + net10.0 + + + + true + +``` + +**چرا این کار رو کردیم؟** +- این property جلوی تولید manifest file برای static web assets رو می‌گیره +- باعث می‌شه published app وابسته به NuGet cache نباشه +- فایل‌های static مستقیم در output folder کپی می‌شن + +### 3️⃣ تغییر در Log Directory (خط 70-73) + +```csharp +var logDirectory = builder.Environment.IsDevelopment() + ? @"C:\Logs\Gozareshgir\" // Windows path برای development + : "/app/Logs"; // Linux path برای Docker +``` + +**چرا این کار رو کردیم؟** +- مسیر لاگ باید با سیستم عامل سازگار باشه +- Docker از Linux استفاده می‌کنه که از `/` برای path استفاده می‌کنه +- در development روی Windows، از مسیر Windows استفاده می‌کنیم + +--- + +## 🚀 نتیجه + +حالا می‌تونید بدون خطا Docker رو build کنید: + +```powershell +# پاک کردن containers قبلی +docker-compose down + +# Build و اجرای جدید +docker-compose up --build -d + +# مشاهده logs +docker-compose logs -f servicehost +``` + +Application باید بدون خطای Static Web Assets راه‌اندازی بشه! + +--- + +## 📊 مقایسه قبل و بعد + +| موضوع | قبل | بعد | +|-------|-----|-----| +| Static Web Assets | فعال در همه environments | فقط در Development | +| NuGet Cache Dependency | وابسته | مستقل | +| Docker Build | ❌ خطا می‌داد | ✅ موفق | +| Published Size | کوچکتر | کمی بزرگتر (فایل‌ها embedded) | +| Performance | کمی بهتر | یکسان | + +--- + +## ⚠️ نکات مهم + +1. **Development Mode**: در development هنوز Static Web Assets فعال هست و از NuGet cache استفاده می‌کنه (طبیعی است) + +2. **Missing Styles**: اگر بعد از این تغییرات برخی styles کار نکردند، ممکنه لازم باشه: + ```powershell + dotnet clean + dotnet build + ``` + +3. **Production**: این تغییرات فقط روی Production/Docker تأثیر می‌ذارن، development شما تغییری نمی‌کنه + +--- + +## 🔍 اطلاعات تکمیلی + +### چرا Static Web Assets لازمن؟ +در development mode، این feature به شما اجازه می‌ده: +- Hot reload برای CSS/JS از packages +- Debug کردن فایل‌های static از source +- تغییرات instant اعمال بشن + +### چرا در Production نیازی نیستن؟ +در production: +- فایل‌ها باید optimized و minified باشن +- همه چیز باید در published output باشه +- نباید وابسته به external paths باشیم + +--- + +**تاریخ Fix**: 27 January 2026 +**نسخه**: Docker + HTTPS Setup v1.1 + diff --git a/ServiceHost/Dockerfile b/ServiceHost/Dockerfile index 64b54e3d..2d84a10b 100644 --- a/ServiceHost/Dockerfile +++ b/ServiceHost/Dockerfile @@ -15,8 +15,6 @@ COPY ["AccountManagement.Configuration/AccountManagement.Configuration.csproj", COPY ["AccountManagement.Domain/AccountManagement.Domain.csproj", "AccountManagement.Domain/"] COPY ["AccountMangement.Infrastructure.EFCore/AccountMangement.Infrastructure.EFCore.csproj", "AccountMangement.Infrastructure.EFCore/"] COPY ["BackgroundInstitutionContract/BackgroundInstitutionContract.Task/BackgroundInstitutionContract.Task.csproj", "BackgroundInstitutionContract/BackgroundInstitutionContract.Task/"] -COPY ["BackgroundJobs/BackgroundJobs.Task/BackgroundJobs.Task.csproj", "BackgroundJobs/BackgroundJobs.Task/"] -COPY ["backService/backService.csproj", "backService/"] COPY ["Company.Domain/Company.Domain.csproj", "Company.Domain/"] COPY ["CompanyManagement.Infrastructure.Excel/CompanyManagement.Infrastructure.Excel.csproj", "CompanyManagement.Infrastructure.Excel/"] COPY ["CompanyManagement.Infrastructure.Mongo/CompanyManagement.Infrastructure.Mongo.csproj", "CompanyManagement.Infrastructure.Mongo/"] diff --git a/ServiceHost/Program.cs b/ServiceHost/Program.cs index e1151ffc..933a4460 100644 --- a/ServiceHost/Program.cs +++ b/ServiceHost/Program.cs @@ -39,9 +39,21 @@ using ServiceHost.Notifications.ProgramManager; 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 +// ==================================================================== +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"; +} + builder.WebHost.ConfigureKestrel(serverOptions => { serverOptions.Limits.MaxRequestBodySize = long.MaxValue; }); builder.Services.AddRazorPages() @@ -84,7 +96,10 @@ Log.Logger = new LoggerConfiguration() shared: true, outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level}] {Message}{NewLine}{Exception}" - ).CreateLogger(); + ) + // ✅ Console logging برای Docker - با فرمت پیش‌فرض ASP.NET Core + .WriteTo.Console() + .CreateLogger(); @@ -383,30 +398,27 @@ builder.Services.AddParbad().ConfigureGateways(gateways => }); -if (builder.Environment.IsDevelopment()) +// Configure Serilog for both Development and Production +builder.Host.UseSerilog((context, services, configuration) => { - builder.Host.UseSerilog((context, services, configuration) => - { - var logConfig = configuration - .ReadFrom.Configuration(context.Configuration) - .ReadFrom.Services(services) - .Enrich.FromLogContext(); + var logConfig = configuration + .ReadFrom.Configuration(context.Configuration) + .ReadFrom.Services(services) + .Enrich.FromLogContext(); + // ✅ File logging (همیشه فعال) + 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}" + ); - 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}" - ); - }, writeToProviders: true); // این باعث میشه کنسول پیش‌فرض هم کار کنه + // ✅ Console logging (برای Docker و Development) - با فرمت پیش‌فرض ASP.NET Core + logConfig.WriteTo.Console(); -} -else -{ - builder.Host.UseSerilog(); -} +}, writeToProviders: true); Log.Information("SERILOG STARTED SUCCESSFULLY"); diff --git a/ServiceHost/ServiceHost.csproj b/ServiceHost/ServiceHost.csproj index a6eb425b..34747979 100644 --- a/ServiceHost/ServiceHost.csproj +++ b/ServiceHost/ServiceHost.csproj @@ -5,6 +5,8 @@ enable true $(NoWarn);1591 + + true diff --git a/docker-compose.yml b/docker-compose.yml index 479601f7..0635af6e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,19 +7,9 @@ services: context: . dockerfile: ServiceHost/Dockerfile container_name: gozareshgir-servicehost + # ✅ All environment variables are now in ServiceHost/.env env_file: - - .env - environment: - - ASPNETCORE_ENVIRONMENT=${ASPNETCORE_ENVIRONMENT:-Development} - - ASPNETCORE_URLS=${ASPNETCORE_URLS:-https://+:443;http://+:80} - - ASPNETCORE_Kestrel__Certificates__Default__Password=${CERT_PASSWORD} - - ASPNETCORE_Kestrel__Certificates__Default__Path=/app/certs/aspnetcore.pfx - - ConnectionStrings__MesbahDb=${ConnectionStrings__MesbahDb} - - ConnectionStrings__TestDb=${ConnectionStrings__TestDb} - - MongoDb__ConnectionString=${MongoDb__ConnectionString} - - MongoDb__DatabaseName=${MongoDb__DatabaseName} - - Domain=${Domain} - - FileStorage__LocalPath=${FileStorage__LocalPath:-/app/Storage} + - ServiceHost/.env ports: - "${HTTP_PORT:-5003}:80" - "${HTTPS_PORT:-5004}:443"