Skip to content

Architecture — Technology Stack

Everything below is read from the five .csproj files and Startup.cs. All five projects target net6.0.

Platform

Component Version Notes
.NET 6.0 <TargetFramework>net6.0</TargetFramework> in all five projects
ASP.NET Core MVC 6.0 Classic Program.cs + Startup.cs hosting model, not minimal APIs
Entity Framework Core 6.0.15 SQL Server provider. Lazy loading is not enabled — see the note below
Database SQL Server Two application databases plus a Hangfire store
Identity ASP.NET Core Identity 6.0.15 ApplicationUser, EF stores, custom ApplicationUserManager
View engine Razor with runtime compilation AddRazorRuntimeCompilation() — views can be edited without a rebuild

Packages by purpose

Data & identity

Package Version
Microsoft.EntityFrameworkCore · .Relational · .SqlServer · .Proxies · .Design · .Tools 6.0.15
Microsoft.AspNetCore.Identity.EntityFrameworkCore · Microsoft.Extensions.Identity.Stores 6.0.15
Microsoft.AspNetCore.Authentication.JwtBearer 6.0.15
BCrypt.Net-Next 4.0.2
IdentityModel 5.1.0

Passwords are hashed with BCrypt through a custom BCryptPasswordHasher rather than the Identity default. Note that it is not wired through DI: ApplicationUserManager's constructor assigns PasswordHasher = new BCryptPasswordHasher() directly, and the two services.AddTransient<BCryptPasswordHasher>() registrations in Startup.cs (the same line twice) are never resolved.

Lazy loading is referenced but never switched on

Microsoft.EntityFrameworkCore.Proxies is referenced, and the entity classes declare their navigation properties virtual as the proxy provider requires — but UseLazyLoadingProxies() is never called. Neither AddDbContext registration in Startup.cs enables it, and NKO_DBEntities1.OnConfiguring only calls ConfigureWarnings(...). Lazy loading is therefore off: an un-Included navigation property is null, not a database round-trip. Treat the package as part of R1-4 (referenced but unused), and assume every query must .Include(...) what it needs.

Background work — three schedulers

Package Version Used for
Quartz.AspNetCore 3.6.2 UpdateNextUserJob (daily 03:00) and ExportHistoryJob, wired in Program.cs
Hangfire.Core · Hangfire.AspNetCore 1.7.24 Fire-and-forget warehouse exports (BackgroundJob.Enqueue)
Hangfire.SqlServer 1.8.6 Job store — note the version gap against Hangfire 1.7.24
Cronos 0.7.1 Cron parsing for the hand-rolled IHostedService scheduler

Having three independent scheduling mechanisms in one application is unusual — see External Services.

Documents & reporting

Package Version Used for
EPPlus 6.1.3 Excel export — used in 9 files
DocumentFormat.OpenXml 2.19.0 Word/Office document generation
Rotativa.AspNetCore 1.2.0 PDF rendering via wkhtmltopdf — used in 22 files
QRCoder 1.4.1 QR codes on printed documents
System.Drawing.Common 6.0.0 Image handling — Windows-only from .NET 6 onward

AWS

Package Version Used for
AWSSDK.S3 3.7.103.21 Document storage behind IS3ServiceHandler
AWSSDK.Core · AWSSDK.Extensions.NETCore.Setup 3.7.x SDK plumbing
AWSSDK.SimpleNotificationService 3.7.101.20 Registered in DI but never injected anywhere

Web & UI

Package Version Used for
Microsoft.AspNetCore.Mvc.NewtonsoftJson 6.0.15 JSON with reference-loop handling
Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation 6.0.14 Runtime view compilation
X.PagedList · X.PagedList.Mvc.Core 8.4.6 / 8.4.5 The int? page paging on every grid
BuildBundlerMinifier 3.2.449 Static asset bundling
Microsoft.Extensions.FileProviders.Embedded 5.0.8 Serving views embedded in NKO.Shared

SignalR ships in the framework and is added with services.AddSignalR(); the hub is mapped at /hub.

Referenced but not used

Five dependencies are declared and never exercised. They still restore, compile in and enlarge the deployment.

Package Evidence
Microsoft.EntityFrameworkCore.Proxies 6.0.15 UseLazyLoadingProxies() appears nowhere in the solution, so the proxy provider is never activated despite the virtual navigation properties.
Refit 6.3.2 · Refit.HttpClientFactory 6.0.94 Zero Refit interfaces in the solution — no [Get("…")] / [Post("…")] attribute anywhere. Referenced by both NKO.Main and NKO.Shared; the only trace is a using Refit; in Startup.cs. Refit is not wired to anything.
Twilio 5.59.0 One stray using Twilio.Rest.Proxy.V1.Service.Session; in ProvidersController.cs. No SMS is ever sent.
MailKit 4.0.0 · MimeKit 4.0.0 Only using statements at the top of EmailManager.cs; the code below uses System.Net.Mail.SmtpClient.
AWSSDK.SimpleNotificationService IAmazonSimpleNotificationService appears once — its own registration in Startup.cs. Nothing resolves it, yet it builds an authenticated SNS client at startup.

Tracked as R1-4 in Recommendations.

Version consistency

ASP.NET Core 2.2 packages inside a .NET 6 application

Five Microsoft.AspNetCore.* packages are pinned at 2.2.x alongside the 6.0.15 ones — Mvc.Core 2.2.5, Http.Abstractions 2.2.0, Identity 2.2.0, Mvc.ViewFeatures 2.2.0 and Mvc.Razor.ViewCompilation 2.2.0. On net6.0 these types come from the shared framework, so referencing the old standalone packages risks duplicate-type and assembly-load conflicts. This is R7-13 in Recommendations.

Smaller drifts in the same family: Mvc.Razor.RuntimeCompilation is 6.0.14 while everything else Microsoft is 6.0.15, and Hangfire.SqlServer 1.8.6 runs against Hangfire.Core 1.7.24.

Build & tooling

  • Solution: NKO.Main/ERP-System.sln
  • Startup project: NKO.Main/NKO.Main
  • EF tooling: Microsoft.EntityFrameworkCore.Tools + a local .config/dotnet-tools.json; migrations must be applied per context (-Context NKO_DBEntities1 / -Context WarehouseDBContext)
  • Configuration: appsettings.json — not committed. appsettings.example.json shows the shape: three connection strings, StorageConfigs (region / clientId / clientSecret), SysUrl, logging levels and ScheduledJobsSettings.