INT402Semester 7 • 4 CreditsElective Subjects

Modern Web Programming Tools And Techniques

This course develops proficiency in C# and ASP.NET Core for building MVC applications and RESTful Web APIs. It covers object-oriented programming, Razor views, model binding and validation, middleware, dependency injection, authentication and authorization, Entity Framework Core, SQL Server, CRUD operations, and API testing with Postman.

6 Units • Notes • Model Answers • MCQs
Select Course Unit (6 Units)
Active: Unit 1
Unit 1:Unit 1: Introduction To .Net And C#
7 min read•High-Yield Unit Guide

Unit 1: Introduction To .Net And C#

Unit 1 Exam Focus & Core Takeaways

Review the core definitions, standard architectures, and syntax patterns below. Pay special attention to sections highlighted with bullet points for your mid-term and end-term subjective questions.

Unit 1: Introduction to .NET and C#

1. Architectural Evolution: From .NET Framework to Unified Modern .NET

The Microsoft .NET ecosystem has undergone an architectural transformation from a Windows-proprietary enterprise runtime into a cross-platform, cloud-native, open-source development platform.

CODE
+---------------------------------------------------------------------------------------------------+
|                                  Historical Evolution of .NET                                     |
|                                                                                                   |
|  2002 - 2019: Legacy .NET Framework (1.0 -> 4.8.1)                                                |
|  - Windows-only, tightly coupled to IIS (System.Web.dll) and Windows GDI/Registry                 |
|  - Machine-wide global runtime installation (GAC - Global Assembly Cache)                         |
|  - High memory footprint, difficult containerization, monolithic architecture                     |
|                                                                                                   |
|  2016 - 2019: .NET Core (1.0 -> 3.1)                                                              |
|  - Ground-up rewrite: Cross-platform (Linux, macOS, Windows)                                      |
|  - Decoupled from IIS via lightweight Kestrel web server                                          |
|  - Side-by-side runtime deployment, self-contained single-file apps, Docker-native                  |
|                                                                                                   |
|  2020 - Present: Modern Unified .NET (.NET 5 -> .NET 6 LTS -> .NET 8 LTS -> .NET 9 STS)          |
|  - Dropped "Core" moniker to represent one unified framework for Web, Cloud, Mobile, Desktop, AI  |
|  - RyuJIT Tiered Compilation, Native AOT (Ahead-Of-Time), Hardware Intrinsics (AVX-512)           |
|  - Predictable release cadence: Even versions = Long-Term Support (LTS, 36 months)                |
+---------------------------------------------------------------------------------------------------+

1.1 Support Lifecycle: LTS vs STS

Microsoft delivers predictable annual releases every November:

  • Long-Term Support (LTS): Even-numbered versions (e.g., .NET 6, .NET 8). Supported for 36 months with enterprise patches, security fixes, and API stability. Recommended for mission-critical banking, government, and enterprise backends.
  • Standard-Term Support (STS): Odd-numbered versions (e.g., .NET 7, .NET 9). Supported for 18 months (6 months after the subsequent release). Ideal for teams adopting bleeding-edge runtime features, preview language enhancements, or fast iterative microservices.

1.2 Comparison: Legacy .NET Framework vs Modern .NET Core / .NET 8+

Architecture MetricLegacy .NET Framework (4.x)Modern .NET (.NET 8+)
Operating SystemWindows Desktop / Windows Server onlyCross-platform (Linux, macOS, Windows, Android, iOS)
Hosting ModelIIS worker process (w3wp.exe) via System.WebIn-process Kestrel reverse-proxied behind Nginx/IIS/Caddy
Open SourceProprietary Windows component100% open source under MIT/Apache 2.0 (GitHub)
Deployment ModelMachine-wide GAC installation (shared)Side-by-side, Framework-Dependent, or Self-Contained
Container SupportHeavy Windows Server containers (~4 GB)Ultra-lightweight Alpine Linux containers (~50 MB)
Compilation TierSingle-pass JIT or NGENTiered JIT (Tier 0 -> Tier 1 PGO) + Native AOT
Web ServerIIS / HTTP.sysHigh-performance asynchronous Kestrel (Sockets/IO)

2. Common Language Infrastructure (CLI) and CoreCLR Internals

The execution engine of .NET is standardized internationally under ECMA-335 and ISO/IEC 23271 as the Common Language Infrastructure (CLI). Modern .NET implements this specification through the CoreCLR.

CODE
+-----------------------------------------------------------------------------------------+
|                                CoreCLR Execution Engine                                 |
|                                                                                         |
|  +------------------------------------+   +------------------------------------------+  |
|  |     Type System (CTS & CLS)        |   |       Garbage Collector (GC Engine)      |  |
|  |  - Unified System.Object hierarchy |   |  - Ephemeral Generations: Gen 0, Gen 1   |  |
|  |  - Structs (Value) vs Classes (Ref)|   |  - Mature Generation: Gen 2              |  |
|  |  - Cross-language interop rules    |   |  - Large Object Heap (LOH: >85,000 bytes)|  |
|  |  - Metadata reflection tables      |   |  - Pinned Object Heap (POH)              |  |
|  +------------------------------------+   +------------------------------------------+  |
|                                     |                                                   |
|                                     v                                                   |
|  +-----------------------------------------------------------------------------------+  |
|  |                RyuJIT (Just-In-Time) Tiered Compilation Engine                     |  |
|  |                                                                                   |  |
|  |   [CIL Bytecode] ---> [Tier 0: Quick JIT (No Optimizations, Quick Startup)]        |  |
|  |                                    |                                              |  |
|  |                              (Call Counter > 30)                                  |  |
|  |                                    v                                              |  |
|  |                       [Dynamic PGO Profiling Data]                                |  |
|  |                                    v                                              |  |
|  |   [Native Machine Code] <--- [Tier 1: High Optimization (SIMD, Inlining, Loop)]   |  |
|  +-----------------------------------------------------------------------------------+  |
+-----------------------------------------------------------------------------------------+

2.1 Core Acronyms & Foundational Specifications

  1. Common Intermediate Language (CIL / MSIL): A CPU-independent, stack-based intermediate instruction set generated by .NET language compilers (csc for C#, fsc for F#). CIL instructions (e.g., ldloc, callvirt, starg) operate on an evaluation stack rather than machine CPU registers.
  2. Common Type System (CTS): The strict specification governing data type declarations and values. It establishes that every type inherits from the root System.Object, defines the distinction between Value Types (stored on the stack or inline) and Reference Types (allocated on the managed heap), and regulates encapsulation (private, protected, internal, public).
  3. Common Language Specification (CLS): A subset of CTS rules guaranteeing complete cross-language interoperability. If a public API adheres to CLS compliance, it can be called seamlessly from C#, F#, or Visual Basic without type impedance.
  4. Managed Code: Code that targets the CoreCLR runtime and relies on runtime-provided services, including automatic memory reclamation (Garbage Collection), type safety verification, exception dispatching, array boundary checking, and thread synchronization.
  5. Unmanaged Code: Code that compiles directly into machine-specific assembly targeting OS system calls (e.g., C/C++ native dynamic libraries). Memory allocation (malloc/free) and pointer arithmetic are the developer's sole responsibility.

2.2 Compilation and Execution Pipeline

The journey of C# code to execution consists of two distinct phases:

CODE
[Developer Source (.cs)] 
         |
         v (Roslyn Compiler: csc)
[Assembly: Portable Executable (.dll)]
    - CIL (Common Intermediate Language)
    - Metadata Tables (Types, Members, Attributes)
    - Embedded Manifest (Dependencies, Versioning)
         |
         v (Runtime Host: dotnet.exe)
[CoreCLR Execution Engine]
         |
         v (RyuJIT Tiered Compilation)
[Target CPU Machine Code (ARM64 / x86_64)]

2.3 Tiered Compilation & Profile-Guided Optimization (PGO)

In modern .NET, the Just-In-Time compiler (RyuJIT) does not treat all methods equally:

  • Tier 0 (Quick JIT): When a method is called for the first time, it compiles instantaneously without expensive loop unrolling, vectorization, or inlining. This guarantees fast cold-start performance and rapid server startup.
  • Dynamic PGO (Profile-Guided Optimization): As the method executes in Tier 0, CoreCLR instruments the code to collect runtime statistics (branch probability, concrete type frequencies at call sites).
  • Tier 1 (Optimized JIT): If a method exceeds a call invocation threshold (typically 30 executions) or contains long-running loops, a background thread re-compiles the method using deep optimizations, devirtualizing interface calls and emitting SIMD hardware instructions.

2.4 JIT Compilation vs Native AOT (Ahead-Of-Time)

Starting in .NET 7 and matured in .NET 8/9, developers can choose between dynamic JIT and static Native AOT:

FeatureStandard RyuJIT (JIT)Native Ahead-Of-Time (AOT)
Output BinaryIntermediate CIL inside .dll assemblyNative standalone OS binary (.exe / ELF binary)
Startup LatencyModerate (requires runtime initialization & JIT)Instantaneous (< 10ms startup)
Memory FootprintHigher (includes JIT engine & CIL buffers)Minimal (no JIT compiler in memory)
Dynamic ReflectionFully supported (Type.GetType(), Emit())Heavily constrained (requires compile-time trimming)
Ideal WorkloadsMonoliths, complex microservices, plugin appsServerless functions (AWS Lambda, Azure Functions), CLI tools

3. C# Language Evolution and Modern Paradigms

C# was created by Anders Hejlsberg and released by Microsoft in 2002. Over two decades, it has evolved from an object-oriented language into a multi-paradigm language combining functional programming, pattern matching, asynchronous task programming, and high-performance zero-allocation systems programming.

3.1 Language Evolution Milestones

  • C# 1.0 (2002): Core OOP principles (classes, interfaces, structs, delegates, properties).
  • C# 2.0 (2005): Generics (List<T>), nullable value types (int?), iterators (yield return), anonymous methods.
  • C# 3.0 (2008): Language-Integrated Query (LINQ), lambda expressions, extension methods, anonymous types, var.
  • C# 5.0 (2012): Asynchronous programming model (async and await), caller info attributes.
  • C# 7.0 - 7.3 (2017-2018): Pattern matching, tuples, local functions, ref struct, Span<T> and Memory<T>.
  • C# 8.0 (2019): Nullable reference types (string?), async streams (IAsyncEnumerable<T>), default interface implementations, switch expressions.
  • C# 9.0 (2020): record types, top-level statements, init-only setters (init), target-typed new.
  • C# 10 - 12 (2021-2023): Global using directives, file-scoped namespaces, raw string literals, collection expressions ([1, 2, 3]), primary constructors for classes and structs.

3.2 Nullable Reference Types (NRT)

In legacy C#, all reference types were implicitly nullable, leading to the infamous NullReferenceException (the "billion-dollar mistake"). In modern C# (#nullable enable), the compiler enforces compile-time null tracking:

csharp
#nullable enable

public class CustomerService
{
    // Non-nullable reference: Must be initialized, cannot be assigned null
    public string OrganizationName { get; set; } = "Default University";

    // Nullable reference: Explicitly marked with '?'
    public string? MiddleName { get; set; }

    public void ProcessCustomer(string nonNullInput, string? optionalInput)
    {
        // Compiler error: nonNullInput cannot be null
        int len1 = nonNullInput.Length; 

        // Compiler warning: optionalInput may be null
        // int len2 = optionalInput.Length; 

        // Safe access via null-conditional or null-coalescing operator
        int len2 = optionalInput?.Length ?? 0;

        // Pattern matching null check
        if (optionalInput is { Length: > 0 } validString)
        {
            Console.WriteLine($"Valid: {validString}");
        }
    }
}

3.3 Record Types and Immutability

Records (record class and record struct) model immutable data containers with compiler-generated value-based equality, formatted string representation, and non-destructive mutation (with expressions):

csharp
// Positional Record declaration
public record StudentRecord(int Id, string FullName, string Department, double Gpa);

public class RecordDemonstration
{
    public static void Run()
    {
        var student1 = new StudentRecord(101, "Aman Sharma", "Computer Science", 3.92);
        var student2 = new StudentRecord(101, "Aman Sharma", "Computer Science", 3.92);

        // Value-based equality (true, unlike standard classes which check reference equality)
        bool areEqual = (student1 == student2); 
        Console.WriteLine($"Value Equality: {areEqual}"); // Output: True

        // Non-destructive mutation using the 'with' keyword
        var updatedStudent = student1 with { Gpa = 4.00 };
        Console.WriteLine(updatedStudent); 
        // Output: StudentRecord { Id = 101, FullName = Aman Sharma, Department = Computer Science, Gpa = 4 }
    }
}

4. The .NET CLI, SDK, and Project Anatomy

4.1 SDK vs .NET Runtime vs ASP.NET Core Runtime

Developers frequently confuse the installation packages required to build and host .NET applications:

  1. .NET Runtime (Microsoft.NETCore.App): The minimal engine containing the CoreCLR and core base class libraries (System.Runtime.dll, System.Collections.dll). Sufficient only for running basic non-web console applications.
  2. ASP.NET Core Runtime (Microsoft.AspNetCore.App): Adds the ASP.NET Core web stack (Kestrel web server, routing, middleware pipeline, Razor rendering engine) on top of the base .NET runtime. Required on Linux/Windows production servers hosting web APIs.
  3. .NET SDK (Software Development Kit): The comprehensive developer bundle. Includes the C# Roslyn compiler (csc), the MSBuild build engine, the dotnet command-line CLI, template engines, and targeting packs. Required to build, test, and publish code.

4.2 Modern Project File Anatomy (.csproj)

Modern .NET utilizes minimal SDK-style project files, eliminating thousands of lines of legacy XML:

xml
<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <InvariantGlobalization>false</InvariantGlobalization>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.0" />
    <PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
  </ItemGroup>

</Project>

Key Directives:

  • Sdk="Microsoft.NET.Sdk.Web": Automatically imports Web SDK targets, including Kestrel and MVC dependencies.
  • <TargetFramework>net8.0</TargetFramework>: Declares that the target framework is .NET 8.
  • <Nullable>enable</Nullable>: Activates static null-state analysis.
  • <ImplicitUsings>enable</ImplicitUsings>: Automatically imports common namespaces (System, System.Collections.Generic, System.Net.Http, Microsoft.AspNetCore.Builder) across all C# files without requiring manual using statements.

4.3 Essential .NET CLI Workflow Commands

The dotnet executable provides a unified command-line interface across all operating systems:

bash
# 1. Scaffolding a new project
dotnet new webapi -n RetailBackend -o ./src/RetailBackend
dotnet new sln -n RetailSolution
dotnet sln RetailSolution.sln add ./src/RetailBackend/RetailBackend.csproj

# 2. Package Management via NuGet
dotnet add ./src/RetailBackend package Microsoft.EntityFrameworkCore.SqlServer
dotnet add ./src/RetailBackend package FluentValidation.AspNetCore

# 3. Dependency Restoration & Build
dotnet restore
dotnet build --configuration Release --no-restore

# 4. Testing & Running
dotnet test --logger "console;verbosity=detailed"
dotnet run --project ./src/RetailBackend

# 5. Production Publishing
# Framework-Dependent Deployment (FDD)
dotnet publish -c Release -o ./dist/fdd

# Self-Contained Deployment (SCD) for Linux x64 with trimming
dotnet publish -c Release -r linux-x64 --self-contained true -p:PublishTrimmed=true -o ./dist/scd-linux

5. Deployment Architectures: FDD vs SCD

CODE
+------------------------------------+      +------------------------------------+
|  Framework-Dependent (FDD)         |      |  Self-Contained Deployment (SCD)   |
|                                    |      |                                    |
|  +------------------------------+  |      |  +------------------------------+  |
|  | Application Assembly (.dll)  |  |      |  | Application Assembly (.dll)  |  |
|  +------------------------------+  |      |  +------------------------------+  |
|  | Third-Party NuGet Libs (.dll)|  |      |  | Third-Party NuGet Libs (.dll)|  |
|  +------------------------------+  |      |  +------------------------------+  |
|                                    |      |  | Complete CoreCLR Runtime     |  |
|  (Requires pre-installed .NET      |      |  +------------------------------+  |
|   Runtime on host operating system)|      |  | Native OS Host Executable    |  |
|                                    |      |  +------------------------------+  |
|  * Output size: ~5 MB to 15 MB     |      |  * Output size: ~60 MB to 120 MB |  |
|  * Fast deployment transfer        |      |  * Zero external dependencies   |  |
|  * Shared OS security patches      |      |  * Total version isolation       |  |
+------------------------------------+      +------------------------------------+

6. Real-World Troubleshooting Playbook

  1. NETSDK1045: The current .NET SDK does not support targeting .NET 8.0:

    • Cause: The host machine has an older SDK installed (e.g., .NET 6/7) while the project file specifies <TargetFramework>net8.0</TargetFramework>.
    • Fix: Check installed SDKs via dotnet --list-sdks. Install the matching .NET 8 SDK or create a global.json pinning the project to an installed SDK version.
  2. Ambiguous invocation or missing using directive despite namespace being present:

    • Cause: Conflicts caused by <ImplicitUsings>enable</ImplicitUsings> colliding with custom namespace types of the same name (e.g., Task, Action).
    • Fix: Explicitly qualify the type with its full namespace or add a targeted alias directive: using AppTask = MyApp.Models.Task;.
  3. NullReferenceException at runtime in a project with <Nullable>enable</Nullable>:

    • Cause: The developer suppressed compiler warnings using the null-forgiving operator (!) (e.g., user.Profile!.Bio), or data deserialized from external JSON contained unexpected null properties.
    • Fix: Never use the null-forgiving operator on unvalidated boundary models; introduce required properties or default fallbacks: public required string Bio { get; init; }.
  4. Self-Contained Linux app crashes with Process terminated. Couldn't find a valid ICU package on the system:

    • Cause: Modern .NET relies on International Components for Unicode (ICU) for string sorting and globalization. Minimal Docker images (e.g., Alpine) lack ICU by default.
    • Fix: Install icu-libs inside the Dockerfile, or set <InvariantGlobalization>true</InvariantGlobalization> in the .csproj if internationalization is not required.

7. ASP.NET Core Middleware Pipeline and Dependency Injection Foundations

7.1 Modern Minimal Hosting Pipeline (Program.cs)

In modern .NET (starting with .NET 6), boilerplate Startup.cs classes have been unified into a clean, top-level Program.cs utilizing WebApplicationBuilder:

csharp
var builder = WebApplication.CreateBuilder(args);

// 1. Dependency Injection Container Registration
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

// Service Lifetime Registrations
builder.Services.AddTransient<IEmailSender, SmtpEmailSender>();      // Created on every injection
builder.Services.AddScoped<IOrderRepository, SqlOrderRepository>(); // Created once per HTTP request
builder.Services.AddSingleton<ICacheManager, MemoryCacheManager>();  // Single instance per application lifetime

var app = builder.Build();

// 2. Middleware Pipeline (Bi-directional Request/Response Chain)
if (app.Environment.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
    app.UseSwagger();
    app.UseSwaggerUI();
}
else
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

// Authentication MUST precede Authorization
app.UseAuthentication();
app.UseAuthorization();

app.MapControllers();

app.Run();

7.2 Service Lifetimes in Dependency Injection

LifetimeMethodCreation ScopeIntended Use Case
TransientAddTransient<T, U>()Every time requestedLightweight, stateless operations (e.g. calculators, formatters)
ScopedAddScoped<T, U>()Once per HTTP RequestEntity Framework DbContext, unit-of-work repositories
SingletonAddSingleton<T, U>()Once per applicationIn-memory caches, configuration wrappers, background workers

Critical DI Anti-Pattern ("Captive Dependency"):
Registering a Scoped service (like an EF Core DbContext) as a constructor parameter inside a Singleton service captures the scoped dependency permanently, preventing disposal and creating thread-safety hazards and stale entity caches. .NET CoreCLR includes runtime scope validation to detect and prevent captive dependencies in Development environments.


8. CoreCLR Garbage Collection Generational Mechanics

Memory allocation in modern managed C# is fast (comparable to a stack pointer bump). The CoreCLR Garbage Collector manages reclamation across generations:

CODE
[Ephemeral Segment]
+--------------------------+--------------------------+--------------------------+
|       Generation 0       |       Generation 1       |       Generation 2       |
| (Short-lived allocations)| (Buffer / Aging area)    | (Long-lived objects)     |
| Small local variables    | Promoted from Gen 0      | Singletons, static caches|
| Collections: Very fast   | Collections: Fast        | Collections: Expensive   |
+--------------------------+--------------------------+--------------------------+
                                                                   |
+------------------------------------------------------------------+
|                   Large Object Heap (LOH)                        |
| Objects >= 85,000 bytes (Large arrays, bitmaps, long strings)   |
| Not compacted by default (prevents costly memory copying)        |
+------------------------------------------------------------------+
  1. Generation 0 (Gen 0): Where all newly allocated small objects enter memory. Collections occur frequently and take less than a millisecond.
  2. Generation 1 (Gen 1): Acts as a buffer between short-lived and long-lived objects. Objects surviving Gen 0 are promoted here.
  3. Generation 2 (Gen 2): Contains long-lived objects (e.g., singleton services, static configurations). Gen 2 collections (often called "Full GC") inspect the entire heap and are comparatively resource-heavy.
  4. Large Object Heap (LOH): Objects exceeding 85,000 bytes bypass Gen 0 directly to prevent heap fragmentation and expensive copying overhead during compaction.