Skip to content

Latest commit

 

History

History
629 lines (481 loc) · 22.5 KB

File metadata and controls

629 lines (481 loc) · 22.5 KB

SKS_Blazor

Understanding the Necessary Changes for Blazor Compatibility

Document Date: March 13, 2026
Purpose: Explain why modifications were necessary to make the application work correctly in Blazor


Executive Summary

The SKS_Blazor application was originally migrated from VB6 to Winforms, and then to Blazor using automated conversion tools. While the code compiled successfully, critical data operations (adding, editing, deleting records) did not function correctly due to fundamental incompatibilities between desktop and web architectures.

SKS_Blazor_Modified solves some of these issues by implementing a manual data synchronization system that works reliably within Blazor's architecture, ensuring all CRUD operations function as expected in most scenarios.

Bottom Line: The original code appeared to work but silently failed during data operations.


The Fundamental Problem: Why the Original Code Doesn't Work

Architecture Mismatch

The original SKS_Blazor code relied on ADO (ActiveX Data Objects) data binding, a technology designed for desktop Windows applications. When running in Blazor (a web framework), these data bindings do not function.

Desktop (WinForms) Architecture

┌─────────────────────────────────┐
│      Single Process             │
│  UI ←─────────→ Database        │
│  (Direct memory connection)     │
└─────────────────────────────────┘

Works: UI controls directly connected to data through memory references.

Blazor (Web) Architecture

┌──────────────┐         ┌──────────────┐
│   Browser    │         │    Server    │
│   (UI)       │ ←───→   │  (Database)  │
│              │ Network │              │
└──────────────┘         └──────────────┘

Doesn't Work: UI and data are separated, ADO bindings cannot bridge this gap.


Specific Problems in the Original Code

Problem 1: Adding New Records Fails

What Should Happen:

  1. User clicks "Add" button
  2. Form clears, ready for input
  3. User enters data
  4. User clicks "Save"
  5. New record saved to database

What Actually Happens in SKS_Blazor:

  1. User clicks "Add" button
  2. Form STILL shows old record data (bindings don't clear controls)
  3. User enters data in some fields
  4. User clicks "Save"
  5. Empty or incomplete record saved (bindings don't capture user input)
  6. Data loss occurs

Root Cause: Recordset.AddNew() and DataBindings don't work together in Blazor.


Problem 2: Editing Records Doesn't Save Changes

What Should Happen:

  1. User navigates to record #5
  2. User changes "Company Name" from "Acme Corp" to "Acme Corporation"
  3. User clicks "Save"
  4. Database updated with new name

What Actually Happens in SKS_Blazor:

  1. User navigates to record #5
  2. User changes "Company Name" text
  3. User clicks "Save"
  4. Original value "Acme Corp" saved (bindings don't capture edits)
  5. User changes lost

Root Cause: Two-way DataBindings (DataSourceUpdateMode.OnPropertyChanged) are non-functional in Blazor.


Problem 3: Navigation Doesn't Update Display

What Should Happen:

  1. User viewing record #5 ("Acme Corp")
  2. User clicks "Next" button
  3. Form displays record #6 ("Beta Inc")

What Actually Happens in SKS_Blazor:

  1. User viewing record #5 ("Acme Corp")
  2. User clicks "Next" button
  3. Form still displays record #5 (UI doesn't refresh)
  4. Database cursor moved to #6, but user sees #5
  5. User confusion and potential data corruption

Root Cause: Moving the recordset cursor doesn't trigger UI updates in Blazor.


Problem 4: Deleting Last Record Causes Crashes

What Should Happen:

  1. One record remains in database
  2. User deletes it
  3. Form clears, showing empty state

What Actually Happens in SKS_Blazor:

  1. One record remains in database
  2. User deletes it
  3. Form still shows deleted record data
  4. User tries to navigate
  5. Application crashes (trying to access non-existent records)

Root Cause: No logic to handle empty recordset scenario.


The Solution: SKS_Blazor_Modified's Manual Synchronization

SKS_Blazor_Modified replaces the broken automatic data binding with a manual synchronization framework that explicitly controls data flow between the UI and database.

Key Components Added

1. Data Binding Helper Methods (modFunctions.cs)

BindValuesToControls() - Displays Data

  • Reads data from database record
  • Sets values in UI controls (TextBoxes, CheckBoxes)
  • Called whenever navigation occurs
  • Replaces: Broken automatic data binding

SynchronizeData() - Captures Edits

  • Reads values from UI controls
  • Writes to database record in memory
  • Called as user types (real-time sync)
  • Replaces: Broken two-way binding

QueryToInsert() - Saves New Records

  • Reads all field values from UI controls
  • Generates SQL INSERT statement
  • Executes directly against database
  • Replaces: Broken Recordset.AddNew() method

EmptyControls() - Clears Form

  • Clears all UI controls to empty/default state
  • Called before adding new record
  • Called when no records remain after deletion
  • Replaces: Non-functional automatic clearing

2. Form-Level Enhancements

DataPointer System - Navigation Control

  • Tracks current record position (0-based index)
  • Validates navigation bounds (prevents crashes)
  • Automatically refreshes UI when changed
  • Replaces: Unreliable ADO cursor

InfoToBind Dictionary - Field Mapping

  • Maps database field names to UI controls
  • Centralized configuration in one place
  • Used by all synchronization methods
  • Replaces: 15 individual DataBinding calls per form

Lifecycle Methods - State Management

  • BeforeInsert(): Prepares form for new record entry
  • AfterInsert(): Executes INSERT with auto-generated values
  • AfterDelete(): Handles empty recordset or navigation
  • Provides: Hooks for validation and business logic

Why These Changes Are Essential

1. The Original Code Silently Fails

The most dangerous aspect of SKS_Blazor is that it appears to work at first glance:

  • Application starts without errors
  • Forms load and display data
  • Buttons are clickable

However, when users actually try to work with data:

  • New records aren't saved properly
  • Edits are lost
  • Navigation shows wrong data
  • Deletions can crash the application

This silent failure mode is unacceptable for production use.

2. No Workaround for ADO Bindings

The ADO data binding infrastructure expects:

  • Synchronous, in-process data access
  • Direct memory connections between UI and data
  • Windows Forms event model

Blazor provides:

  • Asynchronous, network-based data access
  • Separation between client (UI) and server (data)
  • Component-based rendering model

These are fundamentally incompatible. There is no configuration or patch that makes ADO bindings work in Blazor—the architecture mismatch is absolute.

3. Manual Synchronization Is the Industry Standard

Modern web frameworks (React, Angular, Vue, Blazor) all use explicit data synchronization rather than automatic bindings for complex scenarios:

  • React: Manual state management (useState, useEffect)
  • Angular: Explicit template bindings and services
  • Vue: Reactive data with watchers
  • Blazor: Component parameters and state management

SKS_Blazor_Modified's approach aligns with modern web development best practices.

4. Enables Business-Critical Features

Manual synchronization provides control needed for:

  • Validation: Check data before saving
  • Audit Logging: Record who changed what and when
  • Business Rules: Enforce complex logic during CRUD operations
  • Computed Fields: Calculate values during save
  • Transactions: Coordinate multiple operations

These features are difficult or impossible with automatic bindings.


Why It's Important to Remove ADO from Blazor

While SKS_Blazor3 works around ADO limitations through manual synchronization, eliminating ADO dependency entirely should be a strategic priority for long-term application health. Here's why:

1. ADO is Obsolete Legacy Technology

Historical Context:

  • ADO (ActiveX Data Objects) was released by Microsoft in 1996 - nearly 30 years ago
  • Designed for Visual Basic 6 and Classic ASP (pre-.NET technologies)
  • Last major update was 2000 (ADO 2.6)
  • Microsoft officially deprecated ADO in favor of ADO.NET when .NET Framework launched in 2002

Current Status:

  • No longer actively developed by Microsoft
  • No support for modern features (async/await, LINQ, Entity Framework)
  • Security vulnerabilities cannot be patched (no active maintenance)
  • Performance limitations compared to modern data access libraries
  • Not designed for cloud or distributed architectures

The Problem: Running a 30-year-old data access technology in a modern web application is like using a rotary phone in a smartphone world—it technically works but introduces severe limitations.


2. Technical Debt and Maintenance Burden

Immediate Issues:

  • Complex Workarounds Required: SKS_Blazor3's manual synchronization exists solely to compensate for ADO's incompatibility
  • Extra Code to Maintain: Every form needs DataPointer, InfoToBind, BindInfo(), lifecycle methods—all overhead to work around ADO
  • Debugging Complexity: Issues require understanding both modern Blazor AND legacy ADO behavior
  • Knowledge Scarcity: Fewer developers understand ADO (it's not taught in modern courses)

Long-Term Costs:

Current Architecture:
┌─────────────────────────────────────────────┐
│  Blazor Application                         │
│                                             │
│  ┌──────────────┐    ┌──────────────┐     │
│  │   Modern     │───►│   Legacy     │     │
│  │   Blazor     │    │    ADO       │     │
│  │   Code       │◄───│  Wrappers    │     │
│  └──────────────┘    └──────────────┘     │
│         ▲                    ▼              │
│         │                    │              │
│         └────────────────────┘              │
│        Synchronization Overhead             │
└─────────────────────────────────────────────┘

Maintenance Burden:

  • Every new form requires implementing the same ADO workaround patterns
  • Bug fixes may need changes in both Blazor code AND ADO compatibility layer
  • Testing requires validating both the application logic AND the ADO bridge
  • Developer onboarding takes longer (need to learn legacy patterns)

3. Performance and Scalability Limitations

ADO Performance Issues in Web Applications:

Aspect ADO Behavior Impact on Blazor
Connection Model Designed for single-user desktop apps Poor connection pooling in multi-user web scenarios
Data Transfer Fetches entire recordsets into memory Excessive memory usage with large datasets
Cursor Operations Client-side cursors (MoveNext, etc.) Unnecessary overhead when you just need one record
Network Round-trips Not optimized for network latency Slower than modern ORMs with query optimization
Concurrent Users Not designed for this scenario Locking issues, connection exhaustion

Real-World Example:

Desktop App (ADO's design target):
- 1 user, local database, direct connection
- Recordset with 100 rows loads in memory: 50KB
- Acceptable performance

Web App with ADO (current situation):
- 50 concurrent users
- Each loads recordset: 50KB × 50 = 2.5MB
- Most data never displayed (pagination shows 10 rows)
- Wasted bandwidth, memory, processing

Modern Alternative (Entity Framework Core, Dapper):

- Load only needed records: 10 rows = 5KB
- 50 users: 5KB × 50 = 250KB (90% reduction)
- Proper connection pooling
- Async operations (don't block threads)
- Query optimization (load related data efficiently)

4. Security and Compliance Risks

Critical Security Concerns:

A. Unmaintained Code = Security Vulnerabilities

  • ADO has known security issues that will never be patched
  • SQL injection vulnerabilities in legacy ADO code
  • No built-in protection against modern attack vectors
  • Compliance frameworks (SOC 2, ISO 27001) require using actively maintained components

B. Connection String Exposure

// ADO pattern (exposed in multiple places):
dcCustomers.ConnectionString = modMain.ConnectionString;
  • Connection strings scattered throughout codebase
  • Difficult to centralize and secure
  • Hard to rotate credentials
  • Audit trail challenges

C. Direct SQL Generation Risk

// Current QueryToInsert() approach:
string sql = "INSERT INTO Customers (Name) VALUES ('" + txtName.Text + "')";
// Vulnerable to SQL injection if not careful

Modern Secured Approach:

// Entity Framework / Dapper with parameterized queries:
await context.Customers.AddAsync(new Customer { Name = txtName.Text });
// Automatic SQL injection prevention
// Built-in security best practices

5. Incompatibility with Modern Cloud Platforms

Cloud-Native Requirements:

Requirement ADO Support Modern ORM Support Business Impact
Azure SQL Limited Full Can't use cloud database features
Cosmos DB None Yes No NoSQL option
Connection Resilience Manual Built-in More downtime
Auto-scaling Poor Excellent Can't handle traffic spikes
Managed Identity No Yes Security risk, credential management
Multi-region No Yes Poor disaster recovery

Example Scenario:

Business Need: Deploy to Azure with auto-scaling

With ADO:
❌ Manual connection management
❌ Connection leaks under load
❌ No automatic retry on transient failures
❌ Can't use Azure Managed Identity (must store credentials)
❌ Poor performance under scale-out

With Entity Framework Core:
✅ Automatic connection pooling
✅ Built-in retry logic
✅ Azure Managed Identity support
✅ Efficient under horizontal scaling
✅ Connection resilience patterns

6. Developer Productivity and Modern Features

What You CAN'T Do with ADO:

A. Modern Query Patterns

// Impossible with ADO:
var activeCustomers = await context.Customers
    .Where(c => c.Status == "Active")
    .Include(c => c.Orders)
    .OrderBy(c => c.CompanyName)
    .Take(10)
    .ToListAsync();

// With ADO - must do manually:
ExecuteSql("SELECT * FROM Customers WHERE Status = 'Active'");
// Then manually sort, filter, paginate in memory
// Then manually load related Orders with separate query
// Much more code, much slower

B. Type Safety

// ADO - runtime errors:
string name = recordset["CompanyName"];  // Typo? Won't know until runtime
int customerId = (int)recordset["CustomerID"];  // Wrong type? Crash at runtime

// Entity Framework - compile-time safety:
string name = customer.CompanyName;  // Typo caught by compiler
int customerId = customer.CustomerId;  // Type mismatch caught by compiler

C. Async/Await Support

// ADO - blocks threads (scalability killer):
ExecuteSql("SELECT * FROM Customers");  // Thread blocked waiting for database

// Modern - async (better scalability):
await context.Customers.ToListAsync();  // Thread released while waiting

7. Future-Proofing and Technology Evolution

The Technology Landscape is Moving On:

2026 Reality:

  • Blazor framework updates every 6 months (actively developed)
  • .NET releases annually with new features
  • Cloud platforms add new capabilities monthly
  • ADO last updated: 2000 (26 years ago)

Risk of Being Left Behind:

  • ⚠️ Future .NET versions may drop ADO COM interop entirely
  • ⚠️ Modern developers won't want to work with obsolete tech
  • ⚠️ Recruitment difficulty (job candidates prefer modern stacks)
  • ⚠️ Integration challenges with new services/APIs

Investment Protection:

Keeping ADO:
├─ Every enhancement requires ADO workarounds
├─ Technology gap widens over time
├─ Eventually forced to rewrite anyway (at higher cost)
└─ Application becomes "legacy" and difficult to maintain

Migrating Away from ADO:
├─ Upfront effort (one-time cost)
├─ Unlock modern capabilities
├─ Easier maintenance going forward
└─ Application stays current with technology evolution

8. Business Case for ADO Removal

Cost-Benefit Analysis:

Costs of KEEPING ADO:

  • 🔴 Ongoing: Manual workaround code for every form (developer hours)
  • 🔴 Ongoing: Slower performance (poor user experience, lost productivity)
  • 🔴 Risk: Security vulnerabilities (potential breach, compliance failures)
  • 🔴 Risk: Cloud migration blockers (can't leverage modern infrastructure)
  • 🔴 Future: Eventually mandatory anyway when ADO is removed from .NET

Benefits of REMOVING ADO:

  • 🟢 Immediate: Eliminate manual synchronization code (~40% code reduction)
  • 🟢 Immediate: Better performance and scalability
  • 🟢 Immediate: Modern development practices (faster feature development)
  • 🟢 Ongoing: Reduced maintenance burden
  • 🟢 Strategic: Cloud-ready architecture
  • 🟢 Strategic: Attractive technology stack for talent recruitment

ROI Timeline:

Time →
│
│ Cost of Keeping ADO (orange line grows)
│     ╱
│   ╱
│ ╱
├─────────────────────
│ ╲
│   ╲  Cost of Migration (one-time, then lower)
│     ╲___________
│
└──────────────────────────────────
  Now  1yr  2yr  3yr  4yr  5yr

Break-even point: ~18 months
After that: continuous savings + benefits

9. Recommended Migration Path

Phase 1: Assessment (Current State)

  • ✅ You have working ADO workarounds (SKS_Blazor3)
  • ✅ Application is functional for production
  • ⚠️ But carries technical debt of ADO compatibility layer

Phase 2: Plan Modern Data Access (Next Step)

  • Evaluate modern ORMs: Entity Framework Core, Dapper, or micro-ORMs
  • Design data access layer separate from UI (proper architecture)
  • Create migration roadmap (form by form, or full rewrite)

Phase 3: Gradual Migration (Recommended)

Option A: Form-by-Form Migration
├─ Convert one form to modern ORM
├─ Test thoroughly
├─ Repeat for next form
├─ Both systems coexist during transition
└─ Lower risk, gradual learning curve

Option B: Complete Rewrite
├─ Design modern architecture from scratch
├─ Migrate all forms at once
├─ Big-bang deployment
└─ Higher risk, but cleaner result

Phase 4: Completion

  • Remove all ADO dependencies
  • Delete compatibility layer code
  • Update documentation
  • Train team on modern patterns

10. Summary: Why ADO Removal Matters

Concern Impact with ADO Impact without ADO
Reliability 🟡 Works but requires workarounds 🟢 Native framework support
Performance 🔴 Poor for web scenarios 🟢 Optimized for modern apps
Security 🔴 Unmaintained, vulnerable 🟢 Active security updates
Cloud Ready 🔴 Limited compatibility 🟢 Full platform support
Maintainability 🔴 High complexity 🟢 Standard patterns
Developer Experience 🔴 Requires legacy knowledge 🟢 Modern, well-documented
Future Proof 🔴 Technology sunset 🟢 Active development
Cost 🔴 High ongoing burden 🟢 One-time migration, then reduced

Bottom Line:

  • Short-term: SKS_Blazor3 makes the app work (addressing immediate crisis)
  • Long-term: Removing ADO is essential for maintainability, security, and competitive positioning
  • Recommendation: Plan ADO removal as next major initiative after initial deployment

Evidence from the Code

Throughout the SKS_Blazor3 codebase, you'll find comments documenting known issues:

// gap-todo: PBI 746470. Add support for the control UpgradeHelpers.DB.ADO.ADODataControlHelper.

This comment appears 8 times across multiple form Designer files, confirming:

  1. ✅ ADODataControlHelper has known limitations in Blazor
  2. ✅ Issue is tracked officially (PBI 746470)
  3. ✅ Full support is not available
  4. ✅ Manual workaround is necessary

Additionally, the broken AddNew() method is explicitly commented out:

case "Add":
   NewMode = true;
   BeforeInsert();
   //dcCustomers.Recordset.AddNew();  // COMMENTED OUT - doesn't work properly
   break;

This shows the development team tried using AddNew(), found it didn't work, and replaced it with the manual approach.


Conclusion

The Bottom Line

The changes in SKS_Blazor_Modified are not optional enhancements or "nice to have" features. They are critical fixes for a fundamentally broken application.

The original SKS_Blazor code:

  • ❌ Does not function correctly for data operations
  • ❌ Is not suitable for production deployment
  • ❌ Will cause data loss and user frustration
  • ❌ Cannot be fixed with simple configuration changes
  • ❌ ADODataControlHelper has known limitations in Blazor
  • ❌ Full support is not available

SKS_Blazor_Modified:

  • ✅ Fixes critical data operation failures
  • ✅ Follows modern web development best practices

Recommendation

The manual synchronization framework is not a workaround or temporary solution—it is the correct architectural approach for data-bound applications in Blazor.

The investment in changes ensures:

  1. A reliable application that works as users expect
  2. A maintainable codebase that can be extended over time
  3. A solid foundation for future feature development
  4. Protection against data loss and application crashes

Manual changes will be always necessary when migrating the code doing a double jump (VB6 => Winforms => Blazor), especially when working with ADO controls.