Skip to content

Commit 121d939

Browse files
DangDang
authored andcommitted
Make configuration validation flexible for deployment
- Only validate critical settings (MongoDB, JWT) as errors - Make Email and Cloudinary settings optional (warnings only) - Add deployment environment detection - Create Render.com deployment guide with required environment variables - Allow application to start with missing optional configuration
1 parent 39fa5f8 commit 121d939

File tree

2 files changed

+116
-31
lines changed

2 files changed

+116
-31
lines changed
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# Render.com Deployment Guide
2+
3+
## Quick Setup for Render.com
4+
5+
### 1. Set Required Environment Variables
6+
7+
In your Render.com dashboard, go to your service and add these **REQUIRED** environment variables:
8+
9+
```
10+
MONGODB_CONNECTION_STRING=mongodb+srv://username:[email protected]/VehicleShowroomDB
11+
JWT_KEY=your-super-secret-jwt-key-that-is-at-least-32-characters-long-for-security
12+
JWT_ISSUER=VehicleShowroomManagement
13+
JWT_AUDIENCE=VehicleShowroomManagement-Users
14+
```
15+
16+
### 2. Optional Environment Variables (for full functionality)
17+
18+
```
19+
EMAIL_SMTP_HOST=smtp.gmail.com
20+
EMAIL_SMTP_PORT=587
21+
22+
EMAIL_SMTP_PASSWORD=your-app-password
23+
24+
EMAIL_FROM_NAME=Vehicle Showroom Management
25+
26+
CLOUDINARY_CLOUD_NAME=your-cloud-name
27+
CLOUDINARY_API_KEY=your-api-key
28+
CLOUDINARY_API_SECRET=your-api-secret
29+
```
30+
31+
### 3. MongoDB Atlas Setup
32+
33+
1. Go to [MongoDB Atlas](https://www.mongodb.com/atlas)
34+
2. Create a free cluster
35+
3. Create a database user
36+
4. Get your connection string
37+
5. Set `MONGODB_CONNECTION_STRING` in Render.com
38+
39+
### 4. Generate JWT Key
40+
41+
Generate a secure JWT key (32+ characters):
42+
```bash
43+
# Option 1: Use online generator
44+
# Go to: https://generate-secret.vercel.app/32
45+
46+
# Option 2: Use PowerShell
47+
[System.Web.Security.Membership]::GeneratePassword(32, 0)
48+
```
49+
50+
### 5. Deploy
51+
52+
Once you've set the required environment variables, your application should deploy successfully!
53+
54+
## What's Fixed
55+
56+
- ✅ Configuration validation now only fails on critical settings (MongoDB, JWT)
57+
- ✅ Email and Cloudinary settings are optional (warnings only)
58+
- ✅ Better error messages and deployment guidance
59+
- ✅ Environment variable mapping improved
60+
61+
## Troubleshooting
62+
63+
If you still get errors:
64+
1. Check that all 4 required environment variables are set
65+
2. Verify MongoDB connection string is valid
66+
3. Ensure JWT key is at least 32 characters
67+
4. Check Render.com logs for specific error messages

VehicleShowroomManagement/src/Application/Common/Configuration/ConfigurationValidator.cs

Lines changed: 49 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,19 @@ public static async Task<bool> ValidateConfigurationAsync(IConfiguration configu
1717
{
1818
var isValid = true;
1919
var errors = new List<string>();
20+
var warnings = new List<string>();
2021

2122
try
2223
{
23-
// Validate MongoDB connection
24+
// Check if we're in a deployment environment (Docker/Production)
25+
var isDocker = Environment.GetEnvironmentVariable("DOTNET_RUNNING_IN_CONTAINER") == "true";
26+
var isProduction = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == "Production";
27+
var isDeployment = isDocker || isProduction;
28+
29+
logger.LogInformation("Configuration validation - Docker: {IsDocker}, Production: {IsProduction}, Deployment: {IsDeployment}",
30+
isDocker, isProduction, isDeployment);
31+
32+
// Validate MongoDB connection (CRITICAL - always required)
2433
var mongoConnectionString = configuration.GetConnectionString("MongoDB");
2534
if (string.IsNullOrWhiteSpace(mongoConnectionString))
2635
{
@@ -43,7 +52,7 @@ public static async Task<bool> ValidateConfigurationAsync(IConfiguration configu
4352
}
4453
}
4554

46-
// Validate JWT settings
55+
// Validate JWT settings (CRITICAL - always required)
4756
var jwtKey = configuration["Jwt:Key"];
4857
if (string.IsNullOrWhiteSpace(jwtKey))
4958
{
@@ -70,81 +79,90 @@ public static async Task<bool> ValidateConfigurationAsync(IConfiguration configu
7079
isValid = false;
7180
}
7281

73-
// Validate Email settings
82+
// Validate Email settings (OPTIONAL - warn but don't fail)
7483
var smtpHost = configuration["EmailSettings:SmtpHost"];
7584
if (string.IsNullOrWhiteSpace(smtpHost))
7685
{
77-
errors.Add("Email SMTP Host is missing");
78-
isValid = false;
86+
warnings.Add("Email SMTP Host is missing - email functionality will be disabled");
7987
}
8088

8189
var smtpPort = configuration["EmailSettings:SmtpPort"];
82-
if (!int.TryParse(smtpPort, out var port) || port < 1 || port > 65535)
90+
if (!string.IsNullOrWhiteSpace(smtpHost) && (!int.TryParse(smtpPort, out var port) || port < 1 || port > 65535))
8391
{
84-
errors.Add("Email SMTP Port must be a valid port number (1-65535)");
85-
isValid = false;
92+
warnings.Add("Email SMTP Port must be a valid port number (1-65535)");
8693
}
8794

8895
var smtpUsername = configuration["EmailSettings:SmtpUsername"];
89-
if (string.IsNullOrWhiteSpace(smtpUsername))
96+
if (string.IsNullOrWhiteSpace(smtpUsername) && !string.IsNullOrWhiteSpace(smtpHost))
9097
{
91-
errors.Add("Email SMTP Username is missing");
92-
isValid = false;
98+
warnings.Add("Email SMTP Username is missing - email functionality will be disabled");
9399
}
94100

95101
var smtpPassword = configuration["EmailSettings:SmtpPassword"];
96-
if (string.IsNullOrWhiteSpace(smtpPassword))
102+
if (string.IsNullOrWhiteSpace(smtpPassword) && !string.IsNullOrWhiteSpace(smtpHost))
97103
{
98-
errors.Add("Email SMTP Password is missing");
99-
isValid = false;
104+
warnings.Add("Email SMTP Password is missing - email functionality will be disabled");
100105
}
101106

102107
var fromEmail = configuration["EmailSettings:FromEmail"];
103-
if (string.IsNullOrWhiteSpace(fromEmail))
108+
if (string.IsNullOrWhiteSpace(fromEmail) && !string.IsNullOrWhiteSpace(smtpHost))
104109
{
105-
errors.Add("Email From Email is missing");
106-
isValid = false;
110+
warnings.Add("Email From Email is missing - email functionality will be disabled");
107111
}
108-
else if (!IsValidEmail(fromEmail))
112+
else if (!string.IsNullOrWhiteSpace(fromEmail) && !IsValidEmail(fromEmail))
109113
{
110-
errors.Add("Email From Email is not a valid email address");
111-
isValid = false;
114+
warnings.Add("Email From Email is not a valid email address");
112115
}
113116

114-
// Validate Cloudinary settings
117+
// Validate Cloudinary settings (OPTIONAL - warn but don't fail)
115118
var cloudName = configuration["CloudinarySettings:CloudName"];
116119
if (string.IsNullOrWhiteSpace(cloudName))
117120
{
118-
errors.Add("Cloudinary Cloud Name is missing");
119-
isValid = false;
121+
warnings.Add("Cloudinary Cloud Name is missing - image upload functionality will be disabled");
120122
}
121123

122124
var apiKey = configuration["CloudinarySettings:ApiKey"];
123-
if (string.IsNullOrWhiteSpace(apiKey))
125+
if (string.IsNullOrWhiteSpace(apiKey) && !string.IsNullOrWhiteSpace(cloudName))
124126
{
125-
errors.Add("Cloudinary API Key is missing");
126-
isValid = false;
127+
warnings.Add("Cloudinary API Key is missing - image upload functionality will be disabled");
127128
}
128129

129130
var apiSecret = configuration["CloudinarySettings:ApiSecret"];
130-
if (string.IsNullOrWhiteSpace(apiSecret))
131+
if (string.IsNullOrWhiteSpace(apiSecret) && !string.IsNullOrWhiteSpace(cloudName))
131132
{
132-
errors.Add("Cloudinary API Secret is missing");
133-
isValid = false;
133+
warnings.Add("Cloudinary API Secret is missing - image upload functionality will be disabled");
134134
}
135135

136136
// Log validation results
137137
if (isValid)
138138
{
139-
logger.LogInformation("All configuration settings validated successfully");
139+
logger.LogInformation("All critical configuration settings validated successfully");
140+
141+
if (warnings.Any())
142+
{
143+
logger.LogWarning("Configuration validation completed with {WarningCount} warnings", warnings.Count);
144+
foreach (var warning in warnings)
145+
{
146+
logger.LogWarning("Configuration Warning: {Warning}", warning);
147+
}
148+
}
140149
}
141150
else
142151
{
143-
logger.LogError("Configuration validation failed with {ErrorCount} errors", errors.Count);
152+
logger.LogError("Configuration validation failed with {ErrorCount} critical errors", errors.Count);
144153
foreach (var error in errors)
145154
{
146155
logger.LogError("Configuration Error: {Error}", error);
147156
}
157+
158+
if (warnings.Any())
159+
{
160+
logger.LogWarning("Additional configuration warnings:");
161+
foreach (var warning in warnings)
162+
{
163+
logger.LogWarning("Configuration Warning: {Warning}", warning);
164+
}
165+
}
148166
}
149167
}
150168
catch (Exception ex)

0 commit comments

Comments
 (0)