Difference Between Middleware and Filter in C#.

Middleware Vs Filter

In ASP.NET Core, both Middleware and Filters are used to handle cross-cutting concerns such as logging, authentication, authorization, and exception handling. Although they may appear similar, they operate at different levels of the request pipeline and serve different purposes.

Understanding this difference is very important for real-world projects and is a frequently asked interview topic.

What is Middleware?

Middleware is a component that sits in the ASP.NET Core request processing pipeline and handles HTTP requests and responses.

Every incoming request passes through a series of middleware components, and each middleware can:

  • Inspect the request
  • Modify the request or response
  • Decide whether to pass control to the next middleware

Middleware is mainly used for cross-cutting concerns that apply to many or all requests.

When a request comes to an ASP.NET Core application, it flows through the middleware pipeline in the order in which they are registered.

Request Flow:

Request
Middleware 1
Middleware 2
Controller / Endpoint
Middleware 2
Middleware 1
Response

Each middleware:
  1. Executes some logic before calling the next middleware
  2. Calls the next middleware using await _next(context)
  3. Executes logic after the next middleware completes (optional)
Example of Built-in Middleware:
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
Each of these is a middleware component registered in the pipeline.

Why do we need a Middleware?

Middleware helps to:
  • Handle requests globally.
  • Keep controllers clean.
  • Centralize logic like logging, security, and error handling.
  • Improve maintainability.

How To Create Custom Middleware?

There are multiple conditions where we need to create our own custom middleware to handle incoming requests and out going response. Let's learn how to create a custom middleware and register it in the existing pipeline.

Step 1: Create a Custom Middleware Class.

In this step, we create a middleware class that contains the actual logic to handle HTTP requests and responses.
public class RequestLoggingMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger<RequestLoggingMiddleware> _logger;

    public RequestLoggingMiddleware(
        RequestDelegate next,
        ILogger<RequestLoggingMiddleware> logger)
    {
        _next = next;
        _logger = logger;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        _logger.LogInformation(
            "Request Started: {Method} {Path}",
            context.Request.Method,
            context.Request.Path);

        await _next(context);

        _logger.LogInformation(
            "Response Finished: {StatusCode}",
            context.Response.StatusCode);
    }
}

Key Terms Explained
  • RequestDelegate: A delegate representing the next middleware in the pipeline. It is calling _next(context) passes control forward.
  • HttpContext: Represents the current HTTP request and response. It contains headers, body, method, status code, user info, etc.
  • InvokeAsync Method: The method ASP.NET Core automatically calls for each request. This is where middleware logic lives.
  • ILogger: Built-in logging abstraction used instead of Console.WriteLine. Supports logging levels and providers.

Step 2: Creating an Extension Method to Register Middleware.

This step makes your middleware look and behave like a built-in middleware, allowing clean and readable registration in Program.cs.
public static class RequestLoggingMiddlewareExtensions
{
    public static IApplicationBuilder UseRequestLogging(
        this IApplicationBuilder app)
    {
        return app.UseMiddleware<RequestLoggingMiddleware>();
    }
}
  • Extension Method: A static method that adds new functionality to an existing type without modifying it.
  • IApplicationBuilder: Used to build the HTTP request pipeline. It provides methods like Use, Run, and Map.
  • UseMiddleware<T>(): Registers a middleware type into the pipeline and lets the framework manage its lifetime and dependencies.
  • Fluent API: Returning app allows chaining multiple middleware registrations.

Step 3: Register the Middleware in the Program.cs

Here, the middleware is added to the request pipeline, and its position determines when it runs.
var app = builder.Build();

app.UseRequestLogging(); // Custom middleware

app.MapControllers();

app.Run();

Now our custom Middleware is registered successfully and ready to execute for each http request and response.

What is the use of the Run, Use, and Map keywords in the Middleware pipeline?

In ASP.NET Core, Use, Run, and Map are used to configure the middleware pipeline. Each keyword has a specific purpose and behavior.

1. Use: Use is used to add middleware that can pass control to the next middleware.
app.Use(async (context, next) =>
{
    Console.WriteLine("Before next middleware");
    await next();
    Console.WriteLine("After next middleware");
});

2. Run: Run adds a terminal middleware that does not call the next middleware.
app.Run(async context =>
{
    await context.Response.WriteAsync("Request handled here");
});

3. Map: A map is used to branch the request pipeline based on URL path.
app.Map("/admin", adminApp =>
{
    adminApp.Run(async context =>
    {
        await context.Response.WriteAsync("Admin area");
    });
});
Only requests starting with /admin go through this branch.

Common Use Cases of Middleware
  • Global exception handling
  • Authentication & authorization
  • Logging and auditing
  • Request/response modification
  • CORS
  • Rate limiting

What is a Filter?

A Filter is a component in ASP.NET Core that allows you to run custom logic before or after a controller action executes.
Filters are part of the MVC/Web API pipeline, not the global middleware pipeline.

Filters are mainly used for action-level cross-cutting concerns, such as:
  • Authorization
  • Validation
  • Logging
  • Exception handling
  • Modifying responses

Types of Filters.

ASP.NET Core provides five types of filters, each executing at a specific stage of the MVC request pipeline. Filters help handle cross-cutting concerns such as authorization, validation, logging, caching, and exception handling.

1. Authorization Filters

Authorization filters run first in the filter pipeline. They determine whether a user is allowed to access a controller or action.

If authorization fails, the request is short-circuited, and the action never executes.

2. Resource Filters

Resource filters run before model binding and after action execution. They are useful for caching, short-circuiting, or resource initialization.

3. Action Filters (Most Common)

Action filters run before and after controller action methods. They are commonly used for logging, validation, and auditing.

4. Result Filters

Result filters run before and after the action result executes (like Ok(), View()). They are useful for modifying responses.

5. Exception Filters

Exception filters handle exceptions thrown by controller actions.

How do filters work?

In ASP.NET Core, filters execute around a controller action and allow you to run logic before and after specific stages of request processing. Unlike middleware, filters are MVC-specific and are tightly coupled with controllers and actions.

Let’s understand the execution flow step by step using a real example.

Filter Execution Flow:
When a request reaches an MVC controller, it passes through filters in the following order:
Request
Authorization Filter
Resource Filter
Action Filter (Before)
Controller Action
Action Filter (After)
Result Filter
Response
If an exception occurs, Exception Filters are invoked.

Example: Logging Action Filter.

Step 1: Create a Custom Action Filter.
using Microsoft.AspNetCore.Mvc.Filters;

public class LogActionFilter : IActionFilter
{
    public void OnActionExecuting(ActionExecutingContext context)
    {
        Console.WriteLine("Before Action Method");
    }

    public void OnActionExecuted(ActionExecutedContext context)
    {
        Console.WriteLine("After Action Method");
    }
}

Step 2: Apply Filter to Controller
[LogActionFilter]
public class ProductsController : Controller
{
    public IActionResult Get()
    {
        Console.WriteLine("Inside Controller Action");
        return Ok("Products");
    }
}

Step-by-Step Execution (What Happens Internally)

1. Request arrives at MVC: The request has already passed through middleware and is now handled by MVC.
2. Authorization Filters run: ASP.NET Core checks whether the request is authorized to access the action.
3. Resource Filters run: These execute before model binding and can short-circuit the request.
4. Action Filter – OnActionExecuting
Before Action Method
This runs just before the controller action executes.

5. Controller Action Executes
Inside Controller Action

6. Action Filter – OnActionExecuted
After Action Method
This runs immediately after the action method completes.

7. Result Filters execute: These run before and after the action result (e.g., Ok()).
8. Response is returned to the client.

Use Filters when:
  • Logic is tied to MVC actions
  • You need access to model/action parameters
  • Behavior is controller/action specific

Middleware Vs Filter.

Feature Middleware Filter
Scope Global (entire application) MVC / Controller / Action
Execution Level Request pipeline (before MVC) Inside the MVC pipeline
Access to Action Context No Yes
Order Control Registration order in the Program.cs Filter type and order attribute
Can Short-Circuit Request Yes Yes
Dependency on MVC No Yes
Runs for Static Files Yes No
Common Use Cases Logging, Auth, Exception handling Validation, Authorization, Action logging
Performance Faster (framework-level) Slightly slower (MVC-specific)

Use Middleware when you need to handle cross-cutting concerns globally for every HTTP request, such as authentication, logging, CORS, or exception handling, and when the logic is not tied to MVC controllers. Use Filters when the logic is specific to MVC actions or controllers, requires access to action parameters, model state, or results, and should run before or after controller execution, such as validation, authorization at the action level, or action-specific logging.

Value Types vs Reference Types in C#

Understanding the difference between Value Types and Reference Types is one of the most important fundamentals in C#. It directly impacts memory usage, performance, method behavior, and bug prevention.

In this article, we will explore what value types and reference types are, how they behave in memory, how assignment and method calls differ between them, and when to use each one in real applications.

What is Value Type in C#?

Value types store actual data directly. When a value type variable is assigned to another variable, a copy of the data is created. Each variable maintains its own independent copy.

Common value types include:

  • int
  • float, double, decimal
  • bool
  • struct
  • enum
Example:
int a = 10;
int b = a;

b = 20;

Console.WriteLine(a); // 10
Console.WriteLine(b); // 20
Here, changing b does not affect a because b received a copy of a.

What is Reference Type in C#?

Reference types store a reference (address) to the actual data rather than the data itself. When a reference type variable is assigned to another variable, both variables point to the same object in memory.

Common reference types include:
  • class
  • string
  • array
  • object
  • interface
  • delegate
Example:
class Person
{
    public int Age;
}

Person p1 = new Person { Age = 25 };
Person p2 = p1;

p2.Age = 30;

Console.WriteLine(p1.Age); // 30
Both p1 and p2 refer to the same object, so changes made through one reference affect the other.

Pass By Value Vs Pass By Reference.

In C#, how data is passed to a method determines whether the original value can be changed. This is commonly explained using pass by value and pass by reference.

1. Pass By Value: Pass by value means a copy of the variable is passed to the method. Any change made inside the method does not affect the original variable. By default, all method parameters in C# are passed by value.

Example
void ChangeValue(int number)
{
    number = 50;
}

int x = 10;
ChangeValue(x);

Console.WriteLine(x); // Output: 10
Here, number receives a copy of x. Modifying the number does not change x.

2. Pass By Reference: Pass by reference means the method receives a reference to the original variable itself, allowing the method to modify the original variable. In C#, this is done using the ref or out keywords.

Example Using ref:
void ChangeValue(ref int number)
{
    number = 50;
}

int x = 10;
ChangeValue(ref x);

Console.WriteLine(x); // Output: 50
Here, the method modifies the original variable directly.

Example Using out:
void GetValues(out int result)
{
    result = 100;
}

int x;
GetValues(out x);

Console.WriteLine(x); // Output: 100
out is used when the method is expected to assign a value.

How Memory Allocation Works in C#?

In C#, memory is mainly managed using two logical areas: the stack and the heap. Understanding how they work helps explain performance, object lifetime, and behavior of value and reference types.

Stack Memory

The stack stores value types and method call information. Memory allocation on the stack is very fast and is automatically cleaned up when a method finishes execution.

Key points:

  • Stores local value-type variables
  • Follows Last-In-First-Out (LIFO)
  • Memory is freed automatically when the scope ends
Example:
void Test()
{
    int x = 10;   // stored on stack
}
When Test() ends, x is automatically removed from the stack.

Heap Memory

The heap stores reference-type objects. Memory allocation on the heap is slower, and cleanup is handled by the Garbage Collector.

Key points:
  • Stores objects created using new
  • Accessed via references
  • Cleaned by GC, not immediately
Example:
class Person
{
    public int Age;
}

void Test()
{
    Person p = new Person(); // object on heap, reference on stack
}
Here, p is on the stack, but the actual Person object is on the heap.

Why is string Immutable but still a Reference Type in C#?

At first glance, strings look confusing because they are reference types, yet they behave like value types when modified. This design is intentional, providing safety, performance, and reliability.
Note: An immutable object is one whose state cannot be changed after creation. Any modification creates a new object instead of changing the existing one.
A string is a reference type because:
  • Strings can be large and variable in size
  • Storing them on the heap avoids costly copying
  • Multiple variables can reference the same string instance
string s1 = "Hello";
string s2 = s1;
Here, both s1 and s2 initially point to the same string object in memory.

Immutability means once a string is created, its value cannot be changed. Any operation that appears to modify a string actually creates a new string object.
string s1 = "Hello";
string s2 = s1;

s2 = "World";

Console.WriteLine(s1); // Hello
Console.WriteLine(s2); // World
The original "Hello" string is untouched; a new "World" string is created.
String is a reference type for performance reasons, but immutable to ensure security, thread safety, and safe sharing through interning.

Value types store data directly and create copies during assignment, while reference types store references to objects in memory and share the same instance across assignments. Choosing between them correctly leads to better performance, safer code, and fewer bugs.

Garbage Collction in C#.

Garbage Collection

Garbage Collection (GC) in C# is an automatic memory management feature provided by the Common Language Runtime (CLR). Its primary goal is to free memory occupied by objects that are no longer in use, preventing memory leaks and improving application stability. 

Unlike languages like C or C++, developers do not manually free memory in C#. The CLR’s garbage collector handles it automatically.

When Garbage Collection Is Needed?

When a C# application runs, objects are dynamically created on the managed heap. As the application continues executing, many of these objects become unused because they are no longer referenced. If this unused memory is not reclaimed, the application can start consuming excessive memory, experience performance degradation, and may eventually crash due to insufficient available memory. 

Garbage Collection addresses this problem by automatically identifying objects that are no longer in use, releasing the memory occupied by those objects, and compacting the heap to improve memory efficiency and performance.

These are the tasks that Garbage Collection performs behind the scenes.

  • Identifies which objects are still in use (reachable from GC roots)
  • Detects objects that are no longer referenced
  • Reclaims memory occupied by unused objects
  • Compacts the managed heap to reduce fragmentation
  • Updates object references after compaction
  • Promotes surviving objects to older generations
  • Improves memory availability and application performance

Generation in Garbage Collection.

The C# Garbage Collector uses a generational model based on a simple but powerful assumption:
Most objects are short-lived. To optimize performance, objects are grouped into generations based on their longevity. Each generation is collected at different frequencies.

1. Generation 0 (Gen 0)

Generation 0 contains newly created objects. Almost every object starts its life here. It is collected very frequently because most objects become unused quickly. A Gen 0 collection is fast and inexpensive.
If an object survives a Gen 0 collection, it is promoted to Generation 1.

Example:
void CreateObjects()
{
    int x = 10;
    var temp = new object();   // Gen 0 object
}
Once CreateObjects() finishes, temp is no longer referenced and will likely be collected in the next Gen 0 GC.

Typical Gen 0 objects:
  • Temporary objects
  • Method-local objects
  • Short-lived calculations

2. Generation 1 (Gen 1)

Generation 1 acts as a buffer between Gen 0 and Gen 2. It contains objects that survived at least one garbage collection. Objects in Gen 1 are collected less frequently than Gen 0. If they survive a Gen 1 collection, they are promoted to Generation 2.

Example:
class CacheItem
{
    public string Data { get; set; }
}

CacheItem item = new CacheItem(); // Starts in Gen 0
If the item is still referenced after a Gen 0 GC, it moves to Gen 1.

Typical Gen 1 objects:
  • Objects with medium lifetime
  • Temporary caches
  • Objects shared across a few methods

3. Generation 2 (Gen 2)

Generation 2 contains long-lived objects that remain in memory for a long time. Gen 2 collections are infrequent and expensive, but they clean a large portion of memory. Objects in Gen 2 usually stay there until the application ends or the reference is explicitly removed.

Example:
class AppConfig
{
    public static AppConfig Instance = new AppConfig();
}
Because Instance is static, it remains alive throughout the application’s lifetime and eventually ends up in Gen 2.

Typical Gen 2 objects:
  • Static objects
  • Singletons
  • Long-lived caches
  • Application-wide configuration data

Large Object Heap (LOH)

Objects larger than 85,000 bytes are allocated on the Large Object Heap, which is logically part of Gen 2.
  • LOH objects are collected only during Gen 2 GC
  • Not compacted by default (to avoid performance cost)
Example:
byte[] largeArray = new byte[100_000]; // LOH

In short:
  • Gen 0 collections are fast and frequent
  • Gen 1 filters objects before reaching Gen 2
  • Gen 2 collections are rare but thorough
  • Improves overall performance and responsiveness
Generation Lifetime Collection Frequency
Gen 0 Short-lived Very frequent
Gen 1 Medium-lived Less frequent
Gen 2 Long-lived Rare
LOH Very large objects During Gen 2

How Garbage Collection is Triggered Automatically?

When a C# application is running, objects are constantly being allocated on the managed heap. The CLR keeps track of these allocations and monitors the available free memory. Garbage Collection is automatically triggered when the CLR detects that continuing allocations without cleanup would negatively impact performance or stability.

The most common automatic triggers are:
  • The managed heap does not have enough free space for new allocations
  • Allocation pressure becomes high (too many objects being created quickly)
  • A generation threshold is exceeded (Gen 0, Gen 1, or Gen 2)
  • The system is under memory pressure (low available RAM)
  • The application enters certain runtime phases (for example, during idle time)
  • At this point, the CLR decides on its own that a garbage collection cycle is required and pauses the application briefly to perform it.

How To Manually Call Garbage Collection in C#?

First of all, it is never recommended to call GC manually by a developer, and it is completely handled by CLR. However, there are rare, controlled scenarios where forcing garbage collection can make sense.

Example: Imagine a console application that processes a huge amount of data, creates large objects, and then finishes its work.
using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        Console.WriteLine("Application started");

        CreateLargeObjects();

        Console.WriteLine("Large objects created and released");

        // Force garbage collection
        GC.Collect();
        GC.WaitForPendingFinalizers();
        GC.Collect();

        Console.WriteLine("Garbage collection completed");

        Console.ReadLine();
    }

    static void CreateLargeObjects()
    {
        List<byte[]> largeData = new List<byte[]>();

        for (int i = 0; i < 10; i++)
        {
            // Each array is ~10 MB
            largeData.Add(new byte[10_000_000]);
        }

        // Remove references
        largeData = null;

        Console.WriteLine("References removed");
    }
}

What Happens in This Example
  • The application allocates large objects (LOH).
  • References are explicitly removed.
  • GC.Collect() forces garbage collection.
  • GC.WaitForPendingFinalizers() ensures finalizers run.
  • Memory is reclaimed immediately.
This is a controlled environment, where the developer knows exactly when memory is no longer needed.

What is the use of Dispose() method in C#?

The Dispose() method is used to explicitly and immediately release unmanaged resources such as file handles, database connections, network sockets, or native memory. It provides deterministic cleanup, meaning the developer controls when the resources are freed instead of waiting for the Garbage Collector.

Garbage Collection only frees managed memory. It does not know how or when to release unmanaged resources. If these resources are not released promptly, the application can run out of OS-level resources even if enough memory is available.

Dispose() solves this by allowing the developer to clean up resources as soon as they are no longer needed.

Example:
class FileLogger : IDisposable
{
    private StreamWriter _writer = new StreamWriter("log.txt");

    public void Write(string message)
    {
        _writer.WriteLine(message);
    }

    public void Dispose()
    {
        _writer.Dispose(); // releases file handle immediately
        Console.WriteLine("Resources released using Dispose()");
    }
}
Usage:
using (var logger = new FileLogger())
{
    logger.Write("Hello");
} // Dispose() is called automatically here

Key Points
  • Dispose() releases unmanaged resources immediately.
  • It is called explicitly by the developer or via the using keyword.
  • Provides predictable and safe cleanup.
  • Preferred over Finalize() for resource management.
Dispose() is used to deterministically release unmanaged resources as soon as they are no longer needed, improving performance and reliability.

What is the use of Finalizer in C#?

The Finalize method (finalizer) is used to clean up unmanaged resources if they were not released explicitly using Dispose(). It acts as a last-resort safety mechanism and is automatically called by the Garbage Collector before an object’s memory is reclaimed.

Example:
class NativeResource
{
    ~NativeResource()
    {
        // Release unmanaged resource
        Console.WriteLine("Finalize called");
    }
}
If an object of NativeResource is not disposed properly, the GC will eventually call Finalize() to clean up the unmanaged resource.

Best Practices for Garbage Collection

  • Avoid unnecessary object creation
  • Reuse objects when possible
  • Dispose of unmanaged resources properly
  • Avoid manual GC.Collect()
  • Use using for streams, files, and DB connections
  • Be careful with static references

How C# Code Execution Takes Place?

When you press Build or Run in Visual Studio or execute "dotnet run", a lot happens behind the scenes. While we write simple C# programs, the .NET runtime performs multiple sophisticated operations to turn that high-level code into instructions your CPU can understand.

In this article, we will discuss how C# code is compiled, loaded, converted, and executed inside the .NET runtime, with all intermediate steps clearly explained.

Several steps take place behind the scenes, and we will understand each of them one by one in sequence.

step-by-step-diagram-of-C-sharp-code-execution

Step 1: Write a C# Code.

Everything begins with a .cs file that contains C# source code. These files contain human-readable instructions written in the C# programming language. But your computer cannot execute C# directly, so it needs to be converted several times before execution.

using System;

namespace MyApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World");
        }
    }
}

Step 2: The Role of the C# Compiler (Roslyn)

When you write C# code in Program.cs, that code is not directly understood by your CPU. There’s a critical component in between: the C# compiler, also known as Roslyn.

Understanding how the C# compiler (Roslyn) works is key to understanding:

  • How your C# source turns into something runnable.
  • Why do you see certain errors at compile time?
  • How tools like IntelliSense, analyzers, and refactorings work so “smartly” in IDEs.

Let’s walk through this step by step.

What is Roslyn?

Roslyn is the official C# and Visual Basic .NET compiler platform from Microsoft. It converts your C# code into IL (Intermediate Language), also known as CIL (Common Intermediate Language).

Intermediate Language (IL), also known as Common Intermediate Language (CIL) or formerly Microsoft Intermediate Language (MSIL), is a low-level, object-oriented, stack-based bytecode instruction set.

Along with IL, Roslyn also produces metadata that contains type definitions (classes, structs, enums), method signatures, properties, fields, and references to other assemblies.

IL + Metadata is the final output of the Roslyn Compiler.

After compilation of your source code, your project produces assembly:

  • .exe file → console app / Windows app
  • .dll file → class library

Both contain IL Code + Metadata + Manifest (Assembly name, version, culture, references, entry point). These files are platform-independent and can run on Windows, Linux, Mac, or any OS that supports .NET.

Step 3: Role of CLR (Common Language Runtime)

The Common Language Runtime (CLR) is the heart of the .NET runtime environment.
Just like the Java Virtual Machine (JVM) for Java, the CLR is the execution engine that runs applications written in C#, F#, VB.NET, and other .NET languages.

What does CLR do in C# Code Execution

What does CLR do?

The CLR performs many tasks to ensure that your program runs smoothly. Let's understand each role one by one:

Role 1. Loads and Verifies Assembly.

When you run a .NET application, the CLR reads the manifest present inside the (.exe or .dll) and loads the assembly into your memory. It also verifies the IL code and prepares it for execution. This is the first job of the CLR - loading your compiled IL into the runtime environment.

Role 2: JIT Compilation.

IL cannot run directly on your processor, so the CLR uses the JIT (Just-In-Time) compiler to convert IL into native machine code just before execution. JIT compiles methods only when needed to improve startup time, memory usage, and overall performance.

JIT is one of the biggest strengths of the CLR, giving you portability + performance.

Role 3: Memory Allocation.

The CLR allocates memory on the managed heap and keeps track of the objects. You don't need to manually allocate memory because the CLR handles everything.

Role 4: Garbage Collection.

CLR includes Garbage Collection (GC), which finds unused objects and frees memory automatically to prevent memory leaks. This gives C# extremely efficient memory handling without manual malloc/free.

Garbage Collection works in three generations:

Gen 0: The youngest generation, where all new objects are initially allocated. This is where the majority of short-lived objects reside. Garbage collection runs most frequently in this generation to quickly reclaim memory from objects that are no longer in use. 

Gen 1: Objects that have survived a collection in Generation 0 are moved to this generation. These objects are considered to be slightly longer-lived than those in Gen 0. Collection here happens less frequently than in Gen 0.

Gen 2: Objects that survive collection in Generation 1 are moved to this, the oldest generation. This generation holds the long-lived or "permanent" objects that have survived multiple collection cycles. Garbage collection runs least frequently in this generation, as it's assumed these objects will be in use for a long time.

Role 5: Exception Handling

CLR provides a structured and unified exception system. If something goes wrong:

  • CLR throws an exception object
  • Stops the current execution path
  • Jumps to the nearest matching catch
  • Ensures cleanup using finally

Role 6: Thread Management

Thread management is one of the most critical responsibilities of the Common Language Runtime (CLR). The CLR provides a managed, safe, and optimised threading model, which frees developers from dealing with complex low-level details like context switching, CPU scheduling, and memory synchronisation.

Role 7: Security Checks

The CLR enforces multiple layers of security to ensure that .NET applications run safely and do not harm the system. It guarantees type safety, preventing invalid type conversions and illegal memory access. Through Code Access Security (CAS), the CLR restricts what code can do based on its origin and granted permissions, such as blocking untrusted code from accessing files, the registry, or network resources.

So these are some basic operations that take place when building and running your C# Code.

Short Quick Answer: C# code is first compiled by the Roslyn compiler into IL (Intermediate Language) and stored in an assembly (.dll or .exe). When the program runs, the CLR loads this IL and the JIT compiler converts it into native machine code for the current processor. The runtime then executes this native code and handles memory using the Garbage Collector.

DON'T MISS

Tech News
© all rights reserved
made with by AlgoLesson