414 lines
16 KiB
Markdown
414 lines
16 KiB
Markdown
# AOT Readiness Implementation Plan
|
|
|
|
## Overview
|
|
|
|
Make the JdeScopingTool .NET 10 solution ready for Native AOT compilation by addressing three critical areas:
|
|
1. **JSON Source Generation** - Replace reflection-based System.Text.Json with source generators
|
|
2. **Dapper AOT** - Enable compile-time SQL mapping generation
|
|
3. **Configuration Binding** - Replace reflection-based options binding and validation
|
|
|
|
**Current AOT Score:** ~25/100 (1 of 14 projects ready)
|
|
**Target AOT Score:** 90/100 (all projects AOT-compatible with known library exceptions)
|
|
|
|
---
|
|
|
|
## Current State Summary
|
|
|
|
### Projects by AOT Readiness
|
|
|
|
| Status | Project | Key Blockers |
|
|
|--------|---------|--------------|
|
|
| ✅ Ready | `JdeScoping.Domain` | None - pure domain models |
|
|
| ❌ Needs Work | `JdeScoping.DataAccess` | Dapper, SqlKata, Oracle driver |
|
|
| ❌ Needs Work | `JdeScoping.DataSync` | Dapper + STJ without source gen |
|
|
| ❌ Needs Work | `JdeScoping.Core` | STJ + Configuration.Binder |
|
|
| ❌ Needs Work | `JdeScoping.Infrastructure` | STJ + SecureStore + LDAP |
|
|
| ❌ Needs Work | `JdeScoping.Api` | STJ + Swashbuckle + config binding |
|
|
| ❌ Needs Work | `JdeScoping.Host` | Depends on API/DataSync |
|
|
| ❌ Needs Work | `JdeScoping.Client` | STJ + Radzen + SignalR |
|
|
| ❌ Needs Work | `JdeScoping.ExcelIO` | ClosedXML |
|
|
| ❌ Needs Work | `JdeScoping.Database` | dbup-sqlserver |
|
|
| ❌ Needs Work | ConfigManager.* | STJ + System.CommandLine + Avalonia |
|
|
|
|
### No Existing AOT Configuration
|
|
|
|
- No `PublishAot` property
|
|
- No `IsAotCompatible` markers
|
|
- No `TrimMode` settings
|
|
- No `[DynamicallyAccessedMembers]` attributes
|
|
- No `[RequiresUnreferencedCode]` attributes
|
|
|
|
---
|
|
|
|
## Phase 1: Solution-Wide AOT Configuration
|
|
|
|
### 1.1 Create Directory.Build.props
|
|
**File:** `NEW/src/Directory.Build.props` (new)
|
|
|
|
```xml
|
|
<Project>
|
|
<PropertyGroup>
|
|
<IsTrimmable>true</IsTrimmable>
|
|
<EnableTrimAnalyzer>true</EnableTrimAnalyzer>
|
|
<IsAotCompatible>true</IsAotCompatible>
|
|
<EnableAotAnalyzer>true</EnableAotAnalyzer>
|
|
<EnableConfigurationBindingGenerator>true</EnableConfigurationBindingGenerator>
|
|
<JsonSerializerIsReflectionEnabledByDefault>false</JsonSerializerIsReflectionEnabledByDefault>
|
|
</PropertyGroup>
|
|
</Project>
|
|
```
|
|
|
|
### 1.2 Update Host Project for AOT Publishing
|
|
**File:** `NEW/src/JdeScoping.Host/JdeScoping.Host.csproj`
|
|
|
|
Add:
|
|
```xml
|
|
<PropertyGroup>
|
|
<PublishAot Condition="'$(PublishAot)' == ''">false</PublishAot>
|
|
<PublishTrimmed Condition="'$(PublishTrimmed)' == ''">true</PublishTrimmed>
|
|
<TrimMode>partial</TrimMode>
|
|
</PropertyGroup>
|
|
```
|
|
|
|
---
|
|
|
|
## Phase 2: JSON Source Generation (~45 types)
|
|
|
|
### 2.1 Create JsonSerializerContext Classes
|
|
|
|
| Project | Context File | Types Count |
|
|
|---------|-------------|-------------|
|
|
| JdeScoping.Core | `Json/CoreJsonContext.cs` | ~30 (ViewModels, Auth, Search) |
|
|
| JdeScoping.DataSync | `Json/DataSyncJsonContext.cs` | ~6 (ETL pipeline configs) |
|
|
| JdeScoping.Api | `Json/ApiJsonContext.cs` | ~10 (FileUploadResult<T>, HealthCheck) |
|
|
| JdeScoping.Client | `Json/ClientJsonContext.cs` | ~15 (Client-side types) |
|
|
| ConfigManager.Core | `Json/ConfigManagerJsonContext.cs` | ~13 (ConfigModel sections) |
|
|
|
|
### 2.2 Types Requiring [JsonSerializable] Attributes
|
|
|
|
#### Core Authentication & Identity Types
|
|
- `UserInfoDto` - `JdeScoping.Core/Models/Auth/UserInfoDto.cs`
|
|
- `LoginResultModel` - `JdeScoping.Core/Models/Auth/LoginResultModel.cs`
|
|
- `LoginModel` - `JdeScoping.Core/Models/Auth/LoginModel.cs`
|
|
|
|
#### Search & Criteria Types
|
|
- `SearchCriteria` - `JdeScoping.Core/Models/Search/SearchCriteria.cs`
|
|
- `Search` - `JdeScoping.Core/Models/Search/Search.cs`
|
|
- `SearchViewModel` - `JdeScoping.Core/ViewModels/SearchViewModel.cs`
|
|
- `SearchUpdateViewModel` - `JdeScoping.Core/ViewModels/SearchUpdateViewModel.cs`
|
|
- `StatusUpdateViewModel` - `JdeScoping.Core/ViewModels/StatusUpdateViewModel.cs`
|
|
|
|
#### File Upload & Result Types
|
|
- `FileUploadResult<T>` - `JdeScoping.Client/Models/FileUploadResult.cs`
|
|
- `FileUploadResult<T>` - `JdeScoping.Api/Models/FileUploadResult.cs`
|
|
|
|
#### Data Sync & Manual Sync Types
|
|
- `ManualSyncRequestViewModel` - `JdeScoping.Api/Contracts/ManualSync/ManualSyncRequestViewModel.cs`
|
|
- `CreateManualSyncRequestDto` - `JdeScoping.Core/ViewModels/CreateManualSyncRequestDto.cs`
|
|
- `PipelineInfoViewModel` - `JdeScoping.Api/Contracts/ManualSync/PipelineInfoViewModel.cs`
|
|
|
|
#### ETL Pipeline Configuration Types
|
|
- `EtlPipelineConfig` - `JdeScoping.DataSync/Configuration/EtlPipelineConfig.cs`
|
|
- `SourceElement` - `JdeScoping.DataSync/Configuration/SourceElement.cs`
|
|
- `DestinationElement` - `JdeScoping.DataSync/Configuration/DestinationElement.cs`
|
|
- `TransformElement` - `JdeScoping.DataSync/Configuration/TransformElement.cs`
|
|
- `ScriptElement` - `JdeScoping.DataSync/Configuration/ScriptElement.cs`
|
|
- `ParameterElement` - `JdeScoping.DataSync/Configuration/ParameterElement.cs`
|
|
|
|
#### Configuration Model Types
|
|
- `ConfigModel` - `Utils/JdeScoping.ConfigManager.Core/Models/ConfigModel.cs`
|
|
- `ConnectionStringsSection` - `Utils/JdeScoping.ConfigManager.Core/Models/ConnectionStringsSection.cs`
|
|
- `ConnectionStringEntry` - `Utils/JdeScoping.ConfigManager.Core/Models/ConnectionStringEntry.cs`
|
|
|
|
#### Data ViewModels
|
|
- `WorkOrderViewModel`, `ItemViewModel`, `WorkCenterViewModel`, `ProfitCenterViewModel`
|
|
- `PartOperationViewModel`, `JdeUserViewModel`, `LotViewModel`, `ComponentLotViewModel`, `OperatorViewModel`
|
|
|
|
### 2.3 Key Files to Create
|
|
|
|
**`NEW/src/JdeScoping.Core/Json/CoreJsonContext.cs`** - Central context with:
|
|
- All ViewModels (SearchViewModel, WorkOrderViewModel, ItemViewModel, etc.)
|
|
- Auth models (UserInfoDto, LoginResultModel, LoginModel)
|
|
- SearchCriteria, ApiError, ValidationError
|
|
|
|
**`NEW/src/JdeScoping.DataSync/Json/DataSyncJsonContext.cs`**:
|
|
- EtlPipelineConfig, SourceElement, DestinationElement, TransformElement
|
|
|
|
**`NEW/src/JdeScoping.Api/Json/ApiJsonContext.cs`**:
|
|
- FileUploadResult<T> instantiations for each ViewModel type
|
|
- HealthCheckResponse (replace anonymous type)
|
|
|
|
### 2.4 Registration Updates
|
|
|
|
**`NEW/src/JdeScoping.Api/DependencyInjection.cs`** (line ~80):
|
|
```csharp
|
|
.AddJsonOptions(options =>
|
|
{
|
|
options.JsonSerializerOptions.TypeInfoResolverChain.Insert(0, CoreJsonContext.Default);
|
|
options.JsonSerializerOptions.TypeInfoResolverChain.Insert(0, ApiJsonContext.Default);
|
|
});
|
|
```
|
|
|
|
**`NEW/src/JdeScoping.Client/Services/ApiClientBase.cs`** (line ~16):
|
|
```csharp
|
|
private static readonly JsonSerializerOptions JsonOptions = new()
|
|
{
|
|
TypeInfoResolver = JsonTypeInfoResolver.Combine(
|
|
ClientJsonContext.Default,
|
|
CoreJsonContext.Default)
|
|
};
|
|
```
|
|
|
|
### 2.5 Fix Anonymous Type in Health Check
|
|
**`NEW/src/JdeScoping.Api/DependencyInjection.cs`** - Replace anonymous object with typed `HealthCheckResponse` class.
|
|
|
|
---
|
|
|
|
## Phase 3: Dapper AOT (15+ model types)
|
|
|
|
### 3.1 Dapper Usage Locations
|
|
|
|
| File | Dapper Methods | Model Types |
|
|
|------|---------------|-------------|
|
|
| `LotFinderRepository.SearchManagement.cs` | QueryAsync, QueryFirstOrDefaultAsync | Search |
|
|
| `LotFinderRepository.Lookups.cs` | QueryAsync | Item, Lot, WorkOrder, WorkCenter, ProfitCenter, JdeUser |
|
|
| `LotFinderRepository.DataSync.cs` | QueryAsync | DataUpdate |
|
|
| `SearchProcessor.cs` | QueryAsync, QuerySingleOrDefaultAsync | SearchResult, MisSearchResult, MisNonMatchSearchResult |
|
|
| `ManualSyncRequestService.cs` | QueryAsync, QuerySingleAsync, ExecuteAsync | ManualSyncRequest |
|
|
| `WorkOrderTraversalService.cs` | QuerySingleAsync | (int, int) tuple |
|
|
| `DataUpdateRepository.cs` | QueryAsync, ExecuteScalarAsync, ExecuteAsync | DataUpdate, (string, int, DateTime?, int) tuple |
|
|
| `SearchRepository.cs` | QueryFirstOrDefaultAsync, ExecuteAsync | Search |
|
|
|
|
### 3.2 Add Dapper.AOT Package
|
|
**Files:** `JdeScoping.DataAccess.csproj`, `JdeScoping.DataSync.csproj`
|
|
|
|
```xml
|
|
<PackageReference Include="Dapper.AOT" Version="1.0.48" />
|
|
<PropertyGroup>
|
|
<InterceptorsPreviewNamespaces>$(InterceptorsPreviewNamespaces);Dapper.AOT</InterceptorsPreviewNamespaces>
|
|
</PropertyGroup>
|
|
```
|
|
|
|
### 3.3 Enable AOT for Assemblies
|
|
**`NEW/src/JdeScoping.DataAccess/DapperAotConfiguration.cs`** (new):
|
|
```csharp
|
|
[assembly: DapperAot]
|
|
```
|
|
|
|
### 3.4 Fix Private Field Mapping Pattern
|
|
Change 6 models from private to internal for Dapper.AOT compatibility:
|
|
|
|
| Model | File |
|
|
|-------|------|
|
|
| Item | `Core/Models/Inventory/Item.cs` |
|
|
| Lot | `Core/Models/Inventory/Lot.cs` |
|
|
| WorkOrder | `Core/Models/WorkOrders/WorkOrder.cs` |
|
|
| WorkCenter | `Core/Models/Organization/WorkCenter.cs` |
|
|
| ProfitCenter | `Core/Models/Organization/ProfitCenter.cs` |
|
|
| JdeUser | `Core/Models/Organization/JdeUser.cs` |
|
|
|
|
Change:
|
|
```csharp
|
|
private int LastUpdateDate { get; set; } // Before
|
|
[Column("LastUpdateDate")]
|
|
internal int LastUpdateDate { get; set; } // After
|
|
```
|
|
|
|
### 3.5 Replace Tuple Queries with Named Types
|
|
Create explicit result types:
|
|
|
|
**`NEW/src/JdeScoping.DataAccess/Models/TraversalResult.cs`** (new):
|
|
```csharp
|
|
public sealed class TraversalResult
|
|
{
|
|
public int IterationsCompleted { get; init; }
|
|
public int TotalWorkOrders { get; init; }
|
|
}
|
|
```
|
|
|
|
**`NEW/src/JdeScoping.DataSync/Models/TableSyncStatusRow.cs`** (new):
|
|
```csharp
|
|
public sealed class TableSyncStatusRow
|
|
{
|
|
public string TableName { get; init; } = string.Empty;
|
|
public int UpdateType { get; init; }
|
|
public DateTime? LastSuccessfulSync { get; init; }
|
|
public int RecentFailures { get; init; }
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Phase 4: Configuration Binding
|
|
|
|
### 4.1 Options Classes Inventory
|
|
|
|
| Project | Options Class | Has DataAnnotations | Uses ValidateDataAnnotations |
|
|
|---------|--------------|---------------------|------------------------------|
|
|
| JdeScoping.Core | SecureStoreOptions | No | No |
|
|
| JdeScoping.Core | RsaKeyOptions | No | No |
|
|
| JdeScoping.Infrastructure | LdapOptions | Yes (1 Range) | No |
|
|
| JdeScoping.Api | AuthOptions | No | No |
|
|
| JdeScoping.DataAccess | DataAccessOptions | No | No |
|
|
| JdeScoping.DataAccess | SearchProcessingOptions | No | No |
|
|
| JdeScoping.DataAccess | SearchProcessingConfiguration | No | No |
|
|
| JdeScoping.DataSync | DataSyncOptions | Yes (6 Range) | **Yes** |
|
|
| JdeScoping.DataSync | WorkProcessorOptions | Yes (3 Range) | **Yes** |
|
|
| JdeScoping.ExcelIO | ExcelExportOptions | No | No |
|
|
| JdeScoping.DataSync.Dev | DevPipelineOptions | No | No |
|
|
|
|
### 4.2 Create AOT-Compatible Validators
|
|
Replace `ValidateDataAnnotations()` with `IValidateOptions<T>`:
|
|
|
|
**`NEW/src/JdeScoping.DataSync/Validation/DataSyncOptionsValidator.cs`** (new)
|
|
**`NEW/src/JdeScoping.DataSync/Validation/WorkProcessorOptionsValidator.cs`** (new)
|
|
|
|
### 4.3 Update DependencyInjection Files
|
|
|
|
**`NEW/src/JdeScoping.DataSync/DependencyInjection.cs`** (lines 27-36):
|
|
```csharp
|
|
// Before
|
|
.ValidateDataAnnotations()
|
|
|
|
// After
|
|
services.AddSingleton<IValidateOptions<DataSyncOptions>, DataSyncOptionsValidator>();
|
|
```
|
|
|
|
**`NEW/src/JdeScoping.Infrastructure/DependencyInjection.cs`** (lines 33-35):
|
|
Replace `GetSection().Get<T>()` with `GetSection().GetValue<T>()`.
|
|
|
|
**`NEW/src/JdeScoping.Api/DependencyInjection.cs`** (lines 33-35):
|
|
Replace `GetSection().Get<T>()` with explicit property binding.
|
|
|
|
### 4.4 Remove Unused Package
|
|
**`NEW/src/JdeScoping.DataSync/JdeScoping.DataSync.csproj`**:
|
|
Remove `Microsoft.Extensions.Options.DataAnnotations` reference.
|
|
|
|
---
|
|
|
|
## Phase 5: Third-Party Library Handling
|
|
|
|
### 5.1 Package Risk Assessment
|
|
|
|
| Risk Level | Packages |
|
|
|------------|----------|
|
|
| 🔴 High | Dapper (mitigated by Dapper.AOT), SqlKata, Swashbuckle, ClosedXML, dbup-sqlserver |
|
|
| 🟠 Medium | protobuf-net-data, System.CommandLine, SecureStore |
|
|
| 🟡 Low | Microsoft.Data.SqlClient, Oracle driver, LDAP, Serilog |
|
|
| 🟢 Safe | Cronos, OneOf (has source generator), ZstdSharp |
|
|
|
|
### 5.2 Create Trimmer Roots
|
|
**`NEW/src/JdeScoping.Host/TrimmerRoots.xml`** (new):
|
|
|
|
```xml
|
|
<linker>
|
|
<assembly fullname="Dapper">
|
|
<type fullname="Dapper.*" preserve="all" />
|
|
</assembly>
|
|
<assembly fullname="Oracle.ManagedDataAccess">
|
|
<type fullname="Oracle.ManagedDataAccess.*" preserve="all" />
|
|
</assembly>
|
|
<assembly fullname="ClosedXML">
|
|
<type fullname="ClosedXML.*" preserve="all" />
|
|
</assembly>
|
|
<assembly fullname="SqlKata">
|
|
<type fullname="SqlKata.*" preserve="all" />
|
|
</assembly>
|
|
</linker>
|
|
```
|
|
|
|
### 5.3 Known Limitations
|
|
These packages have partial/no AOT support - preserved via trimmer roots:
|
|
- ClosedXML (Excel generation)
|
|
- Oracle.ManagedDataAccess.Core
|
|
- dbup-sqlserver (migrations - dev only)
|
|
- Swashbuckle (Swagger - dev only)
|
|
|
|
---
|
|
|
|
## Implementation Sequence
|
|
|
|
| Step | Task | Files |
|
|
|------|------|-------|
|
|
| 1 | Create Directory.Build.props | 1 new |
|
|
| 2 | Create CoreJsonContext | 1 new |
|
|
| 3 | Create DataSyncJsonContext | 1 new |
|
|
| 4 | Create ApiJsonContext + HealthCheckResponse | 1 new |
|
|
| 5 | Create ClientJsonContext | 1 new |
|
|
| 6 | Create ConfigManagerJsonContext | 1 new |
|
|
| 7 | Update Api DependencyInjection (JSON registration) | 1 edit |
|
|
| 8 | Update ApiClientBase (JSON options) | 1 edit |
|
|
| 9 | Update PipelineRegistry (JSON options) | 1 edit |
|
|
| 10 | Add Dapper.AOT packages | 2 edits |
|
|
| 11 | Create DapperAotConfiguration | 1 new |
|
|
| 12 | Update 6 models (private→internal) | 6 edits |
|
|
| 13 | Create TraversalResult, TableSyncStatusRow | 2 new |
|
|
| 14 | Update tuple queries to use named types | 2 edits |
|
|
| 15 | Create DataSyncOptionsValidator | 1 new |
|
|
| 16 | Create WorkProcessorOptionsValidator | 1 new |
|
|
| 17 | Update DataSync DependencyInjection | 1 edit |
|
|
| 18 | Update Infrastructure DependencyInjection | 1 edit |
|
|
| 19 | Update Api DependencyInjection (config) | 1 edit |
|
|
| 20 | Update Host csproj (AOT settings) | 1 edit |
|
|
| 21 | Create TrimmerRoots.xml | 1 new |
|
|
| 22 | Remove DataAnnotations package | 1 edit |
|
|
|
|
**Total: 14 new files, 18 edits**
|
|
|
|
---
|
|
|
|
## Verification
|
|
|
|
### Build Verification
|
|
```bash
|
|
dotnet build NEW/JdeScoping.slnx
|
|
```
|
|
Should complete with no new errors.
|
|
|
|
### AOT Analysis
|
|
```bash
|
|
dotnet publish NEW/src/JdeScoping.Host -c Release -p:PublishAot=true --no-build
|
|
```
|
|
Check for AOT compatibility warnings.
|
|
|
|
### Trim Analysis
|
|
```bash
|
|
dotnet publish NEW/src/JdeScoping.Host -c Release -p:PublishTrimmed=true
|
|
```
|
|
Review trim warnings and verify TrimmerRoots coverage.
|
|
|
|
### Test Suite
|
|
```bash
|
|
dotnet test NEW/JdeScoping.slnx
|
|
```
|
|
All existing tests should pass.
|
|
|
|
### E2E Verification
|
|
Run Playwright tests to verify JSON serialization works end-to-end.
|
|
|
|
---
|
|
|
|
## Critical Files Summary
|
|
|
|
**New Files (14):**
|
|
- `NEW/src/Directory.Build.props`
|
|
- `NEW/src/JdeScoping.Core/Json/CoreJsonContext.cs`
|
|
- `NEW/src/JdeScoping.DataSync/Json/DataSyncJsonContext.cs`
|
|
- `NEW/src/JdeScoping.Api/Json/ApiJsonContext.cs`
|
|
- `NEW/src/JdeScoping.Client/Json/ClientJsonContext.cs`
|
|
- `NEW/src/Utils/JdeScoping.ConfigManager.Core/Json/ConfigManagerJsonContext.cs`
|
|
- `NEW/src/JdeScoping.DataAccess/DapperAotConfiguration.cs`
|
|
- `NEW/src/JdeScoping.DataAccess/Models/TraversalResult.cs`
|
|
- `NEW/src/JdeScoping.DataSync/Models/TableSyncStatusRow.cs`
|
|
- `NEW/src/JdeScoping.DataSync/Validation/DataSyncOptionsValidator.cs`
|
|
- `NEW/src/JdeScoping.DataSync/Validation/WorkProcessorOptionsValidator.cs`
|
|
- `NEW/src/JdeScoping.Host/TrimmerRoots.xml`
|
|
|
|
**Key Edits:**
|
|
- `NEW/src/JdeScoping.Api/DependencyInjection.cs` - JSON + config
|
|
- `NEW/src/JdeScoping.Client/Services/ApiClientBase.cs` - JSON options
|
|
- `NEW/src/JdeScoping.DataSync/DependencyInjection.cs` - Validators
|
|
- `NEW/src/JdeScoping.Infrastructure/DependencyInjection.cs` - Config binding
|
|
- `NEW/src/JdeScoping.Host/JdeScoping.Host.csproj` - AOT settings
|
|
- 6 model files for private→internal field change
|