Introduction

In modern full-stack development, one of the most common challenges is maintaining consistency between backend validation and frontend validation. As a full stack developer working with ASP.NET Web API and Angular, you often define validation rules in your backend models, but still need to replicate them on the client side.

If this duplication is not handled properly, it can lead to:

In this article, we explore a practical approach to solving this problem using:

User Story

As a full stack software developer, after developing ASP.NET Web API with data validations in the Web API bindings, I would like the SPA on Angular framework to have client side validations to reduce round trips of related data error and improve user experience.

Functional Requirements

Technical Requirements

Backend with .NET Integral Types and Validation Attributes

Below is a simplified version of backend models:

public class IntegralEntity
{
    public sbyte SByte { get; set; }
    public byte Byte { get; set; }
    public short Short { get; set; }
    public ushort UShort { get; set; }
    public int Int { get; set; }
    public uint UInt { get; set; }

    [Range(-1000, 1000000)]
    public int ItemCount { get; set; }
}

public class MixedDataEntity : IntegralEntity
{
    public DateOnly DOB { get; set; }

    [Required]
    [MinLength(2), MaxLength(255)]
    public string Name { get; set; }

    [RegularExpression(@"^(https?:\\/\\/)?[da-z.-]+.[a-z.]{2,6}([/\\w .-]*)*\\/?$")]
    public Uri Web { get; set; }

    [EmailAddress, MaxLength(255)]
    public string EmailAddress { get; set; }
}

These attributes define validation rules at the backend level. The challenge is to reflect the same rules in Angular without manually rewriting them.

Generating TypeScript Code for Angular

To avoid duplication, a code generator like WebApiClientGen with plugin "Fonlow.WebApiClientGenCore.NG2FormGroup" can be used.

This tool converts backend models into:

Example: Generated Angular FormGroup

export function CreateIntegralEntityFormGroup() {
    return new FormGroup({
        byte: new FormControl(undefined, [Validators.min(0), Validators.max(255)]),
        int: new FormControl(undefined, [Validators.min(-2147483648), Validators.max(2147483647)]),
        itemCount: new FormControl(undefined, [Validators.min(-1000), Validators.max(1000000)])
    });
}

This shows how .NET numeric types are mapped to Angular validators.

Why This Approach Matters

Think of this like a real-world scenario:

Before:

After:

AI-Assisted UI Generation

Once the FormGroup is generated, AI tools can be used to create Angular components.

Prompt-Based Approach

You provide:

And ask AI to generate:

Comparison of AI Tools

ChatGPT

Codex (VS Code Extension)

Claude

Example: Angular Template Snippet

<mat-form-field appearance="outline">
  <mat-label>Name</mat-label>

  <input matInput formControlName="name" />

  @if (form.controls.name.errors && form.controls.name.touched) {
    <mat-error>
      @if (form.controls.name.errors['required']) { Name is required }
      @if (form.controls.name.errors['minlength']) { Minimum length is 2 }
      @if (form.controls.name.errors['maxlength']) { Maximum length is 255 }
    </mat-error>
  }
</mat-form-field>

Important Observations

Should You Generate UI Directly from Backend?

You can try generating everything from POCO classes using AI, but results may vary:

Best Approach (Recommended)

A hybrid approach works best:

  1. Use code generator for TypeScript + FormGroup

  2. Use AI for UI generation

  3. Manually refine final output

Advantages

Disadvantages

Summary

Combining traditional code generation with AI tools provides a balanced and efficient workflow for modern full-stack applications.

Code generators give you stability and predictability, while AI accelerates UI development. The key is not choosing one over the other, but finding the right balance between automation and control.

In real-world projects, this hybrid approach helps maintain clean architecture, improves user experience, and significantly reduces development time.