Showing posts with label .Net Core. Show all posts
Showing posts with label .Net Core. Show all posts

Saturday, April 4, 2026

Thread Vs Task

 Thread:
A Thread is a low-level OS-managed unit of execution.
Key characteristics:
  • Directly managed by the operating system
  • Has its own stack and execution context
  • Runs independently
Created using:
Thread t = new Thread(() => DoWork());
t.Start();


Thread t = new Thread(() => DoWork());
t.Start();

Downsides:
  • Expensive to create and destroy
  • Harder to manage (synchronization, lifecycle)
  • Can lead to performance issues if overused

Task
A Task is a high-level abstraction for asynchronous work, built on top of threads.

Key characteristics:
  • Part of the Task Parallel Library (TPL)
  • Uses thread pool threads internally
  • Easier to manage and compose
  • Supports async/await
Task.Run(() => DoWork());

Example:

using System;
using System.Threading.Tasks;

class Program
{
    static async Task Main(string[] args)
    {
        Console.WriteLine("Start");

        await DoWorkAsync();

        Console.WriteLine("End");
    }

    static async Task DoWorkAsync()
    {
        Console.WriteLine("Working...");

        // Simulate a delay (like API call or DB query)
        await Task.Delay(2000);

        Console.WriteLine("Work completed");
    }
}

Key Differences

Feature                    Thread                                Task
Level                 Low-level (OS)         High-level (.NET abstraction)
Management         Manual                         Managed by runtime
Performance         Heavyweight                 Lightweight
Thread Pool         No (manual control) Yes (uses thread pool)
Async support No built-in                 Yes (async/await)
Error handling Harder                         Easier (try/catch, await)

Simple Example

Thread:
new Thread(() => Console.WriteLine("Hello from Thread")).Start();
Task:
await Task.Run(() => Console.WriteLine("Hello from Task"));

Real-World Analogy
  • Thread = Hiring a full-time worker 
  • Task = Assigning a job to a worker pool 

You don’t care who does the job (Task), just that it gets done efficiently.


When to Use What?

Use Task (Recommended)
  • Most modern apps
  • Async operations (I/O, APIs, DB calls)
  • Parallel processing
Use Thread (Rare cases)
  • Need full control over execution
  • Long-running dedicated background work
  • Specialized scenarios (e.g., real-time systems)

Key Takeaway
  • Thread = execution unit
  • Task = work abstraction

In modern .NET, you almost always prefer Task over Thread.

Saturday, February 21, 2026

Web API - Caching

Note: Response/Output cache handled by their respective middlewares and do not hit controller in subsequent requests until cache invalidated.
Data Cache (IMemorycache, Memcache, Redis): Managed by code, you check in code if data available in cache then serve else reproduce and serve.

1. Output Caching (Recommended for .NET 7+)

Starting in ASP.NET Core 7+, Microsoft introduced built-in Output Caching Middleware, which is the best way to cache full API responses.

Step 1: Register Output Caching

In Program.cs:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddOutputCache();

var app = builder.Build();

app.UseOutputCache();

app.MapControllers();

app.Run();

Step 2: Apply Caching to an Endpoint
[HttpGet]
[OutputCache(Duration = 60)]
public IActionResult GetProducts()
{
return Ok(GetProductsFromDatabase());
}

🔹 This caches the response for 60 seconds.
🔹 Works great for GET endpoints.


Advanced Example (Custom Policy)
builder.Services.AddOutputCache(options =>
{
options.AddPolicy("MyPolicy", policy =>
policy.Expire(TimeSpan.FromMinutes(5))
.SetVaryByQuery("category"));
});

Then:

[OutputCache(PolicyName = "MyPolicy")]

2. Response Caching (HTTP Cache Headers)

This uses HTTP headers like Cache-Control. It works with browser/proxy caching.

Enable Middleware
builder.Services.AddResponseCaching();
app.UseResponseCaching();
Use Attribute
[ResponseCache(Duration = 60)]
[HttpGet]
public IActionResult GetProducts()
{
return Ok(data);
}

🔹 This sets HTTP headers.
🔹 It does NOT cache on the server by default.
🔹 Good for public APIs.


3. Data Cache 
In-Memory Caching (IMemoryCache)

Best when you want to cache data, not full HTTP responses.

Register
builder.Services.AddMemoryCache();
Use in Controller
private readonly IMemoryCache _cache;

public ProductsController(IMemoryCache cache)
{
_cache = cache;
}

[HttpGet]
public IActionResult GetProducts()
{
if (!_cache.TryGetValue("products", out List<Product> products))
{
products = GetProductsFromDatabase();

var cacheOptions = new MemoryCacheEntryOptions()
.SetSlidingExpiration(TimeSpan.FromMinutes(5));

_cache.Set("products", products, cacheOptions);
}

return Ok(products);
}

4. Distributed Caching (Redis, SQL Server)

For multi-server environments, use distributed cache.

Common choice:

  • Redis: Redis can store complex data types like Lists, arrays, Hash tables etc.

  • Memcached: Simple text string store 

Example Setup with Redis
builder.Services.AddStackExchangeRedisCache(options =>
{
options.Configuration = "localhost:6379";
});

Then inject IDistributedCache.


FeatureMemcachedRedis
DistributedYesYes
ReplicationNo (basic)Yes
PersistenceNoYes
Data loss riskHigherLower
ComplexitySimpleAdvanced



Which One Should You Use?

ScenarioRecommended
Cache full API response    OutputCache
Scale across multiple servers    Redis (Distributed Cache)
Cache DB results only    IMemoryCache
Browser/proxy caching    ResponseCache

Best Practice Tips
  • Cache only GET requests.
  • Avoid caching user-specific data unless using VaryBy.
  • Always define expiration.
  • Invalidate cache on data update.
  • Use distributed cache in production with multiple instances.

Output cache and Response Cache both stores whole response handled by middleware, only difference is storage location. 

Response Caching vs Output Caching
FeatureResponse CachingOutput Caching
Where caching happensClient / Proxy (browser, CDN)Server (inside ASP.NET Core)
MiddlewareUseResponseCaching()UseOutputCache()
Actually stores response on server?NoYes
Performance benefit for serverMinimalSignificant
Best forPublic APIsHigh-performance APIs
IntroducedEarly ASP.NET Core versions.NET 7

Sunday, November 9, 2025

Dotnet Core - Response Caching vs Output Caching

 ⚖️ Response Caching vs Output Caching in ASP.NET Core

AspectResponse CachingOutput Caching
PurposeInstructs clients (like browsers) and proxies to cache responsesCaches the actual server-generated response in memory (on the server)
Caching LocationClient-side (browser, CDN, proxy)Server-side (in ASP.NET Core memory or distributed cache)
ImplementationUses HTTP Cache-Control headers and middlewareUses the new OutputCache Middleware (ASP.NET Core 7+)
How it WorksAdds headers like Cache-Control, Vary, etc. → tells browser/CDN when to reuse responsesMiddleware saves response output → reuses for identical requests without re-running controller/action
ScopeWorks outside server (helps client cache responses)Works inside server (bypasses controller execution)
Configuration Examplecsharp\n[ResponseCache(Duration = 60, Location = ResponseCacheLocation.Client)]\ncsharp\napp.UseOutputCache();\n[OutputCache(Duration = 60)]\n
DependenciesRelies on clients or CDNs honoring headersFully managed by ASP.NET Core runtime
Use CaseStatic or semi-static responses (e.g., images, GET APIs)Heavy computation APIs, views, or controller actions with repeated requests
Introduced in.NET Core 1.0+.NET 7.0+
InvalidationControlled by headers (no-cache, max-age)Controlled programmatically (OutputCacheStore can evict or tag invalidations)


🧩 Example Scenarios

  • Response Caching

    • Browser caches a product list API for 60 seconds.
    • CDN serves cached version — no new request hits your API.
    • Great for read-heavy GET endpoints.
  • Output Caching

    • Server caches rendered HTML for /home/index or JSON for /api/dashboard.
    • Subsequent requests return cached result from memory — controller not even called.
    • Great for high CPU or DB-intensive endpoints.

🔧 Combined Use

You can combine both:

  • Server caches the response using Output Cache.
  • Sends ResponseCache headers to help client/CDN reuse it.

This provides multi-level caching — server + client.

Dotnet Core - Performance Tuning of Applications

 🚀 How to Improve Performance in ASP.NET Core Applications

Performance optimization in .NET Core is multi-layered, covering areas from code-level tuning to infrastructure scaling.
Here’s a structured breakdown:





🧱 1. Use Built-in Caching

🔹 Memory Cache (for small-scale, single-server)

builder.Services.AddMemoryCache(); public class ProductService { private readonly IMemoryCache _cache; public ProductService(IMemoryCache cache) => _cache = cache; public Product GetProduct(int id) { return _cache.GetOrCreate($"product_{id}", entry => { entry.SlidingExpiration = TimeSpan.FromMinutes(5); return LoadProductFromDb(id); }); } }

🔹 Distributed Cache (for load-balanced apps)

Use Redis, SQL Server, or AWS ElastiCache.

builder.Services.AddStackExchangeRedisCache(options => { options.Configuration = "localhost:6379"; });

Benefit: Reduces DB hits and speeds up responses.


⚙️ 2. Enable Response Caching

Cache HTTP responses for static or infrequently changing data.

builder.Services.AddResponseCaching(); app.UseResponseCaching();
[ResponseCache(Duration = 60)] public IActionResult GetWeather() => Ok("Sunny");

Benefit: Reuses responses instead of regenerating data.


⚡ 3. Use Asynchronous Code

ASP.NET Core is non-blocking. Always use async/await for I/O operations:

public async Task<IActionResult> GetProductsAsync() => Ok(await _db.Products.ToListAsync());

Benefit: Frees up threads → handles more concurrent requests.


🧰 4. Optimize Entity Framework Core

  • Use AsNoTracking() for read-only queries.
  • Fetch only needed columns via Select().
  • Use compiled queries for hot paths.
  • Use connection pooling.

Example:

var products = await _context.Products .AsNoTracking() .Select(p => new { p.Id, p.Name }) .ToListAsync();

Benefit: Reduces EF overhead and memory allocations.


🧩 5. Compression & Minification

Enable Response Compression middleware:

builder.Services.AddResponseCompression(); app.UseResponseCompression();

Compresses JSON, HTML, CSS, etc., reducing network load.


💾 6. Use Data Transfer Optimization

  • Use DTOs to avoid over fetching large models.
  • Paginate results.
  • Use gzip/brotli compression and HTTP/2.

🌐 7. Use CDN & Static File Optimization

Host static assets (JS, CSS, images) on a CDN like CloudFront.
Also, use cache headers:

app.UseStaticFiles(new StaticFileOptions { OnPrepareResponse = ctx => { ctx.Context.Response.Headers.Append("Cache-Control", "public,max-age=604800"); } });

🧮 8. Connection & Pooling

Use IHttpClientFactory for efficient, pooled HTTP calls:

builder.Services.AddHttpClient("MyClient");

Avoids socket exhaustion caused by frequent new HttpClient instances.


🧠 9. Reduce Middleware Overhead

Register only necessary middleware, and put frequently used ones first (e.g., authentication before routing).


🧩 10. Use Output Caching (ASP.NET Core 7+)

Output caching stores full HTTP responses:

builder.Services.AddOutputCache(); app.UseOutputCache();
[OutputCache(Duration = 60)] public IActionResult GetProducts() => Ok(Products);

Much faster than recomputing each request.


☁️ 11. Use Cloud & Deployment Optimization (AWS Context)

On AWS, you can:

  • Use Elastic Beanstalk or ECS/EKS for autoscaling.
  • Add AWS ElastiCache for distributed caching.
  • Use AWS CloudFront CDN.
  • Add Application Load Balancer for traffic balancing.
  • Store assets in S3 instead of app server.

You can also enable AOT (Ahead-of-Time Compilation) for startup performance improvements.


🧪 12. Profiling & Diagnostics

Use tools like:

  • dotnet-trace, dotnet-counters
  • Application Insights
  • MiniProfiler
  • AWS X-Ray (for distributed tracing)

✅ Identify slow methods, DB queries, or excessive GC pressure.


🧠 13. Memory Management

  • Use Span<T>, Memory<T> for high-performance code.
  • Avoid large object allocations.
  • Prefer pooled objects (ArrayPool<T>).
  • Release disposable resources properly.

✅ Summary Table

AreaTechniqueBenefit
CachingMemory, Redis, Output CacheReduce recomputation
Async I/Oasync/awaitHandle more requests
EF CoreAsNoTracking, ProjectionOptimize DB performance
CompressionGzip, BrotliReduce payload
MiddlewareOptimize pipelineReduce latency
CDN/StaticCache headersReduce load
DiagnosticsProfilers, LogsIdentify bottlenecks

💡Summary (Short Answer)

"In ASP.NET Core, I improve performance using multi-level caching (in-memory, distributed, and output), async programming, optimized EF Core queries, response compression, and CDN-based static content delivery. I also use IHttpClientFactory for efficient HTTP calls, limit middleware overhead, and profile apps with Application Insights or AWS X-Ray to find hot spots. In cloud deployments, I leverage autoscaling and caching via AWS ElastiCache and CloudFront."

Saturday, November 8, 2025

Dotnet Core - DI(Dependency Injection) vs DIP(Dependency Inversion Principle)

 🧩 The “D” in SOLID — Dependency Inversion Principle (DIP)

Dependency Inversion Principle (DIP) is the design principle behind the idea of Dependency Injection.




🧠 What DIP States

High-level modules should not depend on low-level modules. Both should depend on abstractions.
Abstractions should not depend on details. Details should depend on abstractions.

In simpler words:

  • Instead of classes depending on concrete implementations, they should depend on interfaces or abstract classes.
  • This makes the system more flexible and loosely coupled.


🧱 Example Without DIP (Bad Design)

public class NotificationService { private EmailService _emailService = new EmailService(); public void Notify(string message) { _emailService.SendEmail(message); } } public class EmailService { public void SendEmail(string message) { Console.WriteLine($"Email sent: {message}"); } }

Problem:

  • NotificationService depends directly on a concrete EmailService.
  • If you want to switch to SmsService, you must modify NotificationService.


✅ Example With DIP (Good Design)

public interface IMessageService { void Send(string message); } public class EmailService : IMessageService { public void Send(string message) => Console.WriteLine($"Email: {message}"); } public class SmsService : IMessageService { public void Send(string message) => Console.WriteLine($"SMS: {message}"); } public class NotificationService { private readonly IMessageService _messageService; public NotificationService(IMessageService messageService) { _messageService = messageService; } public void Notify(string message) { _messageService.Send(message); } }

Now:

  • NotificationService depends on the abstraction IMessageService.
  • You can easily switch between implementations (Email, SMS, Push).

✅ This is Dependency Inversion Principle in action.


🧩 How Dependency Injection (DI) Fits In

Now that we understand DIP as a principle, here’s where DI comes in:

ConceptWhat it is
DIP (Principle)A guideline that says “depend on abstractions, not concretions.”
DI (Pattern)A technique or mechanism to implement DIP in code.

🔄 Relationship Between DIP and DI

Let’s visualize it:

DIP → is the principle (what you should do) DI → is the method (how you do it)

So:

  • DIP is about how classes should relate to each other (architectural rule).
  • DI is about how to supply those dependencies (technical mechanism).


🧰 Example: Applying DI to Implement DIP

In .NET Core:

var builder = WebApplication.CreateBuilder(args); builder.Services.AddScoped<IMessageService, EmailService>(); builder.Services.AddScoped<NotificationService>(); var app = builder.Build();

  • Here, DI container ensures NotificationService receives an implementation of IMessageService.
  • That’s Dependency Injection in practice.
  • And since both classes depend on abstractions, that’s Dependency Inversion Principle applied.

🧠 Summary Comparison

AspectDependency Inversion Principle (DIP)Dependency Injection (DI)
TypePrinciple (part of SOLID)Design Pattern / Technique
PurposeTo reduce coupling between high-level and low-level modulesTo supply dependencies to classes at runtime
FocusArchitecture & relationships between classesImplementation & object creation
Enforced ByDeveloper’s designFramework or DI container
In .NET CoreInterfaces like IService, IRepositoryAddScoped, AddSingleton, AddTransient

💬 Analogy

ConceptAnalogy
DIP“Don’t depend on specific brands; depend on a plug standard.”
DI“Use a socket that provides power to any plug that fits.”

🧾 Quick Recap

✅ DIP (Dependency Inversion Principle) = design principle (the “D” in SOLID)
✅ DI (Dependency Injection) = pattern / implementation of that principle
💡 DIP gives the rule, DI provides the tool to achieve it

Friday, November 7, 2025

Dotnet Core - Dependency Injection (DI)

 🧩 What is Dependency Injection (DI)?

Dependency Injection (DI) is a design pattern used to achieve loose coupling between classes and their dependencies.

In simple terms:

Instead of a class creating its own dependencies, they are provided (injected) from the outside — typically by a framework or container.

 




🧠 Example Without DI (Tight Coupling)

public class NotificationService { private readonly EmailService _emailService = new EmailService(); public void Notify(string message) { _emailService.Send(message); } }

Here:

  • NotificationService directly depends on EmailService.
  • If we want to replace EmailService with, say, SmsService, we must change the code inside NotificationService.


✅ Example With DI (Loose Coupling)

Step 1: Define Interface
public interface INotification
{
void Notify(string msg);
}


Step 2: Implement Email & SMS
public class EmailNotification : INotification
{
public void Notify(string msg)
{
Console.WriteLine("Email: " + msg);
}
}

public class SMSNotification : INotification
{
public void Notify(string msg)
{
Console.WriteLine("SMS: " + msg);
}
}


Step 3: Create NotificationService (Core Logic)

Instead of injecting just one service, inject both:

public class NotificationService
{
private readonly EmailNotification _email;
private readonly SMSNotification _sms;

public NotificationService(EmailNotification email, SMSNotification sms) //DI
{
_email = email;
_sms = sms;
}

public void SendEmail(string msg)
{
_email.Notify(msg);
}

public void SendSMS(string msg)
{
_sms.Notify(msg);
}
}

Step4: Register with DI

builder.Services.AddScoped<EmailNotification>();
builder.Services.AddScoped<SMSNotification>();
builder.Services.AddScoped<NotificationService>();


Step 5: Use in Controller / App
public class HomeController
{
private readonly NotificationService _notificationService;

public HomeController(NotificationService notificationService) //DI
{
_notificationService = notificationService;
}

public void Test()
{
_notificationService.SendEmail("Hello via Email");
_notificationService.SendSMS("Hello via SMS");
}
}

Now you can plug in any implementation (Email, SMS, Push) without changing NotificationService.


🧱 Dependency Injection in .NET Core

.NET Core has built-in support for Dependency Injection via the Microsoft.Extensions.DependencyInjection namespace.

You configure DI inside the Program.cs or Startup.cs (depending on .NET version).


🧰 Typical .NET Core DI Setup

Example — in Program.cs (.NET 6/7/8 minimal hosting model)

var builder = WebApplication.CreateBuilder(args);

// 1️⃣ Register services in DI container builder.Services.AddScoped<IMessageService, EmailService>(); builder.Services.AddScoped<NotificationService>(); var app = builder.Build(); // 2️⃣ Resolve and use service app.MapGet("/notify", (NotificationService service) => { service.Notify("Hello, .NET Core DI!"); return "Notification Sent!"; }); app.Run();

🔍 How DI Works in .NET Core

When you run the app:

  1. The service container is created by WebApplication.CreateBuilder.
  2. Services are registered using builder.Services.Add...().
  3. When a class (e.g., controller, page, or middleware) requests a dependency, the DI container creates and injects it automatically.


🔄 Service Lifetimes

LifetimeDescriptionUse Case
TransientNew instance created every time it’s requestedLightweight, stateless services
ScopedOne instance per request (HTTP scope)Web request-specific services
SingletonSingle instance for the entire app lifetimeConfiguration, caching, logging

Example:

builder.Services.AddTransient<IEmailService, EmailService>(); builder.Services.AddScoped<IUserService, UserService>(); builder.Services.AddSingleton<ILoggingService, LoggingService>();

🧠 DI Example in ASP.NET Core Controller

public interface ICustomerService { IEnumerable<string> GetCustomers(); } public class CustomerService : ICustomerService { public IEnumerable<string> GetCustomers() => new[] { "John", "Jane" }; } [ApiController] [Route("[controller]")] public class CustomerController : ControllerBase { private readonly ICustomerService _service; // Dependency is injected automatically public CustomerController(ICustomerService service) { _service = service; } [HttpGet] public IActionResult Get() { return Ok(_service.GetCustomers()); } }

✅ ASP.NET Core automatically injects CustomerService because it was registered in the DI container.


⚙️ Advanced DI Topics

1️⃣ Constructor Injection (most common)

Dependencies passed via constructor.

2️⃣ Method Injection

Dependencies passed as method parameters.

public void SendNotification([FromServices] IMessageService service) { service.Send("Message"); }

3️⃣ Property Injection

Dependency assigned via property (not common in .NET Core DI by default).


🔩 Built-in DI Container Features

  • Open Generics Support
    builder.Services.AddScoped(typeof(IRepository<>), typeof(Repository<>));

    DI Container creates instance of entity (User in below example) and provide when referred 

             public class UserController
        {
            private readonly IRepository<User> _repo;

            public UserController(IRepository<User> repo)
            {
                _repo = repo;
            }
        }


  • Service Replacement:  Simply remove MyService registration with IMyService and add new registration MyMockService with IMyService.
    This is useful when you are using some library and that has registered IMyService with MyService, so now Replace statement will replace all previous registration with new one.

    builder.Services.AddSingleton<IMyService, MyService>();
    builder.Services.Replace(ServiceDescriptor.Singleton<IMyService, MyMockService>());

  • Configuration + Options Pattern
    builder.Services.Configure<MyConfig>(builder.Configuration.GetSection("MySection"));


🧰 DI in Non-Web .NET Apps

You can also use DI in:

  • Console apps
  • Worker services
  • Background jobs

Example:

var services = new ServiceCollection(); services.AddScoped<IMessageService, EmailService>(); var provider = services.BuildServiceProvider(); var messageService = provider.GetRequiredService<IMessageService>(); messageService.Send("Hello from Console App!");

Benefits of Using DI

BenefitDescription
Loose CouplingEasier to swap implementations
TestabilityUse mocks in unit tests easily
ReusabilityServices can be reused across components
MaintainabilityReduces hard-coded dependencies
ScalabilityCentralized lifecycle management

⚠️ Common Pitfalls

MistakeImpact
Registering service with wrong lifetimeMemory leaks or inconsistent behavior
Creating new instances manually inside serviceBreaks DI chain
Overusing SingletonCan cause thread-safety issues
Circular dependenciesTwo services depend on each other — runtime error

Summary

AspectDetails
PatternDependency Injection (DI)
Built-in ContainerMicrosoft.Extensions.DependencyInjection
Registration MethodsAddSingleton, AddScoped, AddTransient
GoalLoose coupling, better testability, and flexibility
Injection MethodsConstructor (primary), Method, Property
Used InASP.NET Core, Worker Services, Blazor, Console Apps

Node | process.nextclick

process.nextTick() schedules a callback to run immediately after the current operation , before the event loop continues . It runs: Befor...