Skip to main content

WepNG_MVC Evolution Plan: From Monolith to Modern Architecture

1. Executive Summary

The WepNG_MVC solution is a classic "Big Ball of Mud" Monolith:

  • Architecture: Tightly coupled (Controller -> Direct DB Access).
  • Logic: Scattered between "God Controllers" (e.g., HomeController.cs), "Transaction Scripts" (ComponentServices), and Views.
  • Quality: No automated testing found. Dead code and hardcoded IDs are prevalent.
  • Risk: High. Changing one part likely breaks another due to shared EITWEP.Model (God Object).

1.1 Risk Assessment

Risk CategorySeverityLikelihoodImpact DescriptionMitigation Strategy
RegressionCriticalHighTouching EITWEP.Model breaks WepNG_OMGT or WepNG_Public.Automated Regression Tests (Phase 1). Feature Toggles.
Data IntegrityHighMedium"Anemic" models rely on controllers for validation; missed validation leads to bad data.Move validation to Domain Entities (Phase 3).
Knowledge LossMediumHighLogic hidden in WepNG_Business (745 OMGT items) is undocumented."Archaeology" documentation during refactoring.
PerformanceHighMediumN+1 queries in loops and synchronous I/O block IIS.MiniProfiler & Async/Await (Phase 2).
ObsolescenceCriticalCertain.NET Framework 4.8 is a legacy platform. Risk of EOL/Security issues.Mandatory Migration to latest .NET (Active Support) via Hybrid Strangler.

[!NOTE] For a deep dive into the Core Engine architecture, see OMGT Module Analysis.

For a deep dive into the Back Office (Performance Bottleneck), see BO Module Analysis.


2. Pillar 1: Maintainability (Stop the Bleeding)

The immediate goal is to stabilize the codebase and enable safe refactoring.

Strategies

  1. The "Boy Scout" Rule:
    • Rule: Touch a file -> Clean it.
    • Action: Remove commented-out code (Git is your history). Fixing indentation.
  2. Introduce Automated Testing:
    • Problem: No safety net.
    • Action: Create a WepNG.Tests (xUnit/NUnit) project.
    • Start Small: Don't try to mock the DB yet. Test pure logic (static helpers, string manipulation, math).
  3. Static Analysis:
    • Tool: SonarQube or Roslyn Analyzers.
    • Goal: Identify "Dead Code", unused variables, and SQL injection risks.

Immediate "Quick Wins"

  • Delete WepNG_OMGT/Controllers/HomeController.cs commented blocks: It accounts for ~20-30% of the file size.
  • Centralize Strings/IDs: Move hardcoded IDs (e.g., 1788, "SE53224") to a Constants class or Configuration.

2.1 Concrete "Quick Wins" & Fixes

The code review revealed specific patterns that can be fixed immediately:

A. The "Swallow Exception" Pattern

Problem: 100+ occurrences of catch (Exception) { } or catch (Exception e) { // do nothing }. This hides bugs and makes debugging impossible. Example: WADataFeeder.cs, AspnetUserList.cs (Line 251). Fix: Remove the try/catch or at least log the exception.

B. Business Layer Leaking HTTP

Problem: WepNG_Business should be agnostic of the web context, but it's full of HttpContext.Current.Cache (2700+ hits). Example: AccomodationTypeNGList.cs (Line 124). Fix: Inject an ICacheProvider interface. This is required for Step 4 (Headless) and Step 1 (Unit Testing).

C. Hardcoded Paths ("It works on my machine")

Problem: Hardcoded C:\Temp\ paths will fail in containers or other servers. Example:

  • WepPartnerOMGTsController.cs: C:\Temp\partner_jsv.xlsx
  • KeyNoteNGsController.cs: c:\temp\ Fix: Use Server.MapPath or a configurable AppSetting.

D. The "Loop of Death" (OMGT Specific)

Problem: WepPartnerOMGTsController.Ts() iterates over all partners and calls a service that opens a new connection and saves changes for each one. Example: WepPartnerOMGTsController.cs (Line 30). Impact: 1000 Partners = 1000 DB Connections + 1000 Transactions. Fix: Batch processing or Stored Procedure.


3. Pillar 2: Performance (Bottlenecks & Modernization)

Current performance issues are likely due to synchronous I/O and N+1 queries in loops.

Strategies

  1. Profiling First:
    • Action: Install MiniProfiler in WepNG_OMGT.
    • Goal: Visualize the SQL generated by those foreach loops in Controllers.
  2. Async/Await Adoption:
    • Current: Synchronous actions block IIS threads. Task.Run is used in some services (e.g., ACLTestOMGTComponentService).
    • Decision (Jan 2026): While Task.Run has pitfalls in ASP.NET, it is kept for now as the benefits outweigh the immediate cons. See ADR-008 for details.
    • Target: Change ComponentService methods to EnsureAsync(). Convert Controllers to async Task<ActionResult>.
    • Guideline: See Async Strategy.
    • Tactical Plan: See Async Migration Plan for prioritized hotspots.
    • Evolution: For critical background tasks like payment processing, transition from Task.Run to formal Task Queues (e.g., Hangfire or external messaging) to ensure persistence and reliability.
  3. Database Optimization:
    • Finding: SolveFeeTitle iterates all CultureForLanguage and all OrderFeeLines. This is O(N*M) complexity.
    • Fix: Move batch processing logic to Stored Procedures or optimized LINQ queries (Server-side evaluation).

4. Pillar 3: Domain-Driven Design (DDD)

We cannot "install" DDD. We must extract it.

Current State

  • Anemic Domain Model: ACLTestOMGT is just data getters/setters.
  • Logic in UI: HomeController orchestrates business rules.

Transition Strategy

  1. Identify Bounded Contexts:
    • Core: OMGT (Order Management).
    • Support: CRM (Customer Relations), CMS (Content).
  2. The "Service Layer" Refactoring:
    • Stop: Writing logic in Controllers.
    • Start: Use the Command/Query Separation (CQS) pattern.
    • Example: Instead of HomeController.CopyTicketForGroup, create a CopyTicketCommand and a CopyTicketHandler.
  3. Rich Domain Models:
    • Move logic into the entity.
    • Before: if (order.Status == "Paid") { order.SendEmail(); } (in Controller)
    • After: order.MarkAsPaid(); (Entity method handles state change and triggers events).

5. Pillar 4: Headless & Decoupling (The Future)

Moving towards a frontend-agnostic backend.

Strategy: "API First"

  1. Stop adding MVC Views:
    • For new features, do NOT create a .cshtml file.
    • Create a REST API endpoint in WepNG_API (or a specific WepNG.ModernAPI project).
    • Create a client-side app (Vue/React) or even simple HTML/JS that consumes this API.
  2. Decouple the Monolith:
    • Treat WepNG_Business as a NuGet package (conceptually) used by the API.
    • The API should return DTOs (Data Transfer Objects), never Entity Framework entities (avoids Serialization loops and leaks).

6. Strategic Directive: Platform Lifecycle Management

To avoid the risk of operating on unsupported or vulnerable frameworks (End of Life - EOL), the project mandates a continuous update strategy.

Requirement: Stay on "Active Support" LTS

  • Current Status: Legacy Monolith on .NET Framework 4.8 (Supported but "Classic").
  • Target State: All new development (ModernAPI) must target the latest .NET Long Term Support (LTS) version (currently .NET 8, moving to .NET 10 etc.).
  • Policy:
    1. No New Legacy Code: New modules must not lock us further into .NET Framework 4.8.
    2. Proactive Upgrade: The WepNG.ModernAPI sidecar must be kept up-to-date with .NET LTS cycles to ensure access to latest security patches and performance improvements.

7. Database Health & "Blind Spots"

Why I didn't ask for access: Direct DB access is risky/blocked in many environments. I prioritized code analysis to see how the app interacts with it.

  • Findings from Code:
    • Context Size: WEPV2DataContext has 840+ DbSets. This is massive. Startup time is likely slow.
    • Hidden Logic: Database.SqlQuery<int>(sqlQuery) found in WADataFeeder.cs and OrderOMGTList.cs suggests strictly coupled SQL logic (potential stored procs or complex views) not visible in C#.
    • Relations: EF Navigation properties exist, but manual joins in LINQ (seen in HomeController) suggest indices might be missing or FKs are not trusted.
  • Blind Spots:
    • Stored Procedures: Are there 10 or 1000? Code calls them but doesn't define them.
    • Triggers: "Magic" data changes?
    • Data Volume: Is OrderOMGT 10k rows or 10M? (Affects migration strategy).

8. Alternative Options

What are we not doing?

Option A: The "Big Bang" Rewrite (Rejected)

  • Concept: Build WepNG_vNext from scratch in .NET 8.
  • Pros: Clean slate, latest tech.
  • Cons: High Fail Rate. Business logic is lost; years of debugging are discarded. Feature freeze required (impossible).

[!TIP] See the detailed Strangler Fig Pattern guide for comprehensive implementation steps specific to WepNG.

  • Concept: Build new features in a new WepNG.API and proxy traffic. Slowly kill the old app.
  • Pros: Low risk, immediate value.
  • Cons: Complexity of maintaining two systems (SSO, Data Sync).

6. Implementation Roadmap

Phase 1: Stabilization (Weeks 1-4)

  • Setup WepNG.Tests project.
  • Install MiniProfiler to identify worst offenders.
  • Clean HomeController (Delete dead code).

Phase 2: Pilot Refactoring (Weeks 5-8)

  • Pick ONE small feature (e.g., ACLTestOMGT).
  • Extract ACLTestOMGTComponentService logic into a Command Handler.
  • Write Unit Tests for the Handler.
  • Expose basic API endpoint for it.

Phase 3: Scaling (Month 3+)

  • Systematically apply "Async/Await".
  • Split WepNG_Business into separate libraries (Wep.Core.Orders, Wep.Core.Crm) to enforce separation.

Appendix A: Alignment with Internal Audit (Jan 2026)

Context: The Expected Architectural Audit established a "Renovate, Don't Demolish" baseline.

1. Analysis of "Microservices First"

Recommendation: REJECTED. Reasoning: Transforming a coupled Monolith with high Transaction Density (OrderMGT) into microservices would create a distributed distributed consistency nightmare.

  • Decision: Adhere to the Modular Monolith. We will split code namespaces, not physical servers.

2. Analysis of "Dockerization"

Recommendation: ACCEPTED (Hybrid Strategy). Reasoning:

  • Discovery: The Data Layer (EITWEP.Model) uses Entity Framework 6.4.4, which is compatible with .NET Standard 2.1. This unlocks .NET 8 on Linux.
  • Strategy: Adopt a Hybrid Strangler Fig approach.
    1. Containerize the Legacy Monolith (Windows Containers) for CI stability.
    2. Build new features in a side-by-side .NET 8 API (Linux Containers) sharing the Data Layer.
  • Detail: See Docker & .NET Migration Strategy for the complete roadmap.
  • Decision: Proceed with Phase 1 (Windows Containers for Build) immediately.

3. Analysis of "Continuous Deployment"

Recommendation: ACCEPTED (High Priority). Reasoning: This is the fundamental enabler for all future evolution. Without an automated pipeline verifying tests, every refactoring is a high-risk operation.