e5fe2f06e9
Add ConfigurationValidationRunner with IConfigurationValidator interface for validating required settings at startup. Includes SecureStore and LDAP validators. Expand ConfigManager with pipeline editing UI, dialogs, and step editors. Update documentation with config validation guidance.
306 lines
8.8 KiB
Markdown
306 lines
8.8 KiB
Markdown
# Configuration
|
|
|
|
The application uses standard ASP.NET Core configuration with `appsettings.json` and environment variables for sensitive values.
|
|
|
|
## appsettings.json Structure
|
|
|
|
```json
|
|
{
|
|
"ConnectionStrings": {
|
|
"SqlServer": "Server=localhost;Database=LotFinder;Integrated Security=true;TrustServerCertificate=true",
|
|
"JdeOracle": "Data Source=jde-server:1521/JDEPROD;User Id=${JDE_USER};Password=${JDE_PASSWORD}",
|
|
"CmsOracle": "Data Source=cms-server:1521/CMSPROD;User Id=${CMS_USER};Password=${CMS_PASSWORD}"
|
|
},
|
|
"DataSource": {
|
|
"UseFileDataSource": false,
|
|
"FileDirectory": "DevData"
|
|
},
|
|
"Auth": {
|
|
"UseFakeAuth": false
|
|
},
|
|
"Ldap": {
|
|
"Url": "LDAP://your-domain.com",
|
|
"BaseDn": "DC=your-domain,DC=com",
|
|
"RequiredGroup": "CN=LotFinderUsers,OU=Groups,DC=your-domain,DC=com"
|
|
},
|
|
"DataSync": {
|
|
"MassSchedule": "0 2 * * 0",
|
|
"DailySchedule": "0 3 * * *",
|
|
"HourlySchedule": "0 * * * *",
|
|
"BatchSize": 10000
|
|
},
|
|
"Search": {
|
|
"MaxResultRows": 100000,
|
|
"TimeoutSeconds": 300,
|
|
"MaxConcurrentSearches": 5
|
|
},
|
|
"Logging": {
|
|
"LogLevel": {
|
|
"Default": "Information",
|
|
"Microsoft.AspNetCore": "Warning"
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
## Environment Variables
|
|
|
|
Sensitive values are provided via environment variables at runtime:
|
|
|
|
| Variable | Purpose |
|
|
|----------|---------|
|
|
| `JDE_USER` | JDE Oracle username |
|
|
| `JDE_PASSWORD` | JDE Oracle password |
|
|
| `CMS_USER` | CMS Oracle username |
|
|
| `CMS_PASSWORD` | CMS Oracle password |
|
|
|
|
For local development, use User Secrets or a `.env` file (not committed to source control).
|
|
|
|
## Strongly-Typed Options
|
|
|
|
Configuration sections are bound to strongly-typed options classes:
|
|
|
|
```csharp
|
|
public class LdapOptions
|
|
{
|
|
public string Url { get; set; }
|
|
public string BaseDn { get; set; }
|
|
public string RequiredGroup { get; set; }
|
|
}
|
|
|
|
public class DataSyncOptions
|
|
{
|
|
public string MassSchedule { get; set; }
|
|
public string DailySchedule { get; set; }
|
|
public string HourlySchedule { get; set; }
|
|
public int BatchSize { get; set; } = 10000;
|
|
}
|
|
|
|
public class SearchOptions
|
|
{
|
|
public int MaxResultRows { get; set; } = 100000;
|
|
public int TimeoutSeconds { get; set; } = 300;
|
|
public int MaxConcurrentSearches { get; set; } = 5;
|
|
}
|
|
|
|
public class DataSourceOptions
|
|
{
|
|
public bool UseFileDataSource { get; set; } = false;
|
|
public string FileDirectory { get; set; } = "DevData";
|
|
}
|
|
|
|
public class AuthOptions
|
|
{
|
|
public bool UseFakeAuth { get; set; } = false;
|
|
}
|
|
```
|
|
|
|
Registered in `Program.cs`:
|
|
|
|
```csharp
|
|
builder.Services.Configure<LdapOptions>(builder.Configuration.GetSection("Ldap"));
|
|
builder.Services.Configure<DataSyncOptions>(builder.Configuration.GetSection("DataSync"));
|
|
builder.Services.Configure<SearchOptions>(builder.Configuration.GetSection("Search"));
|
|
builder.Services.Configure<DataSourceOptions>(builder.Configuration.GetSection("DataSource"));
|
|
builder.Services.Configure<AuthOptions>(builder.Configuration.GetSection("Auth"));
|
|
```
|
|
|
|
## Configuration Validation
|
|
|
|
The application validates configuration at startup using `ConfigurationValidationRunner`. This catches configuration errors early, before the application attempts to use misconfigured services.
|
|
|
|
### How validation works
|
|
|
|
1. The runner resolves all `IConfigurationValidator` implementations from DI
|
|
2. Validators execute in order (sorted by `Order` property, lower values run first)
|
|
3. Each validator returns a `ConfigurationValidationResult` with errors and warnings
|
|
4. Warnings are logged but don't prevent startup
|
|
5. Errors cause startup to fail with detailed logging
|
|
|
|
### Built-in validators
|
|
|
|
| Validator | Order | Purpose |
|
|
|-----------|-------|---------|
|
|
| `SecureStoreValidator` | 100 | Validates required secrets exist in the SecureStore |
|
|
| `LdapOptionsValidator` | 200 | Validates LDAP configuration settings |
|
|
|
|
### Creating a new validator
|
|
|
|
Implement `IConfigurationValidator` in `JdeScoping.Infrastructure/Validation/`:
|
|
|
|
```csharp
|
|
using JdeScoping.Core.Validation;
|
|
|
|
public class MyOptionsValidator : IConfigurationValidator
|
|
{
|
|
private readonly MyOptions _options;
|
|
|
|
public int Order => 300; // Run after existing validators
|
|
public string Name => "MyOptions";
|
|
|
|
public MyOptionsValidator(IOptions<MyOptions> options)
|
|
{
|
|
_options = options.Value;
|
|
}
|
|
|
|
public ConfigurationValidationResult Validate()
|
|
{
|
|
var result = new ConfigurationValidationResult(Name);
|
|
|
|
if (string.IsNullOrEmpty(_options.RequiredSetting))
|
|
result.AddError("RequiredSetting must be configured");
|
|
|
|
if (_options.Timeout < 1000)
|
|
result.AddWarning("Timeout below 1000ms may cause issues");
|
|
|
|
return result;
|
|
}
|
|
}
|
|
```
|
|
|
|
Register the validator in `DependencyInjection.cs`:
|
|
|
|
```csharp
|
|
services.AddSingleton<IConfigurationValidator, MyOptionsValidator>();
|
|
```
|
|
|
|
The runner automatically discovers and executes all registered validators.
|
|
|
|
### Validation result types
|
|
|
|
- **Errors** - Fatal configuration problems that prevent startup. Use `result.AddError()` for missing required settings, invalid values, or conditions that would cause runtime failures.
|
|
- **Warnings** - Non-fatal issues that should be logged but allow startup. Use `result.AddWarning()` for suboptimal settings or deprecated configurations.
|
|
|
|
### Order conventions
|
|
|
|
Follow these conventions for the `Order` property:
|
|
|
|
| Range | Purpose |
|
|
|-------|---------|
|
|
| 100 | Security/secrets (SecureStore) |
|
|
| 200 | Authentication (LDAP) |
|
|
| 300-399 | Data sources and connections |
|
|
| 400-499 | Service-specific validation |
|
|
| 500+ | Application-level validation |
|
|
|
|
Lower-ordered validators run first, allowing dependent validators to assume earlier validations passed.
|
|
|
|
## Data Source Configuration
|
|
|
|
The JDE and CMS data sources support two implementations:
|
|
|
|
| Implementation | Use Case |
|
|
|----------------|----------|
|
|
| Oracle (`JdeOracleDataSource`, `CmsOracleDataSource`) | Production - connects to Oracle databases |
|
|
| File (`JdeFileDataSource`, `CmsFileDataSource`) | Development - reads from exported JSON/CSV files |
|
|
|
|
### Development Setup
|
|
|
|
For development without Oracle access, set `UseFileDataSource: true` in `appsettings.Development.json`:
|
|
|
|
```json
|
|
{
|
|
"DataSource": {
|
|
"UseFileDataSource": true,
|
|
"FileDirectory": "DevData"
|
|
}
|
|
}
|
|
```
|
|
|
|
Place data export files in the `DevData` directory:
|
|
```
|
|
DevData/
|
|
├── workorders.json
|
|
├── lots.json
|
|
├── items.json
|
|
└── lotusage.json
|
|
```
|
|
|
|
### Registration Logic
|
|
|
|
```csharp
|
|
var dataSourceOptions = builder.Configuration
|
|
.GetSection("DataSource").Get<DataSourceOptions>();
|
|
|
|
if (dataSourceOptions?.UseFileDataSource == true || builder.Environment.IsDevelopment())
|
|
{
|
|
builder.Services.AddScoped<IJdeDataSource, JdeFileDataSource>();
|
|
builder.Services.AddScoped<ICmsDataSource, CmsFileDataSource>();
|
|
}
|
|
else
|
|
{
|
|
builder.Services.AddScoped<IJdeDataSource, JdeOracleDataSource>();
|
|
builder.Services.AddScoped<ICmsDataSource, CmsOracleDataSource>();
|
|
}
|
|
```
|
|
|
|
## Authentication Configuration
|
|
|
|
Authentication supports two implementations:
|
|
|
|
| Implementation | Use Case |
|
|
|----------------|----------|
|
|
| LDAP (`LdapAuthService`) | Production - authenticates against real LDAP server |
|
|
| Fake (`FakeAuthService`) | Development - accepts any non-empty credentials |
|
|
|
|
### Development Setup
|
|
|
|
For development without LDAP access, set `UseFakeAuth: true` in `appsettings.Development.json`:
|
|
|
|
```json
|
|
{
|
|
"Auth": {
|
|
"UseFakeAuth": true
|
|
}
|
|
}
|
|
```
|
|
|
|
The fake auth service:
|
|
- Accepts any non-empty username/password combination
|
|
- Returns the username as the display name
|
|
- Always returns `true` for group membership checks
|
|
|
|
### Registration Logic
|
|
|
|
```csharp
|
|
var authOptions = builder.Configuration
|
|
.GetSection("Auth").Get<AuthOptions>();
|
|
|
|
if (authOptions?.UseFakeAuth == true)
|
|
{
|
|
builder.Services.AddScoped<IAuthService, FakeAuthService>();
|
|
}
|
|
else
|
|
{
|
|
builder.Services.AddScoped<IAuthService, LdapAuthService>();
|
|
}
|
|
```
|
|
|
|
## Cron Expressions
|
|
|
|
Data sync schedules use cron expressions, parsed by the Cronos library:
|
|
|
|
| Expression | Meaning |
|
|
|------------|---------|
|
|
| `0 2 * * 0` | Sunday at 2:00 AM |
|
|
| `0 3 * * *` | Daily at 3:00 AM |
|
|
| `0 * * * *` | Every hour on the hour |
|
|
|
|
## Windows Service Installation
|
|
|
|
When installing as a Windows Service, environment variables can be set:
|
|
|
|
```powershell
|
|
# Create service
|
|
sc.exe create JdeScopingTool binPath= "C:\Services\JdeScoping\JdeScoping.Host.exe"
|
|
|
|
# Set environment variables for the service
|
|
$envVars = "JDE_USER=myuser`0JDE_PASSWORD=mypass`0CMS_USER=cmsuser`0CMS_PASSWORD=cmspass"
|
|
Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\JdeScopingTool" -Name "Environment" -Value $envVars
|
|
```
|
|
|
|
## Related Documentation
|
|
|
|
- [Host Project](./HostProject.md)
|
|
- [Data Flow](./DataFlow.md)
|