.NET on AWS Blog

Modernize your legacy VB.NET applications: Automated migration to C# using AWS Transform custom

Many enterprises still maintain legacy Visual Basic .NET (VB.NET) applications built on .NET Framework. While these applications continue to serve business needs, organizations face growing challenges: a shrinking VB.NET developer talent pool, limited modern tooling support, and a difficult path to cross-platform .NET modernization. Migrating from VB.NET to C# addresses these challenges by opening access to a larger developer community, better IDE support, and modern language features.

However, manually converting VB.NET code to C# is tedious and error-prone. For instances, every Module needs to become a static class, every Function() lambda becomes =>, every Select Case becomes switch — across potentially thousands of files.

In this post, we walk through using AWS Transform custom to automate the migration of a sample VB.NET .NET Framework 4.8 console application to C#. We show how to create a custom transformation definition, execute the transformation, and verify the results — all with minimal manual effort.

About AWS Transform

AWS Transform custom is an agentic AI service that performs large-scale modernization of software, code, libraries, and frameworks. It handles API and service migrations, language version upgrades, framework upgrades, code refactoring, and organization-specific transformations.

AWS Transform custom offers out-of-the-box (AWS-managed) transformations for common scenarios such as Java SDK v1 to v2 upgrades, Node.js and Python version upgrades, Angular to React migration, and more. While VB.NET Framework to C# on .NET Framework is not currently in the list of AWS-managed transformations, AWS Transform custom can still perform this kind of conversion. With AWS Transform custom, you define a transformation using natural language, and the AI agent executes it against your codebase.

After migrating to C# .NET Framework, you can further use AWS Transform Full-Stack Windows Modernization to convert the C# .NET Framework application to C# on cross-platform .NET (such as .NET 10). AWS Transform Full-Stack Windows Modernization supports both VB.NET and C# as source languages, so you can choose to port your VB.NET Framework application directly to cross-platform .NET without converting to C# first, or follow the two-step approach described in this post.

Solution overview

This is the migration workflow:

  1. Start with a VB.NET .NET Framework 4.8 application
  2. Use AWS Transform custom to convert VB.NET to C# on .NET Framework 4.8
  3. Optionally, use AWS Transform Full-Stack Windows Modernization to port C# .NET Framework to cross-platform .NET

The AWS Transform custom workflow follows these phases:

  1. Define — Create a transformation definition describing the VB.NET to C# conversion rules in natural language
  2. Plan — The AI agent analyzes the codebase and generates a step-by-step execution plan
  3. Execute — The agent transforms files incrementally, verifying the build after each step
  4. Validate — Confirm all exit criteria are met: successful build, no remaining VB.NET syntax, preserved API signatures

Prerequisites

Environment setup: Windows EC2 Instance

The .NET Framework build toolchain (MSBuild) is required for the AWS Transform custom process to verify the converted C# code, so we ran the AWS Transform CLI (atx) on a Windows EC2 instance for the sample application in this blog post.

You now have two options for where atx itself runs. As of version 3.5.0 (July 2026), atx runs natively on Windows using Windows Terminal and PowerShell — WSL is no longer a requirement. If you go native, atx and MSBuild share the same environment, there is no /mnt/c/ path translation between them, and you are free to pick any general-purpose instance type.
* Use atx 3.6.0 or later, which fixes a Windows issue where paths containing ~ (home directory) resolved to an unexpected directory mid-session.

WSL2 remains fully supported and is still a reasonable choice if you prefer a Linux-style shell. Bash-based scripts, standard GNU tooling — and the commands in the rest of this post are written in that style. Note that the continuous modernization commands (atx ct) are not yet supported on native Windows. This post only uses the AWS Transform custom commands, which work in both environments.

We used WSL2 for this walkthrough, so the commands that follow assume a bash shell. If you are on native Windows, the same commands work with PowerShell equivalents for shell syntax. The setup we used involves:

1.    Launch a Windows EC2 instance

  • For WSL2, choose an instance type that supports nested virtualization — we used m8i.xlarge.
  • If you run atx natively on Windows instead, nested virtualization is not needed and any suitably sized general-purpose type works.

2.    Install WSL2 on the Windows instance

3.    Install atx within WSL2

4.    Install .NET Framework 4.8 SDK and MSBuild on the Windows host

  • For WLS2, they need to be accessible via /mnt/c/

Sample application

We use a sample VB.NET console application — an Employee Management System — to demonstrate the migration. The source code is available on GitHub in the aws-samples organization:

The atx-result-staging-20260403_074329_289c738e branch was created and committed automatically by atx as a local branch during the transformation process. It was then pushed to the remote repository manually.

Application structure

The application targets .NET Framework 4.8 and includes the following components:

SampleConsoleApp/
├── Program.vb                    # Main entry point (Module)
├── SampleConsoleApp.vbproj       # VB.NET project file
├── Models/
│   ├── Employee.vb               # Employee model with IComparable(Of T)
│   └── Department.vb             # Department model with validation
├── Services/
│   ├── EmployeeService.vb        # CRUD operations with LINQ queries
│   └── ReportService.vb          # Report generation with LINQ grouping
├── Utilities/
│   └── ConsoleHelper.vb          # Console helper (NotInheritable Class)
└── My Project/
    └── AssemblyInfo.vb           # Assembly metadata

The application demonstrates VB.NET language features commonly found in enterprise applications:

  • Modules (Module Program)
  • Explicit properties with validation logic
  • Interface implementation (IComparable(Of Employee))
  • LINQ method chains with lambda expressions (Function(e) e.Salary)
  • Select Case statements
  • NotInheritable Class (sealed classes)
  • Shared methods (static methods)
  • Try...Catch error handling
  • Optional parameters
  • String concatenation with & operator

Walkthrough

Step 1: Start AWS Transform custom

Launch atx from WSL on the Windows EC2 instance. The interactive CLI displays available AWS-managed transformations and accepts natural language commands.

ubuntu@EC2AMAZ-S6OK3KG:~$ atx
 █████╗ ██╗    ██╗███████╗
██╔══██╗██║    ██║██╔════╝
███████║██║ █╗ ██║███████╗
██╔══██║██║███╗██║╚════██║
██║  ██║╚███╔███╔╝███████║
╚═╝  ╚═╝ ╚══╝╚══╝ ╚══════╝

████████╗██████╗  █████╗ ███╗   ██╗███████╗███████╗ ██████╗ ██████╗ ███╗   ███╗
╚══██╔══╝██╔══██╗██╔══██╗████╗  ██║██╔════╝██╔════╝██╔═══██╗██╔══██╗████╗ ████║
   ██║   ██████╔╝███████║██╔██╗ ██║███████╗█████╗  ██║   ██║██████╔╝██╔████╔██║
   ██║   ██╔══██╗██╔══██║██║╚██╗██║╚════██║██╔══╝  ██║   ██║██╔══██╗██║╚██╔╝██║
   ██║   ██║  ██║██║  ██║██║ ╚████║███████║██║     ╚██████╔╝██║  ██║██║ ╚═╝ ██║
   ╚═╝   ╚═╝  ╚═╝╚═╝  ╚═╝╚═╝  ╚═══╝╚══════╝╚═╝      ╚═════╝ ╚═╝  ╚═╝╚═╝     ╚═╝
┌──────────────────────────────────────────────────────────────────────────────┐
│                              Region: us-east-1                               │
└──────────────────────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────────────────────┐
│                                Trusted Tools                                 │
│                                                                              │
│ Built-in Trusted Tools                                                       │
│   Configuration: Built-in read-only tools                                    │
│   • file_read                                                                │
│   • get_transformation_from_registry                                         │
│   • list_available_transformations_from_registry                             │
│   • document_manager (add operations only)                                   │
│   • editor (view and find_line operations only)                              │
└──────────────────────────────────────────────────────────────────────────────┘
Welcome to AWS Transform. You can discover, create, and execute transformations (AWS-managed or custom ones published to your registry). How can I help?
> please transform the current directory from VB.NET to C#.NET

Step 2: Create the transformation definition

When you ask atx to transform VB.NET to C#, it first checks the transformation registry for an existing AWS-managed transformation. The agent calls list_available_transformations_from_registry and finds 13 AWS-managed transformations — but none for VB.NET to C#. The agent recognizes the gap and decides to create a custom transformation definition:

> I don't see an existing VB.NET to C# transformation in the 
  registry. Let me create a custom one for you. I'll build a
  transformation definition for this migration.

  To make this transformation definition as effective as possible,
  it would be useful to know:

  1. Are there any specific VB.NET patterns or libraries your
     codebase relies on heavily?
  2. Which .NET version are you targeting for the C# output?

> 1. No, 2. .NET Framework 4.8

After you provide the answers, atx generates a comprehensive transformation definition as a markdown file. The definition includes an objective, entry criteria, 20 detailed implementation steps, and 8 validation/exit criteria. Here is a snippet of the generated transformation definition:

Using tool: editor (trusted)
 ⋮
 ● Path: ~/.aws/atx/custom/20260403_074329_289c738e/artifacts/tp-staging/transformation_definition.md
 ● Command: create
 ● File content:

# VB.NET to CSharp.NET Migration

## Objective

Transform VB.NET source files (.vb) into equivalent C#.NET source files (.cs) targeting .NET Framework 4.8, preserving all original functionality, logic, and application behavior while producing idiomatic C# code.

## Summary

This transformation converts an entire VB.NET codebase to C#.NET by translating all language-specific syntax, constructs, and patterns to their C# equivalents. The process covers file-by-file conversion of namespaces, classes, modules, data types, control flow statements, error handling, LINQ expressions, events, delegates, properties, operators, and other VB.NET idioms. The output must compile against .NET Framework 4.8 and maintain identical runtime behavior to the original VB.NET code.

## Entry Criteria

1. The source codebase contains VB.NET source files (.vb) targeting .NET Framework 4.8 or compatible versions.
2. The VB.NET project compiles and builds successfully before transformation.
3. Project files (.vbproj) and solution files (.sln) are present and properly configured.

## Implementation Steps

1. Convert all VB.NET project files (.vbproj) to C# project files (.csproj), translating MSBuild properties and items accordingly. Update the solution file (.sln) to reference the new .csproj files.

2. Convert namespace and imports declarations: replace VB.NET "Imports" statements with C# "using" directives. Translate "Namespace ... End Namespace" blocks to C# "namespace { }" syntax.

3. Convert class, structure, and module declarations:
   - Translate "Class ... End Class" to "class { }".
   - Translate "Structure ... End Structure" to "struct { }".
   - Translate "Module ... End Module" to "static class { }" with all members made static.
   ...

## Validation / Exit Criteria

1. All VB.NET source files (.vb) have been converted to corresponding C# source files (.cs).
2. The converted C# project compiles successfully against .NET Framework 4.8 with no build errors.
3. All namespaces, class hierarchies, interfaces, and type relationships are preserved in the C# output.
4. All public and internal API signatures (method names, parameters, return types, access modifiers) remain functionally equivalent.
5. Control flow logic, error handling, and exception behavior are preserved and functionally identical.
6. Event handling, delegate usage, and LINQ queries produce the same results as the original VB.NET code.
7. All existing unit tests, if present, pass against the converted C# code with equivalent test coverage.
8. No VB.NET-specific syntax or constructs remain in the C# output files.

 ● Completed in 2ms

The agent then confirms the definition covers the full breadth of conversion concerns:

The transformation definition for VB.NET to C#.NET has been created and saved. It covers the full breadth of conversion concerns targeting .NET Framework 4.8, including:

- Project and solution file conversion (.vbproj to .csproj)
- Namespace, imports, and module translations
- Data type mappings (Integer to int, Boolean to bool, etc.)
- Method, property, and indexer conversions
- Control flow (If/Select Case/For/While/With/Using)
- Error handling (structured Try-Catch and legacy On Error patterns)
- Events, delegates, WithEvents/Handles, AddHandler/RemoveHandler
- LINQ query syntax and lambda expression translation
- Operator mappings (AndAlso to &&, OrElse to ||, string concatenation, etc.)
- String function conversions, XML literals, preprocessor directives, attributes, generics, enumerations
- VB.NET-specific constructs like ReDim, My namespace, Option Strict/Explicit, and case-sensitivity resolution

Finally, the agent saves the transformation definition as a draft to the registry:

Using tool: save_transformation (requested)
 ⋮
 ● Name: VB.NET-to-CSharp.NET
 ● Description: Transform VB.NET code to C#.NET, converting all VB.NET source files to equivalent C#.NET code including project files, syntax, data types, control flow, error handling, LINQ, events, delegates, and all VB.NET-specific constructs.
 ● Publish: No (Draft)
 ● New Transformation: Yes

 ● Completed in 3.1s

The transformation definition is saved and can be reused across multiple projects. You can also publish it to the registry so other team members can use it.

Step 3: Execute the transformation

After saving the transformation definition, atx analyzes the codebase and generates a transformation plan. First, it reads all source files and runs an initial build verification:

> The VB.NET project builds successfully. Now I have a complete understanding of the codebase. Let me create the transformation plan.

**Codebase Analysis Summary:**

- **Project type:** VB.NET Console Application targeting .NET Framework 4.8
- **Solution:** SampleConsoleApp.sln with a single project SampleConsoleApp.vbproj
- **Build tool:** MSBuild (accessible via `MSBuild.exe`)
- **Files to convert (7 VB.NET files):**
- `Models/Department.vb` - Department class (base model, no dependencies on other project files)
- `Models/Employee.vb` - Employee class (depends on Department, implements IComparable)
- `Utilities/ConsoleHelper.vb` - Static utility class (no dependencies on other project files)
- `Services/EmployeeService.vb` - Employee service (depends on Employee)
- `Services/ReportService.vb` - Report service (depends on Employee, Department, ConsoleHelper)
- `Program.vb` - Main module (depends on all other classes)
- `My Project/AssemblyInfo.vb` - Assembly info
- **Project/Solution files to convert:** SampleConsoleApp.vbproj → SampleConsoleApp.csproj, SampleConsoleApp.sln update
- **Key VB.NET constructs to convert:** Module (→ static class), Option Strict/Explicit, Imports, NotInheritable, vbCrLf, string concatenation with &, Function lambdas, OrElse/AndAlso, TryCast, CInt, NameOf, Optional parameters, Do...Loop While

**Dependency hierarchy (bottom-up):**
1. Department (no dependencies)
2. ConsoleHelper (no dependencies)
3. Employee (depends on Department)
4. EmployeeService (depends on Employee)
5. ReportService (depends on Employee, Department, ConsoleHelper)
6. Program (depends on all)

The agent then creates a 4-step execution plan and presents a summary:

Step Title Key Actions
1 Convert project/solution infrastructure .vbproj → .csproj, update .sln, AssemblyInfo.vb → AssemblyInfo.cs
2 Convert base model classes Department.vb → .cs, Employee.vb → .cs
3 Convert utility and service classes ConsoleHelper.vb, EmployeeService.vb, ReportService.vb → .cs
4 Convert entry point, cleanup, final build Program.vb (Module) → Program.cs (static class), remove all .vb f

After approving the plan, the agent sets up version control and begins the implementation:

Using tool: vcs_control (requested)
⋮
● Action: setup
● Repository: /mnt/c/aws-samples/sample-aws-transform-custom-vb-to-csharp
● Current Branch: main
● Will Create Branch: atx-result-staging-20260403_074329_289c738e
● Note: Creates a new branch for transformation commits (original branch preserved)
⋮
● Completed in 628ms

Each step corresponds to a commit made by atx on the atx-result-staging-20260403_074329_289c738e branch. You can review the exact changes for each step on GitHub:

Step Commit message GitHub link
1 Step 1: Convert project files and solution configuration 8af77e1
2 Step 2: Convert base model classes (Department.vb and Employee.vb) c626517
3 Step 3: Convert utility and service classes ccd51e3
4 Step 4: Verify the results 24187ca

After all steps complete, the validation summary confirms:

  • 7 VB.NET files converted to 7 C# files
  • Project infrastructure migrated (.vbproj.csproj, .sln updated, AssemblyInfo migrated)
  • All original .vb files removed
  • Build succeeded with 0 errors and 0 warnings
  • All public API signatures preserved
  • No VB.NET-specific syntax remaining in any .cs file
================================================================================
TRANSFORMATION COMPLETE
================================================================================
All 4 steps executed successfully. The VB.NET codebase has been fully converted to C#.NET.
Summary of conversion:
- 7 VB.NET files converted to 7 C# files
- Project infrastructure migrated (.vbproj -> .csproj, .sln updated, AssemblyInfo migrated)
- All original .vb files and VB.NET project artifacts removed
- Full build succeeds with 0 errors and 0 warnings
- All public API signatures preserved
- All business logic preserved identically
● Completed in 0ms

Before and after: Code comparison

Let’s look at some key conversion examples to see what AWS Transform custom produced.

Module to static class

VB.NET (Program.vb):

Module Program
    Private _employeeService As EmployeeService
 
    Sub Main(args As String())
        ' ...
        Dim running As Boolean = True
        While running
            DisplayMenu()
            Dim choice As String = Console.ReadLine()
            Select Case choice
                Case "1"
                    ListAllEmployees()
                Case "0"
                    running = False
                Case Else
                    ConsoleHelper.WriteColoredLine("Invalid option.",
                        ConsoleColor.Red)
            End Select
        End While
    End Sub
End Module

C# (Program.cs) — converted by AWS Transform custom:

public static class Program
{
    private static EmployeeService _employeeService;
 
    static void Main(string[] args)
    {
        // ...
        bool running = true;
        while (running)
        {
            DisplayMenu();
            string choice = Console.ReadLine();
            switch (choice)
            {
                case "1":
                    ListAllEmployees();
                    break;
                case "0":
                    running = false;
                    break;
                default:
                    ConsoleHelper.WriteColoredLine("Invalid option.",
                        ConsoleColor.Red);
                    break;
            }
        }
    }
}

Key conversions: Modulestatic class, all members made static, Select Caseswitch, While...End Whilewhile { }, Dim → explicit type declarations.

Interface implementation and properties

VB.NET (Employee.vb):

Public Class Employee
    Implements IComparable(Of Employee)
 
    Public ReadOnly Property FullName As String
        Get
            Return FirstName & " " & LastName
        End Get
    End Property
 
    Public Function CompareTo(other As Employee) As Integer _
        Implements IComparable(Of Employee).CompareTo
        If other Is Nothing Then Return 1
        Return String.Compare(Me.LastName, other.LastName, _
            StringComparison.OrdinalIgnoreCase)
    End Function
End Class

C# (Employee.cs):

public class Employee : IComparable<Employee>
{
    public string FullName
    {
        get
        {
            return FirstName + " " + LastName;
        }
    }
 
    public int CompareTo(Employee other)
    {
        if (other == null) return 1;
        return string.Compare(this.LastName, other.LastName,
            StringComparison.OrdinalIgnoreCase);
    }
}

Key conversions: Implements IComparable(Of Employee): IComparable<Employee>, Me. → this., Is Nothing== null, &+, Implements clause removed from method signature.

LINQ and lambda expressions

VB.NET (EmployeeService.vb):

Public Function SearchEmployees(searchTerm As String) As List(Of Employee)
    If String.IsNullOrWhiteSpace(searchTerm) Then
        Return New List(Of Employee)()
    End If
    Dim lowerSearchTerm As String = searchTerm.ToLower()
    Return _employees.Where(Function(e) _
        e.FirstName.ToLower().Contains(lowerSearchTerm) OrElse _
        e.LastName.ToLower().Contains(lowerSearchTerm) OrElse _
        e.Email.ToLower().Contains(lowerSearchTerm)).ToList()
End Function

C# (EmployeeService.cs):

public List<Employee> SearchEmployees(string searchTerm)
{
    if (string.IsNullOrWhiteSpace(searchTerm))
    {
        return new List<Employee>();
    }
    string lowerSearchTerm = searchTerm.ToLower();
    return _employees.Where(e =>
        e.FirstName.ToLower().Contains(lowerSearchTerm) ||
        e.LastName.ToLower().Contains(lowerSearchTerm) ||
        e.Email.ToLower().Contains(lowerSearchTerm)).ToList();
}

Key conversions: List(Of Employee)List<Employee>, Function(e)e =>, OrElse||.

Sealed class with static methods

VB.NET (ConsoleHelper.vb):

Public NotInheritable Class ConsoleHelper
    Private Sub New()
    End Sub
 
    Public Shared Sub DrawLine(Optional length As Integer = 50, _
        Optional character As Char = "-"c)
        Console.WriteLine(New String(character, length))
    End Sub
End Class

C# (ConsoleHelper.cs):

public sealed class ConsoleHelper
{
    private ConsoleHelper()
    {
    }
 
    public static void DrawLine(int length = 50, char character = '-')
    {
        Console.WriteLine(new string(character, length));
    }
}

Key conversions: NotInheritablesealed, Sharedstatic, Optional parameters → C# optional parameters, "-"c → '-'.

Comprehensive conversion reference

The following table summarizes the VB.NET to C# conversions that AWS Transform custom handled in this migration:

VB.NET construct C# equivalent
Module ... End Module public static class { }
Sub ... End Sub void Method() { }
Function ... End Function ReturnType Method() { }
Dim x As Type Type x
Shared static
NotInheritable sealed
Overrides override
ReadOnly (property) Get-only property
Implements IComparable(Of T) : IComparable<T>
Select Case ... End Select switch { case: break; }
If ... Then ... End If if (...) { }
While ... End While while (...) { }
For Each ... Next foreach (...) { }
Do ... Loop While do { } while ();
Try ... Catch ... End Try try { } catch { }
Function(e) e.Property e => e.Property
AndAlso / OrElse && / ||
Is Nothing / IsNot Nothing == null / != null
Not !
& (string concatenation) +
TryCast(obj, Type) obj as Type
CInt(...) (int)(...)
Me. this.
vbCrLf "\r\n"
Throw New throw new
NameOf(x) nameof(x)
Optional param As Type = val Type param = val
"-"c (Char literal) '-'
500000D (Decimal literal) 500000m
Imports using

Next steps: From .NET Framework to cross-platform .NET

After converting your VB.NET application to C# on .NET Framework, the next step in your modernization journey is porting to cross-platform .NET. AWS Transform Full-Stack Windows Modernization can help with this. It provides AI-driven capabilities to:

  • Port .NET Framework (C# / VB.NET) applications to cross-platform .NET (such as .NET 8 / 10)
  • Modernize SQL Server databases to Amazon Aurora PostgreSQL
  • Update UI frameworks from ASP.NET Web Forms to Blazor
  • Deploy applications to Amazon EC2 Linux or Amazon ECS

This two-step approach:

  1. First VB.NET to C# using AWS Transform custom,
  2. Then C# .NET Framework to cross-platform .NET using AWS Transform Full-Stack Windows Modernization

provides a clear, incremental path to fully modernize your legacy VB.NET Framework applications. This process results in a modernized C# application (NOT VB.NET) running on cross-platform .NET, ready for deployment on Linux or containers.

Clean up

If you launched a Windows EC2 instance for this walkthrough, terminate it to avoid ongoing charges. No other AWS resources are created during the AWS Transform custom process beyond the EC2 instance.

Conclusion

In this post, we demonstrated how to use AWS Transform custom to automate the migration of a VB.NET .NET Framework application to C#. The AI agent created a comprehensive transformation definition, generated a step-by-step execution plan, converted 7 source files with zero build errors, and preserved all business logic and API signatures.

AWS Transform Custom reduces the manual effort and risk involved in language migrations. The transformation definition is reusable — once created, you can apply it across multiple VB.NET projects in your organization. Combined with AWS Transform Full-Stack Windows Modernization for the subsequent .NET Framework to cross-platform .NET migration, you have a complete modernization path for your legacy VB.NET applications.

The sample source code used in this post is available in the aws-samples GitHub organization at sample-aws-transform-custom-vb-to-csharp. To get started with, visit the AWS Transform getting started guide or learn more about AWS Transform custom.

George Liu

George Liu

George Liu is a Senior Solutions Architect at AWS, dedicated to serving enterprise customers in Hong Kong. With hands-on experience in developing and modernizing enterprise applications using various technology stacks such as Java, .NET, Oracle, and SQL Server, he has also taken a key architect role in several large-scale projects focused on modernizing core mission-critical systems in Hong Kong. With over two decades of experience in the IT industry, George brings a wealth of expertise to his role.

Fei Lok

Fei Lok

Fei Lok is a Solutions Architect at AWS, dedicated to serving enterprise customers in Hong Kong and Macau with a special focus on the Betting and Gaming industry. With deep experience in industry specific pain points, technologies, architectures, and solutions, he has been providing customers with secure, compliant, localized and reliable solutions within highly regulated industries.