And SQL Interview Questions
And SQL Interview Questions
NET Developer
Stripping away vague theories and generic answers, this guide delivers 100+ highly
curated questions designed to test and elevate your engineering depth.
From the hidden memory overhead of boxing and unboxing to the architectural chess of the Outbox
and Strangler Fig patterns, this book bridges the gap between coding and high-performance system
design.
Whether you are aiming to ace your next technical round or searching for a bulletproof reference to
write cleaner, production-ready code—this guide is your ultimate backend blueprint.
MUHAMMAD AFZAL
(Full Stack .NET Engineer)
Contact
LinkedIn : [Link]
📌 HOW TO USE THIS GUIDE: Work through each section in order. Time yourself — most interviews allow
3–5 mins per question. Focus on WHY, not just WHAT — interviewers reward deeper reasoning.
# Question Level
What is the difference between value types and reference types in C#? Give
Q1 Medium
memory-level explanation.
Ans In C#, value types store the actual data directly, while reference types store a reference (address)
pointing to where the data lives in memory.
🔹 Memory-Level Explanation
Value Type Reference Type
Stored in Stack Heap (reference on Stack)
Holds Actual value Memory address
Examples int, bool, struct, enum class, string, array, object
Copy behavior Copies the value Copies the reference
"One important thing — string in C# is a reference type, but it behaves like a value type
because of immutability. Every modification creates a new string object on the heap."
Explain boxing and unboxing. What are the performance implications and
Q2 Hard
when does it silently happen?
Ans Boxing is converting a value type to a reference type (object). Unboxing is the reverse — converting
it back to a value type.
🔹 Memory-Level Picture
Boxing:
The value 42 that lived on the Stack is now copied and wrapped into a new object on the Heap.
Unboxing:
The value is extracted from the Heap and copied back to the Stack.
🔹 Performance Implications
Problem Why it hurts
Heap allocation Every box creates a new object on heap
Garbage Collection pressure More heap objects = more GC work
Extra CPU cycles Copy + cast operations cost time
Slower in loops 1000 iterations = 1000 allocations
Boxing seems small but in a tight loop or high-traffic API, it can cause serious performance
degradation.
🔹 How to Avoid It
"Always prefer generic collections like List<T> or Dictionary<K,V> over non-generic ones specifically to
avoid hidden boxing overhead. It's a small habit that reflects performance-aware coding."
What is the difference between string and StringBuilder? When would you
Q3 Easy
choose one over the other?
Ans string is immutable — every change creates a new object in memory. StringBuilder is mutable — it
modifies the same object in place.
🔹 Memory-Level Picture
String — New object every time:
🔹 Side-by-Side Comparison
string StringBuilder
Mutability Immutable Mutable
Memory New object each change Same object modified
Performance Slow for many changes Fast for many changes
Thread safety ✅ Safe (immutable) ❌ Not thread-safe
Namespace System [Link]
Best for Few / no changes Many concatenations
Explain the difference between == and .Equals() for strings and objects. Can
Q4 Medium
they give different results?
Ans == checks reference equality by default — are they the same object in memory? .Equals() checks
value equality — do they have the same content?
"But for strings, C# overrides == to behave like .Equals() — which is where it gets interesting."
Both are different heap objects, so both return false here — unless you override .Equals() in your
class.
When you cast string to object, == goes back to comparing references — and now they differ!
What are nullable value types (int?) and how does the compiler implement
Q5 Medium
them under the hood?
Ans By default, value types like int, bool, DateTime cannot be null — they always hold a value. int? is a
nullable value type that allows a value type to also represent null.
This is extremely common when working with databases, APIs, or optional form fields where a value
may simply not exist.
So int? is actually a struct with two fields — a boolean flag and the actual value. It still lives on the
Stack, not the Heap!
Explain the 'readonly' keyword vs 'const'. What are the key differences in
Q6 Medium
terms of compile-time vs run-time?
Ans const is a compile-time constant — value is fixed when code is compiled and never changes.
readonly is a runtime constant — value is set once, either at declaration or in the constructor, and
cannot change after that.
If the value is truly universal and will never change across any environment like Pi or
MaxPasswordLength, use const. But for anything environment-specific like connection strings, feature
flags, or startup timestamps, always use readonly — it's safer, more flexible, and avoids the cross-
assembly versioning trap.
What is the difference between 'is', 'as', and explicit casting? Which throws
Q7 Easy
and which returns null?
Ans is checks type without casting. as tries to cast and returns null if it fails. Explicit cast (Type) forces the
cast and throws an exception if it fails.
Explicit cast says — I am 100% sure this is the right type. If you are wrong, runtime punishes you with
an exception.
as is the safe version of explicit cast — it never throws, it just returns null if the cast is not possible.
The delegate variable can point to ANY method that matches its signature.
Even though Dog is an Animal, List<Dog> is NOT a List<Animal> by default. Variance solves this.
What is the 'dynamic' keyword and how does it differ from 'object'? When
Q10 Medium
not to use it?
Ans object is the base of all types — type checking happens at compile time. dynamic bypasses
compile-time checking entirely — all type resolution happens at runtime.
With object you must cast before using type-specific members. With dynamic the runtime figures it out
for you — no casting needed
🔹 Side-by-Side Comparison
object dynamic
Type checking Compile time Runtime
# Question Level
Q11 Explain the SOLID principles with a real-world .NET example for each. Hard
Ans SOLID is a set of 5 design principles that make code more maintainable, scalable, and testable. Each
principle solves a specific design problem that causes pain as software grows.
# Question Level
This class has 4 reasons to change — validation rules, database, email provider, logging format.
Change any one and you touch this class.
# Question Level
🔹 O — Open/Closed Principle
Open for extension, closed for modification.
Adding a new payment method means adding a new class — nothing existing is touched or risked.
# Question Level
# Question Level
Every subclass must honor the contract of the base — no surprises, no broken expectations.
# Question Level
Each class only depends on what it actually uses — no dead code, no forced implementations.
# Question Level
The controller doesn't care if storage is SQL or Mongo, or if AI is OpenAI or Gemini — it just uses the
abstraction. Switching providers requires zero changes to business logic.
What is the difference between abstract class and interface? When would
Q12 Medium
you choose each in C# ?
Ans An abstract class is a partially implemented base class — it can have both implemented and
unimplemented members. An interface is a pure contract — it defines what a class must do, but not
how.
# Question Level
# Question Level
Ans What is Overriding?
When we mark a method virtual in parent and override in child, the runtime decides which method to
call based on the actual object type. This is true polymorphism.
What is Hiding?
When we use the new keyword in child class, we are not overriding — we are hiding the parent method.
Now the compiler decides based on the variable type, not the actual object.
The compiler refuses to compile and forces you to explicitly resolve the conflict yourself.
# Question Level
Describe the difference between composition and inheritance. Why is
Q15 Medium
'favour composition over inheritance' good advice?
Ans Inheritance:
Inheritance is an IS-A relationship. Dog extends Animal — Dog gets all Animal behavior automatically.
It sounds convenient but it creates tight coupling between parent and child.
Composition:
Composition is a HAS-A relationship. Instead of extending a class, you inject the behavior you need as
a dependency. The class owns the capability without being locked into a hierarchy.
# Question Level
Tomorrow if you switch from SQL to MongoDB — You only write a new repository class.
Factory Pattern
"Creates objects without exposing creation logic"
When object creation is complex or depends on conditions, I use a factory to centralize that
decision. The caller just says what it wants — not how to build it.
# Question Level
Decorator Pattern
"Adds behavior to an object without changing its code"
When I need to add cross cutting concerns like logging, caching, or retry logic — I wrap the
original service in a decorator. Original class stays untouched.
# Question Level
The ChatService never knows caching exists — it just calls IAIProvider. I can stack decorators
— add logging decorator on top of caching decorator — without touching any existing code.
# Question Level
No exception thrown — just silently wrong behavior. This is the most dangerous kind of bug.
# Question Level
Explain the Strategy pattern vs the Template Method pattern. When do you
Q18 Hard
pick one over the other?
Ans Strategy Pattern
"Change the behavior by swapping the algorithm at runtime"
Strategy pattern defines a family of algorithms behind an interface and lets you switch between them at
runtime. The class delegates the behavior to whichever strategy is injected.
# Question Level
# Question Level
# Question Level
How does the .NET Garbage Collector work? Explain generations 0, 1, 2
Q19 Hard
and the LOH.
Ans The Garbage Collector automatically manages memory in .NET. Instead of manually freeing memory
like in C++, the GC periodically finds objects that are no longer referenced and reclaims their memory.
# Question Level
GC starts from root references — static variables, local variables, CPU registers — and traces every
object reachable from them. Anything not reachable is considered dead and gets collected.
Generation 0 — Newborns
Every new object starts in Gen 0. GC collects Gen 0 most frequently — hundreds of times per day. It is
small, fast, and most objects die here without ever promoting.
Generation 1 — Survivors
Objects that survive a Gen 0 collection get promoted to Gen 1. It acts as a buffer between short lived
and long lived objects. Collected less frequently than Gen 0.
What is IDisposable and the Dispose pattern? What happens if you don't
Q20 Medium
call Dispose?
Ans IDisposable is an interface with a single Dispose() method. It exists for objects that hold unmanaged
resources — database connections, file handles, HTTP clients, streams — things the Garbage
Collector cannot clean up automatically.
# Question Level
The finalizer is a safety net — if a developer forgets to call Dispose, GC eventually calls the finalizer.
But finalizers are non-deterministic — you never know when GC will run them. That is why using is
always preferred.
Explain the 'using' statement. How does the compiler transform it? Does it
Q21 Easy
call Dispose on exception?
Ans The compiler transforms using into a try/finally block under the hood. Finally block always runs —
even on exception — which guarantees disposal.
# Question Level
In the modern using var syntax, if you have multiple disposable objects in one method, they
are disposed in reverse order of declaration when the method ends. Just like a stack — last in
first out. This matters when objects depend on each other, like a SqlCommand depending on
a SqlConnection.
What is a memory leak in .NET? Can managed code have memory leaks?
Q22 Hard
Give two common causes.
Ans A memory leak in .NET is when objects are no longer needed but GC cannot collect them because
something still holds a reference. Managed code absolutely can have memory leaks — GC only
collects what is unreachable, not what is unused.
# Question Level
# Question Level
What is the difference between Span<T> and Memory<T>? Why were they
Q23 Hard
introduced?
Ans Span<T> — Stack Only, Ultra Fast
Span is a ref struct — it can only live on the stack. It is the fastest way to slice and work with
contiguous memory — arrays, strings, stack allocated memory — without copying anything.
What is the difference between 'struct' and 'class' beyond stack vs heap?
Q24 Medium
When would you make a struct?
# Question Level
Ans The common answer is struct lives on stack, class lives on heap. But the real difference goes deeper —
it is about value semantics vs reference semantics, copy behavior, identity, and mutability.
Use structs for things like GPS coordinates and date ranges — small, immutable, frequently created
values where avoiding heap allocation matters. But for anything with behavior, identity, or complex state
— it is always a class.
# Question Level
What does 'async/await' actually do? Explain the state machine the
Q25 Hard
compiler generates.
Ans async/await does NOT create a new thread. It is a compiler transformation that allows a method to
pause and resume without blocking the calling thread. While waiting for I/O — database, HTTP, file —
the thread is released back to the thread pool to serve other requests.
# Question Level
Every await becomes a state number. MoveNext runs between states. Thread is only used when
actual code runs — not during the waiting.
If you wrap this in [Link] — you waste a thread pool thread just to sit and wait. That is the wrong
tool.
# Question Level
[Link] — CPU Bound Work
[Link] pushes heavy CPU work to a thread pool thread so it does not block the calling thread —
typically the UI thread or request thread.
In an [Link] API, [Link] rarely makes sense — the calling thread is already a pool thread.
[Link] just borrows another pool thread — no real benefit, just overhead.
# Question Level
Ans async void is an async method that returns nothing. It is considered dangerous because
exceptions cannot be caught, the caller cannot await it, and failures happen silently —
often crashing the entire application.
# Question Level
[Link] Core — No Longer A Deadlock Issue
[Link] Core removed SynchronizationContext entirely. Deadlocks of that type cannot happen.
ConfigureAwait(false) is optional in application code.
Three Fixes
# Question Level
Even when result is immediately available, Task<T> still creates a heap object. Under high load —
thousands of unnecessary allocations per second.
Key Differences
Task<T> ValueTask<T>
Type Class — heap Struct — stack
Allocation Always Only when truly async
Awaited twice ✅ Safe ❌ Never await twice
Complexity Simple Slightly more careful
# Question Level
Key Difference
WhenAll WhenAny
Completes when All tasks done First task done
Use case Need all results Timeout, fastest wins
# Question Level
What happens when you await a Task that has already completed? Does
Q33 Hard
context switch happen?
Ans If you await a Task that is already completed, the await does NOT suspend the method. It continues
synchronously inline — no thread switch, no context capture, no state machine pause.
# Question Level
Hot path hits cache — await completes inline, no overhead. Cold path hits database — real suspension
happens.
# Question Level
What is the difference between lock(), Monitor, Mutex, and SemaphoreSlim?
Q34 Hard
When to use each?
Ans When multiple threads access shared data simultaneously, you get race conditions — unpredictable,
corrupted results. Synchronization primitives ensure only the right number of threads access shared
resources at a time.
Never lock on this or a public object — anyone can lock on it causing deadlocks.
# Question Level
Explain race conditions with a code example. How would you fix it using
Q35 Hard
Interlocked vs lock?
Ans When two threads read and write shared data simultaneously, results become unpredictable — each
thread overwrites the other's work.
# Question Level
Why? _counter++ is actually three steps — read value, add 1, write back. Two threads can read the
same value simultaneously and both write back — one increment is lost.
How It Works
# Question Level
Q37 What is the difference between [Link]() and [Link]() inside a loop? Medium
Key Difference
[Link] [Link] in loop
Blocks caller ✅ Yes ❌ No — use WhenAll
Async friendly ❌ No ✅ Yes
# Question Level
What is the volatile keyword in C#? When does it matter and what does it
Q38 Hard
NOT protect against?
Ans Volatile
Volatile tells the compiler and CPU — always read this variable from main memory, never cache it in
a CPU register or reorder it. It guarantees visibility across threads.
# Question Level
Explain the [Link] Core middleware pipeline. What is the difference
Q39 Medium
between Use(), Run(), and Map()?
Ans Middleware Pipeline
# Question Level
Middleware is a chain of components that process every HTTP request and response. Each component
can run logic before and after passing the request to the next component.
Key Difference
Use() Run() Map()
Passes to next ✅ Yes ❌ No Branches
Terminal ❌ No ✅ Yes Per branch
Use when General middleware End pipeline Path branching
# Question Level
What is the order of middleware execution and why does order matter? Give
Q40 Hard
an example of a bug caused by wrong order.
Ans Middleware Executes In Registration Order
Request flows top to bottom through middleware. Response flows bottom to top. The order you
register middleware in [Link] is the exact order it executes.
Request
↓
1. Logging
↓
2. Authentication
↓
3. Authorization
↓
4. Controller
↓
3. Authorization
↑
2. Authentication
↑
1. Logging
↑
Response
# Question Level
How would you write a custom middleware to log request/response time and
Q41 Medium
add a correlation ID header?
Ans The Custom Middleware
# Question Level
Register In [Link]
# Question Level
Execution Order
Request
↓
Middleware 1 (Logging)
↓
Middleware 2 (Auth)
↓
MVC Pipeline starts
↓
Authorization Filter
↓
Action Filter — OnActionExecuting
↓
Controller Action executes
↓
Action Filter — OnActionExecuted
↓
Exception Filter (if error)
↓
Result Filter
↓
Response travels back up
# Question Level
ExceptionFilter — Catches Action Exceptions Only
Register Filters
# Question Level
Conventional Routing
Conventional routing uses a URL pattern template defined globally. Every request is matched against
that pattern — controller and action names determine the route.
Key Differences
Conventional Endpoint Routing
Route resolved Late — after middleware Early — before middleware
Middleware sees route ❌ No ✅ Yes
Minimal APIs ❌ No ✅ Yes
Flexibility Limited High
# Question Level
Explain the three DI lifetimes: Transient, Scoped, Singleton. Give a real bug
Q44 Hard
caused by using Singleton for a DbContext.
Ans Transient — New Instance Every Time
A new instance is created every time it is requested from the container. Use for lightweight stateless
services.
# Question Level
# Question Level
Q45 What is a Captive Dependency? How do you detect and prevent it? Hard
OrderRepository is scoped — it should die after each request. But Singleton OrderService holds it alive
forever. Every request uses the same stale repository — same DbContext, same tracked entities,
memory grows forever.
How To Detect It
[Link] Core Warns You
How To Fix It
Match Lifetimes
Always enable ValidateOnBuild in all environments — not just development. It catches captive
dependencies the moment the app starts, before any request is served. Catching it at startup costs
nothing — catching it in production costs everything.
# Question Level
How do you inject multiple implementations of the same interface and
Q46 Medium
resolve them selectively?
Ans The Scenario
Sometimes you have multiple implementations of the same interface — multiple payment gateways,
multiple notification channels — and you need to pick the right one at runtime.
# Question Level
# Question Level
What is IServiceScopeFactory and when would you use it inside a Singleton
Q47 Hard
or background service?
Ans IServiceScopeFactory
IServiceScopeFactory creates a manual DI scope — letting you safely resolve Scoped services like
DbContext from inside a Singleton or background service that lives longer than a single request.
# Question Level
1. Background job processing queue
2. Scheduled tasks — cleanup, reports, emails
3. Event handlers in Singleton services
4. Hosted services processing messages from RabbitMQ or Azure Service Bus
IServiceScopeFactory is the correct solution whenever a long lived service needs database access. In
my projects every BackgroundService follows this pattern — create scope, resolve what you need, do
the work, dispose scope. This guarantees DbContext is never shared across operations and
connections return to pool properly.
Can you inject services into a static class or a class not managed by the DI
Q48 Medium
container? How?
Ans No — static classes and unmanaged classes cannot use constructor injection because the DI container
never creates them. But there are workarounds.
Problem
# Question Level
This works but Service Locator is considered an anti-pattern — it hides dependencies and makes
testing harder.
# Question Level
What is the difference between [FromBody], [FromQuery], [FromRoute], and
Q49 Easy
[FromForm]? Explain model binding.
Ans FromRoute — From URL Path
Model Binding
Model binding is how [Link] Core automatically maps HTTP request data to action method
parameters — so you work with C# objects instead of raw HTTP strings.
Quick Reference
Attribute Reads From Use For
FromRoute URL path Resource ID
FromQuery Query string Filters, pagination
FromBody JSON body Create/update objects
FromForm Form data File uploads
How does model validation work in [Link] Core? How do you create a
Q50 Medium
custom ValidationAttribute?
Ans Model Validation Works
[Link] Core automatically validates incoming models using Data Annotations. When [ApiController]
is present, if validation fails it returns a 400 Bad Request automatically — no manual checking needed.
# Question Level
How It Flows
Request arrives with JSON body
↓
Model binding maps JSON → RegisterDto
↓
Validation attributes checked automatically
↓
[ApiController] — ModelState invalid?
↓
❌ Returns 400 Bad Request automatically
✅ Passes to action if valid
Custom ValidationAttribute
When built-in attributes are not enough — create your own by extending ValidationAttribute.
# Question Level
For complex cross-property validation — like confirming password matches password confirmation —
Use IValidatableObject on the DTO itself instead of a custom attribute. It gives access to the entire
object during validation, which a single property attribute cannot do.
# Question Level
What is IActionResult vs ActionResult<T>? What are the advantages of using
Q51 Medium
ActionResult<T>?
Ans IActionResult — Flexible But Type Blind
IActionResult can return any HTTP response — Ok, NotFound, BadRequest. But the actual return
type is lost — Swagger cannot infer it, callers do not know what to expect.
Advantages Of ActionResult<T>
1 — Swagger Documents It Automatically
Side By Side
IActionResult ActionResult<T>
Return type known ❌ No ✅ Yes
Swagger support ❌ Manual attributes ✅ Automatic
Implicit conversion ❌ No ✅ Yes
# Question Level
Explain repeat-safe behavior in REST APIs. Which HTTP verbs are repeat-
Q52 Hard
safe and why does it matter for reliability?
Ans Repeat-Safe Behavior
Repeat-safe means calling the same request multiple times produces the same result as calling it
once. The technical term is idempotency. It matters because networks fail — clients retry requests,
and retrying must not cause duplicate data or side effects.
# Question Level
How do you implement API versioning in [Link] Core? What are the
Q53 Medium
tradeoffs of URL vs header versioning?
Ans API Versioning
When you change an API that clients already depend on, you need versioning — so existing clients
keep working while new clients use the improved version.
# Question Level
Approach 2 — Header Versioning
GET /api/orders
X-API-Version: 1.0 → V1 controller
X-API-Version: 2.0 → V2 controller
GET /api/orders?api-version=1.0 → V1
GET /api/orders?api-version=2.0 → V2
Tradeoffs
URL Header Query String
Visibility ✅ Very clear ❌ Hidden ✅ Visible
Cacheable ✅ Easy ❌ Harder ✅ Yes
REST purist ❌ URL should not change ✅ Cleaner URLs ❌ Not clean
Browser friendly ✅ Yes ❌ No ✅ Yes
Most common ✅ Industry standard Internal APIs Simple APIs
Always use URL versioning for public APIs — it is explicit, cacheable, and works perfectly in browsers
and Swagger. Header versioning I use for internal microservice APIs where clean URLs matter more
than visibility. The most important thing is picking one strategy and applying it consistently.
1. ExceptionHandler Middleware
[Link] Core provides built-in middleware:
or custom middleware:
# Question Level
Why use it
Centralized exception handling
Cleaner controllers
Better logging
Prevents exposing sensitive error details
2. ProblemDetails
ProblemDetails is a standard error response format based on RFC 7807.
Example response:
In .NET:
Why use it
Standardized API responses
Easy for frontend/mobile apps to understand
Better API consistency
Professional REST API design
What is Minimal API in .NET 6+? When would you choose it over Controller-
Q55 Medium
based APIs?
# Question Level
Ans Minimal API in .NET 6+
Minimal API is a lightweight way to build APIs in [Link] Core with less boilerplate code and minimal
setup.
Instead of creating:
Controllers
Separate action methods
Large configuration files
everything can be written directly inside [Link].
Example:
How do you implement rate limiting in [Link] Core? Explain the built-in
Q56 Hard
rate limiting middleware in .NET 7+.
Ans Rate limiting in [Link] Core?
Rate limiting is used to control how many requests a client can send within a specific time.
It helps to:
Prevent API abuse
Avoid server overload
Improve security
# Question Level
Enable middleware:
Apply it to endpoint:
# Question Level
Explain JWT authentication in [Link] Core. What are the three parts of a
Q57 Medium
JWT and what does each contain?
Ans JWT Authentication in [Link] Core
JWT (JSON Web Token) authentication is a token-based authentication mechanism used to secure
APIs.
After successful login:
Server generates a token
Client stores the token
Client sends the token in every request
Server validates the token before allowing access
Usually sent in header:
Authorization: Bearer <token>
User Login
↓
# Question Level
Server validates credentials
↓
JWT Token generated
↓
Client stores token
↓
Client sends token with requests
↓
Server validates token
↓
Access granted
1. Header
Contains:
Token type
Signing algorithm
Example:
2. Payload
Contains claims or user data.
Example:
UserId
Email
Roles
Expiration time
3. Signature
Used to verify that token is valid and not modified.
Generated using:
Header
Payload
Secret key
This provides security and integrity.
# Question Level
Verifies who the user is Verifies what the user can access
Happens first Happens after authentication
Checks identity Checks permissions
Example: Login with username/password Example: Access Admin dashboard
Returns user identity Returns access rights
Role-based:
Claims-Based Identity?
Claims-based identity stores user information as claims.
A claim is a key-value pair containing information about the user.
Examples:
Name
Email
Role
Department
UserId
Example of Claims
# Question Level
Middleware-Level Authentication
Authentication middleware validates the token or cookie and creates the user identity.
Example:
Responsibilities:
Read JWT token/cookie
Validate credentials
Create [Link]
Without this middleware:
[Authorize] will not work properly
[Authorize] Attribute
Used to protect controllers or actions.
Example:
Role-based:
Responsibilities:
Check if user is authenticated
Check roles/policies/claims
Allow or deny access
Order of Execution
Correct middleware order is very important.
Execution Flow:
Request arrives
↓
Routing Middleware
↓
Authentication Middleware
↓
Authorization Middleware
↓
[Authorize] attribute checks permissions
↓
Controller Action executes
# Question Level
How do you implement refresh tokens securely? What are the security
Q60 Hard
considerations?
Ans Implement refresh tokens securely
Refresh tokens are used to generate new access tokens without asking the user to log in again.
Usually:
Access token → short expiry (15–30 mins)
Refresh token → long expiry (days/weeks)
When access token expires:
Client sends refresh token
Server validates it
New access token is generated
Basic Flow
User Login
↓
Generate Access Token + Refresh Token
↓
Store Refresh Token securely
↓
Access Token expires
↓
Client sends Refresh Token
↓
Server validates it
↓
Generate new Access Token
# Question Level
Refresh tokens should expire.
Example:
7 days
30 days
Never create non-expiring tokens.
Security Considerations
Security Concern Solution
Token theft Use HTTPS
XSS attacks Use HttpOnly cookies
Replay attacks Refresh token rotation
Long-lived token misuse Short expiry
Database leaks Hash refresh tokens before storing
Unauthorized reuse Revoke tokens on logout
What is OAuth 2.0? Explain the Authorization Code flow with PKCE and
Q61 Hard
when to use it.
Ans OAuth 2.0?
OAuth 2.0 is an authorization framework that allows an application to access a user’s resources on
another service without sharing the user’s password.
Instead of credentials, it uses:
Access tokens
Refresh tokens (optional)
It is commonly used for:
“Login with Google / Microsoft”
API authorization between services
Core Idea
User → Grants permission → App gets token → Access API securely
Step-by-Step Flow
1. Client creates PKCE values
Code Verifier (random string)
Code Challenge (hashed version)
# Question Level
1. Role-based Authorization
Role-based authorization checks user roles only.
Example:
How it works:
User is assigned roles like Admin, User, Manager
Access is granted based on matching role
2. Policy-based Authorization
Policy-based authorization is more flexible and rule-driven.
Instead of checking only roles, it checks custom conditions (claims, logic, requirements).
Example:
# Question Level
How it works:
Policies can check:
o Claims
o Roles
o Custom logic
o Multiple conditions
# Question Level
What is the difference between Code First, Database First, and Model First
Q63 Easy
approaches in EF Core?
Ans Entity Framework provides different approaches to work with databases depending on how the project
starts: code, database, or model.
Advantages:
# Question Level
Advantages:
Best for legacy databases
Quick setup for existing DB
No need to design models manually
Disadvantages:
Less control over code
Regeneration needed if DB changes
Not ideal for clean architecture
Advantages:
Visual design approach
Easy for beginners in simple projects
Disadvantages:
Limited in modern EF Core
Rarely used today
Not flexible for large systems
# Question Level
What to ignore
1. Added
Entity is new and will be inserted into the database.
Example:
Behavior:
INSERT query will be generated
Primary key usually generated by DB
2. Modified
Entity already exists and has been changed.
Example:
Behavior:
UPDATE query will be generated
Only changed fields are updated
3. Unchanged
Entity is tracked but no changes detected.
Example:
Behavior:
No SQL operation executed
EF ignores it during SaveChanges
4. Deleted
Entity is marked for removal from database.
Example:
Behavior:
DELETE query will be generated
Removed after SaveChanges()
What is AsNoTracking()? When should you always use it and why can it
Q65 Medium
cause bugs if misused?
Ans AsNoTracking() in EF Core?
AsNoTracking() tells EF Core not to track the entity in the Change Tracker.
Normally, EF Core tracks every entity so it can detect changes and update the database later. With
AsNoTracking(), EF only reads data without tracking it.
Example:
# Question Level
2. High-performance queries
Large datasets
APIs returning data only
Search results
Why?
EF Core is not tracking the entity, so it doesn’t detect changes.
What is the N+1 query problem? Give a concrete example and show how to
Q66 Hard
fix it with Include() or explicit loading.
Ans N+1 Query Problem
The N+1 problem happens when an application executes:
1 query to get main data
N additional queries to get related data
# Question Level
Problem Impact
Slow performance
High database load
Increased latency
Not scalable for large data
# Question Level
Behavior:
Still multiple queries
But controlled and intentional
Better than naive per-query access
Solution Comparison
Approach Queries Performance Use Case
Bad (loop query) 1 + N Poor ❌ Avoid
Include() 1 Best Most common
Explicit Loading Controlled N Medium Advanced scenarios
# Question Level
ConcurrencyCheck vs RowVersion
ConcurrencyCheck RowVersion
How it works Checks specific column value Auto-incremented byte stamp
Manual update needed ✅ Yes ❌ SQL handles it
Reliability Moderate ✅ Higher
Best for Specific fields Entire row protection
# Question Level
What is a database migration? What happens if you delete a migration that
Q68 Hard
has already been applied to production?
Ans Database Migration
A migration is a versioned C# file that describes how the database schema should change — create
table, add column, drop index. EF Core tracks which migrations have been applied so schema stays in
sync with your models.
Treat migrations exactly like Git commits — you never rewrite history that others have already pulled. If
made a mistake in an applied migration, create a new corrective migration instead of touching the old
one. This keeps every environment — local, staging, production — perfectly in sync.
Explain the difference between Eager Loading, Lazy Loading, and Explicit
Q69 Hard
Loading in EF Core. What are the risks of Lazy Loading?
Ans Eager Loading — Load Everything Upfront
Related data is loaded immediately with the main query using Include. One SQL query with JOIN —
everything arrives together.
# Question Level
SELECT * FROM Orders
JOIN OrderItems ON [Link] = [Link]
JOIN Customers ON [Link] = [Link]
# Question Level
When It Helps
High traffic APIs with many short lived requests benefit most — reduces GC pressure from constant
DbContext allocation and destruction.
Restrictions It Imposes
# Question Level
How do you execute raw SQL in EF Core? What is the difference between
Q71 Medium
FromSqlRaw and ExecuteSqlRaw?
# Question Level
Ans Two Types Of Raw SQL In EF Core
FromSqlRaw is for SELECT queries — returns entities tracked by EF Core.
ExecuteSqlRaw is for INSERT, UPDATE, DELETE — returns rows affected count, no entities returned.
Key Difference
FromSqlRaw ExecuteSqlRaw
Use for SELECT INSERT, UPDATE, DELETE
Returns Entities Rows affected count
EF Tracking ✅ Yes ❌ No
LINQ chainable ✅ Yes ❌ No
# Question Level
If the join table needs extra columns like enrollment date, you still define an explicit join entity
even in EF Core 5+ — but for pure relationships the automatic approach keeps the code clean
and simple.
# Question Level
What is the difference between INNER JOIN, LEFT JOIN, RIGHT JOIN, and
Q73 Easy
FULL OUTER JOIN? When does LEFT JOIN return NULLs unexpectedly?
Ans INNER JOIN — Only Matching Rows
Returns rows where there is a match in both tables. If no match exists on either side — row is
excluded completely.
# Question Level
LEFT JOIN Customers c ON [Link] = [Link]
WHERE [Link] = 'Ahmed' -- Orders with no customer excluded! NULLs gone 💥
# Question Level
# Question Level
Same as RANK but no gaps after ties. Two rows ranked 1 — next rank is 2.
What is the difference between WHERE and HAVING? Can you use a
Q76 Medium
window function in a WHERE clause?
Ans WHERE — Filters Rows Before Grouping
WHERE filters individual rows before any grouping or aggregation happens. It cannot reference
aggregate functions.
# Question Level
Explain CROSS APPLY vs OUTER APPLY. When would you use them over
Q77 Hard
a JOIN?
Ans What Is APPLY
APPLY lets you call a table-valued function or subquery for each row of the outer table —
something a regular JOIN cannot do. It is like a correlated loop between two result sets.
# Question Level
# Question Level
Ans Recursive CTE
A recursive CTE is a CTE that references itself — it keeps repeating until no more rows are returned.
Perfect for hierarchical data like org charts, category trees, or folder structures where depth is unknown.
# Question Level
Result
What is the difference between UNION and UNION ALL? When does UNION
Q79 Easy
cause performance problems?
# Question Level
Ans UNION — Combines And Removes Duplicates
UNION combines results of two queries and removes duplicate rows. To remove duplicates it
performs a sort or hash operation internally — which costs extra CPU and memory.
Key Difference
UNION UNION ALL
Duplicates Removed Kept
Performance Slower ✅ Faster
Use when Duplicates must go Duplicates acceptable
Explain the MERGE statement. What are its common pitfalls and race
Q80 Hard
condition risks?
Ans MERGE
# Question Level
MERGE combines INSERT, UPDATE, and DELETE into a single statement. It compares a source
against a target and performs different actions based on whether rows match or not — also called
upsert.
# Question Level
What is the difference between EXISTS and IN? When does IN fail with
Q81 Hard
NULLs?
Ans EXISTS — Checks If Rows Exist
EXISTS checks whether a subquery returns any rows at all — it stops as soon as it finds the first
match. It never compares actual values, just presence.
# Question Level
When IN Fails With NULLs — The Hidden Trap
This is the most dangerous behavior. If the subquery returns even one NULL value, IN returns
UNKNOWN for non-matching rows — silently returning zero results.
What are PIVOT and UNPIVOT? Write a query to pivot monthly sales data
Q82 Medium
into columns.
Ans What Is PIVOT
PIVOT rotates rows into columns — transforms unique values from one column into multiple column
headers. Useful for reporting and summary views."
What Is UNPIVOT
UNPIVOT is the opposite — rotates columns back into rows. Normalizes wide tables back into a long
format.
# Question Level
# Question Level
What is the difference between a Clustered Index and a Non-Clustered
Q83 Medium
Index? Can a table have both?
Ans Clustered Index — The Table IS The Index
A clustered index physically sorts and stores the actual table data in index order. The leaf nodes of
the index contain the actual data rows — not pointers. A table can have only one clustered index
because data can only be physically sorted one way.
# Question Level
What is index selectivity? Why is an index on a boolean column almost
Q84 Hard
useless?
Ans Index Selectivity
Selectivity measures how unique the values in a column are. High selectivity means most values are
different — index is very useful. Low selectivity means values repeat constantly — index gives little
benefit.
# Question Level
What Is A Covering Index
A covering index includes all columns the query needs directly inside the index — so SQL Server never
needs to go back to the main table.
# Question Level
What causes a Table Scan vs Index Seek? Name five query patterns that
Q87 Hard
prevent index use.
Ans Table Scan vs Index Seek
An Index Seek jumps directly to matching rows using the index tree — fast and precise. A Table Scan
reads every single row in the table — slow on large data. SQL Server chooses based on whether it can
use an index efficiently.
# Question Level
What is a Composite Index? Explain the leading column rule and how
Q88 Hard
column order matters.
Ans Composite Index
A composite index is an index built on two or more columns together. SQL Server builds the index
tree using columns in the exact order you define them — order matters critically.
# Question Level
How do you read an Execution Plan? What do the icons Table Scan, Index
Q89 Hard
Seek, Hash Join, Nested Loop, and Sort mean?
Ans What Is An Execution Plan
An execution plan shows exactly how SQL Server executes your query — which indexes it uses,
how it joins tables, where the cost is. It is the most powerful tool for diagnosing slow queries.
Table Scan
Reads every single row in the table — no index used. Always a red flag on large tables.
Index Seek
# Question Level
Jumps directly to matching rows using index tree — fast and precise. What you always want to see.
Hash Join
Builds a hash table from smaller input, then probes it with larger input. Used when joining large
tables with no useful index. Memory intensive.
Sort
Physically sorts result set — expensive on large data. Appears when ORDER BY, DISTINCT,
GROUP BY cannot use an existing index.
What are statistics in SQL Server? How do stale statistics cause bad query
Q90 Hard
plans?
Ans Statistics
Statistics are metadata objects that tell SQL Server how data is distributed in a column — how many
rows exist, how unique values are spread, and what the data range looks like. SQL Server uses this
information to estimate row counts and choose the best execution plan.
# Question Level
# Question Level
What is the difference between a filtered index and a partial index? When
Q91 Medium
would you use one?
Ans What Is A Filtered Index
A filtered index is a non-clustered index with a WHERE clause — it only indexes a subset of rows that
match the filter condition. Smaller, faster, and cheaper to maintain than a full index.
# Question Level
Partial Index
Partial index is simply another name for filtered index — same concept, different terminology.
PostgreSQL calls it partial index, SQL Server calls it filtered index.
# Question Level
Explain the ACID properties. Give a real scenario where violating each
Q92 Medium
would cause problems.
Ans What Are ACID Properties
ACID is a set of four properties that guarantee database transactions are processed reliably and
correctly even in failures or concurrent access.
A — Atomicity
All operations in a transaction succeed together or fail together — never partially applied.
# Question Level
❌ Violation scenario:
-- Debit succeeds, server crashes before Credit
-- Account 1 lost 500 — Account 2 never received it 💥
-- Money disappeared from the system
C — Consistency
Transaction must bring database from one valid state to another — all rules, constraints, and
cascades always satisfied.
❌ Violation scenario:
-- Order created with CustomerId = 9999
-- Customer 9999 does not exist — foreign key violated
-- Database now has orphaned order — referential integrity broken 💥
I — Isolation
Concurrent transactions must not interfere with each other — each transaction sees a consistent
snapshot of data.
D — Durability
Once transaction is committed, data is permanently saved — survives crashes, power failures,
restarts.
❌ Violation scenario:
-- Customer completes payment — transaction committed ✅
-- Server crashes immediately after commit
-- After restart — payment record is gone 💥
-- Customer charged but no order exists
# Question Level
What are the four SQL Server isolation levels? What read anomalies does
Q93 Hard
each prevent?
Ans Read Anomalies
Before isolation levels — three problems can occur when transactions run concurrently.
# Question Level
Quick Reference
Dirty Read Non-Repeatable Phantom
READ UNCOMMITTED ❌ ❌ ❌
READ COMMITTED ✅ ❌ ❌
REPEATABLE READ ✅ ✅ ❌
SERIALIZABLE ✅ ✅ ✅
SNAPSHOT ✅ ✅ ✅
What is a deadlock? Explain the classic deadlock scenario and how SQL
Q94 Hard
Server detects and resolves it.
Ans Deadlock
A deadlock happens when two transactions are waiting for each other to release locks — neither
can proceed. SQL Server detects this and forcefully terminates one transaction to break the cycle.
# Question Level
with another process and has been chosen as the deadlock victim
What Is RCSI
READ COMMITTED SNAPSHOT ISOLATION is a database level setting that automatically upgrades
all READ COMMITTED statements to use row versioning — no code change needed in application.
# Question Level
Key Difference
SNAPSHOT gives a consistent view from transaction start — reads same data throughout entire
transaction even if others commit changes. RCSI gives latest committed version at statement start —
each statement sees latest committed data.
Non-Repeatable Read
Reading the same row twice in one transaction gives different results — another transaction modified
it between your two reads.
# Question Level
Phantom Read
Running the same query twice returns different rows — another transaction inserted or deleted rows
matching your filter between reads.
Explain shared lock (S), exclusive lock (X), and update lock (U). What is
Q97 Hard
lock escalation?
Ans Shared Lock (S) — For Reading
Acquired when a transaction reads data. Multiple transactions can hold shared locks on the same row
simultaneously — reads never block each other. But a shared lock blocks exclusive locks.
# Question Level
Acquired when a transaction modifies data. Only one transaction can hold an exclusive lock — blocks
all other reads and writes until committed.
Lock Escalation
When a transaction acquires too many row level locks, SQL Server automatically escalates to a
single table level lock — reduces memory overhead but blocks all other transactions on that table.
# Question Level
What is the difference between NOLOCK hint and READ UNCOMMITTED
Q98 Hard
isolation? Why is NOLOCK dangerous in production?
Ans What Is NOLOCK Hint
NOLOCK is a table hint that tells SQL Server to read data without acquiring any shared locks —
equivalent to READ UNCOMMITTED isolation but applied to a specific table in a query.
Key Difference
NOLOCK is per table — other tables in same query still acquire locks. READ UNCOMMITTED applies
to every table in the entire transaction.
# Question Level
What is the difference between a Stored Procedure and a User-Defined
Q99 Medium
Function? What can an SP do that a UDF cannot?
Ans A Stored Procedure is a saved batch of SQL statements that can do almost anything — modify data,
call other procedures, handle transactions. A UDF is a reusable function that returns a value or table
but has strict limitations on what it can do."
# Question Level
Key Difference
Stored Procedure UDF
Modify data ✅ Yes ❌ No
Transactions ✅ Yes ❌ No
Use in SELECT ❌ No ✅ Yes
Call SP ✅ Yes ❌ No
Multiple results ✅ Yes ❌ No
# Question Level
How To Detect It
# Question Level
Copy parameter into local variable — SQL Server compiles plan based on statistics not parameter
value.
What are the dangers of using dynamic SQL in stored procedures? How
Q101 Hard
do you prevent SQL injection in T-SQL?
Ans What Is Dynamic SQL
Dynamic SQL is SQL built as a string at runtime and executed with EXEC or sp_executesql. Used
when table names, column names, or conditions are unknown at compile time.
# Question Level
# Question Level
Ans Scalar UDF — Returns Single Value
A scalar UDF returns one single value. Simple to write but has a serious hidden performance
problem when used in SELECT or WHERE on large tables.
# Question Level
# Question Level
Problem 1 — Hidden Behavior
Developer runs simple insert
INSERT INTO Orders VALUES (1, 500, 'Pending')
Trigger fires silently — sends email, updates 3 tables, calls API
Nobody knows unless they check triggers
# Question Level
##Global Temp Table — All Sessions
Visible to all sessions — exists until the creating session closes and no other session is using it.
#Temp table — always TempDB, has statistics, good for large data
Table variable — memory first, spills to TempDB when large
no statistics — optimizer assumes 1 row always
##Global temp — always TempDB, visible everywhere
Key Comparison
#Temp ##Global Temp Table Variable
Scope Current session All sessions Current batch
Statistics ✅ Yes ✅ Yes ❌ No
Large data ✅ Good ✅ Good ❌ Poor
Transactions ✅ Yes ✅ Yes ❌ No
Best for Intermediate results Cross session sharing Small datasets
# Question Level
What is the difference between DELETE, TRUNCATE, and DROP? Which
Q105 Easy
writes to transaction log minimally?
Ans DELETE — Row By Row Removal
DELETE removes rows one by one, logs every single row deletion in transaction log, fires triggers,
and can be rolled back. Slowest but most flexible.
# Question Level
Which Writes To Transaction Log Minimally
TRUNCATE writes minimally to transaction log — only logs page deallocations. DELETE logs every
single row. DROP logs table metadata removal.
Key Comparison
DELETE TRUNCATE DROP
Removes Specific or all rows All rows Entire table
Transaction log Full — every row Minimal — pages only Metadata only
Triggers ✅ Fires ❌ No ❌ No
Rollback ✅ Yes ✅ Yes ⚠️ Difficult
WHERE clause ✅ Yes ❌ No ❌ No
Resets identity ❌ No ✅ Yes N/A
Foreign keys ✅ Allowed ❌ Blocked ⚠️ Must drop FK first
What are schemas in SQL Server? How do they help with multi-tenancy and
Q106 Medium
security?
Ans Schema
A schema is a logical namespace inside a database that groups related objects — tables, views,
procedures — together. Default schema in SQL Server is dbo.
# Question Level
# Question Level
Row Level Security automatically filters rows based on who is executing the query. Users only see
rows they are allowed to see — enforced at database level, invisible to application code.
How It Works
RLS uses a Security Policy with a predicate function. Every query against the table automatically has
the filter applied — application cannot bypass it.
# Question Level
# Question Level
What is Clean Architecture? Explain the four layers and the Dependency
Q108 Hard
Rule.
Ans Clean Architecture
Clean Architecture organizes code into concentric layers where dependencies only point inward.
Inner layers know nothing about outer layers — business logic is completely isolated from frameworks,
databases, and UI.
2 — Application Layer
Orchestrates business use cases — what the application can do. Defines interfaces for
infrastructure. Depends only on Domain layer.
# Question Level
3 — Infrastructure Layer
Implements interfaces defined in Application layer — database, email, file storage, external APIs.
Depends on Application and Domain layers.
# Question Level
What is CQRS? What problem does it solve and what complexity does it
Q109 Hard
introduce?
Ans CQRS
CQRS stands for Command Query Responsibility Segregation — it separates read operations
(Queries) from write operations (Commands) into completely different models. One model optimized
for writing, another optimized for reading.
# Question Level
# Question Level
Solves Introduces
─────────────────────────────────────────────────
Read/write model conflicts More classes and handlers
Slow queries from bloated model Separate read/write pipelines
Poor scalability Eventual consistency if separate DBs
Unclear responsibilities Steeper learning curve for team
What is the Repository pattern? When does it add value and when is it an
Q110 Medium
over-abstraction over EF Core?
Ans Repository Pattern
Repository pattern abstracts data access behind an interface — business logic talks to a repository
interface, never directly to EF Core or any database technology.
# Question Level
1 — Testability
# Question Level
When It Is Over-Abstraction
EF Core DbContext is already a repository and unit of work. Wrapping it in another repository layer
often just duplicates what EF Core already provides.
# Question Level
# Question Level
Pros and Cons
✅ Cost effective — one database
✅ Simple migrations — one schema update
✅ Easy to manage at scale
❌ Noisy neighbor — one tenant affects others
❌ Accidental data leak risk if filter missed
❌ Harder to isolate per tenant backup
What is the Outbox pattern? How does it solve the dual-write problem in
Q112 Hard
distributed systems?
Ans Outbox Pattern
Instead of publishing directly to message bus, save the event to an Outbox table in the same
database transaction as your business data. A background job then reads the outbox and publishes
events reliably.
# Question Level
# Question Level
Dual Write Problem
When your application needs to save to database AND publish an event — both must succeed or both
must fail. Without a pattern, one can succeed while the other fails — data and events go out of sync.
Before Outbox
Save Order → DB Publish Event → Crash = inconsistency
After Outbox
Save Order + Save OutboxMessage → Same Transaction → Atomic
Background Job → Reads Outbox → Publishes Event → Marks Processed
Crash between publish and mark? → Job retries → Event published again
Explain Circuit Breaker and Retry patterns. How would you implement
Q113 Hard
them using Polly in .NET?
Ans Circuit Breaker Pattern
After too many consecutive failures, stop trying and fail fast for a period. Prevents hammering a
struggling service — gives it time to recover.
# Question Level
Retry Pattern
When a call fails due to a transient error — network blip, temporary timeout — retry automatically a
few times before giving up. Not all failures are permanent.
# Question Level
# Question Level
Comparison
OFFSET/FETCH Keyset
Deep page performance ❌ Degrades badly ✅ Constant speed
Random page access ✅ Jump to any page ❌ Must go sequentially
Implementation ✅ Simple Moderate
Consistent results ❌ Rows can shift ✅ Stable
Best for Small tables, few pages Large tables, infinite scroll
What is an API Gateway? When would you introduce one and what are
Q115 Medium
the downsides?
Ans API Gateway
An API Gateway is a single entry point that sits in front of all your backend services. Clients talk to
the gateway — the gateway routes requests to the right service, handling cross cutting concerns
centrally.
# Question Level
Client (Mobile/Web)
↓
API Gateway
↙ ↓ ↘
Order Payment User
Service Service Service
# Question Level
Downsides
❌ Single point of failure — gateway goes down, everything goes down
❌ Added latency — extra network hop on every request
❌ Operational complexity — another service to deploy, monitor, scale
❌ Can become a bottleneck — all traffic flows through one place
❌ Over-centralisation — teams depend on gateway team for changes
# Question Level
Stores data in external Redis or SQL Server — all server instances share same cache. Slower than
memory cache due to network hop.
# Question Level
# Question Level
Comparison
IHostedService Worker Service Hangfire
Persistent jobs ❌ No ❌ No ✅ Yes
Dashboard ❌ No ❌ No ✅ Yes
Survives restart ❌ No ❌ No ✅ Yes
Scheduling Manual Manual ✅ Built in
Best for Simple polling Heavy isolated work Production job scheduling
📌 These questions assess problem-solving thinking. Use STAR format: Situation → Task → Action →
Result. Be specific — real numbers and outcomes are far more convincing than vague generalities.
# Question Level
Tell me about a time a production API was slow. Walk me through how
Q118 Hard
you diagnosed and resolved it.
Ans In my current role at [Your Company Name], we had a situation where our [You API/Project Name]
API was returning [List Nmae] lists very slowly — response times were around 4 to 5 seconds on the
booking history endpoint. Users were complaining and the client escalated it.
My first step was to reproduce the issue locally with similar data volume. I attached SQL Server
Profiler to capture the actual queries being generated by EF Core. What I found was that the endpoint
was loading bookings along with vehicle details, driver details, and customer details — but each
related entity was being loaded separately. It was a classic N+1 problem. For 100 bookings we were
making 300 additional database calls.
The root cause was that the developer who wrote that endpoint used lazy loading and never included
the related entities explicitly. So every time the code accessed a navigation property, EF Core silently
fired another query.
My fix was straightforward — I replaced the lazy loading with eager loading using Include and
ThenInclude, and I also added a projection to return only the columns the frontend actually needed
instead of loading entire entities. I also added a composite index on the BookingDate and CustomerId
columns which were used in the WHERE and ORDER BY clauses.
After deploying the fix, response time dropped from 4 seconds to under 200 milliseconds. I also took it
as an opportunity to disable lazy loading globally in our DbContext to prevent the same mistake
happening again on other endpoints.
The lesson I took from this was — always profile your queries in a realistic data environment early.
Problems like N+1 are invisible in development with 10 rows but catastrophic in production with
thousands.
You are building an API that must handle 10,000 requests per second.
Q119 Hard
What are the first five bottlenecks you would investigate?
Ans When I think about handling 10,000 requests per second, my approach would be systematic —
starting from where the request enters the system and following it all the way to the database and
back.
The first thing I would investigate is the database. In almost every high traffic system, the
database is the bottleneck. I would look at slow queries, missing indexes, N+1 problems, and
connection pool exhaustion. At that scale even a 50 millisecond query running 10,000 times per
second becomes catastrophic.
The second thing I would look at is caching. If the same data is being fetched from the database
on every request that is unnecessary load. I would identify data that is read frequently but changes
rarely — reference data, configurations, lookup tables — and cache it in Redis or IMemoryCache.
Reducing database hits by even 60 percent makes a massive difference at that scale.
# Question Level
Third I would investigate thread pool exhaustion. At 10,000 requests per second, if any code path
is blocking — using dot Result or dot Wait on async methods — threads get exhausted and new
requests start queuing. I would ensure the entire call chain is truly async from controller all the way
down to the database.
Fourth I would look at unnecessary memory allocations and garbage collection pressure.
Frequent Gen 2 collections pause the entire application. At high throughput, small inefficiencies in hot
paths add up quickly. I would use dotMemory or Visual Studio diagnostics to identify allocation
hotspots.
Fifth I would investigate the infrastructure itself — whether the API is horizontally scaled behind a
load balancer, whether read replicas exist for read heavy workloads, and whether connection pool
sizes are tuned for the expected load.
The honest answer is you cannot know the real bottleneck until you measure — so alongside
everything else I would set up Application Insights from day one to see exactly where time is being
spent on every single request.
The first thing I would do is check if it is a data volume problem. Development databases
typically have hundreds or thousands of rows. Production has millions. A query without proper indexes
that runs fine on small data degrades badly at scale. I would immediately check row counts on the
tables involved.
Second I would capture the actual query being executed in production. Sometimes ORM
generated queries look different than expected — EF Core might be generating a cartesian product,
loading unnecessary columns, or missing a filter. I would use SQL Server Profiler or Extended Events
to capture the exact SQL hitting the database.
Third I would look at the execution plan in production. This is the most important step. I would run
the query in SSMS with actual execution plan enabled and look for Table Scans, Key Lookups, Hash
Joins on large tables, and Sort operators with high cost percentage. The execution plan tells me
exactly where SQL Server is struggling.
Fourth I would check for parameter sniffing. A 200ms query in development with small parameter
values can become 45 seconds in production if SQL Server cached a plan based on a parameter that
returns very few rows but the production call returns millions. I would check plan cache and try running
the query with OPTION RECOMPILE to see if the plan changes.
Fifth I would check index fragmentation and statistics. Stale statistics cause SQL Server to make
wrong row estimates and choose terrible execution plans. I would run UPDATE STATISTICS and
check fragmentation levels on relevant indexes.
Sixth I would check for blocking and locking. In production with concurrent users, the query might
not actually be slow — it might be waiting for locks held by another transaction. I would check
sys.dm_exec_requests for blocking chains.
The most important mindset here is — never assume. Every step is about gathering evidence before
making a change. A 45 second query always has a reason and the execution plan almost always
points directly to it.
# Question Level
The first thing I would do is understand what is in there before touching anything. I would read
through the entire controller, document every endpoint, what it does, what tables it touches, what
business rules it enforces. You cannot refactor what you do not fully understand. A 3,000 line
controller usually has hidden business logic, special cases, and silent dependencies that are not
obvious at first glance.
Second I would make sure there are integration tests covering the existing endpoints before
changing a single line. If tests do not exist I would write them first — testing the HTTP responses,
not the implementation. These tests become my safety net. If anything breaks during refactoring, the
tests catch it immediately.
Third I would start extracting without changing behavior — not redesigning. My first move is
purely mechanical — take database calls out of the controller and put them in a repository. Take
business logic out and put it in a service class. The controller still calls everything the same way,
results are identical, but code is now in the right place. This is called the Strangler Fig pattern —
gradually replace pieces without disrupting the whole.
Fourth I would introduce the Application layer use cases one endpoint at a time. Not all 50
endpoints at once — pick the simplest one, extract it fully into a command or query handler, wire it up,
run the tests, deploy. Then move to the next one. Each deployment is small and low risk.
Fifth I would move infrastructure concerns to the Infrastructure layer — DbContext calls behind
repository interfaces, external HTTP calls behind service interfaces. This is when the code becomes
truly testable because dependencies can be mocked.
The most important principle throughout is — never refactor and add features at the same
time. Refactoring commits and feature commits stay completely separate. This way if something
breaks you know exactly what caused it.
In my experience the biggest mistake teams make is trying to rewrite everything perfectly in one sprint.
That always ends in broken functionality and rollbacks. Small safe incremental steps with tests running
after every change is the only approach that works reliably in production systems.
The very first thing I would do is notify my team lead and management immediately. This is not
something to handle alone or quietly. A SQL injection vulnerability in a live system is a security
incident — the right people need to know right away so decisions can be made at the right level.
Second I would assess the blast radius before touching anything. I would try to understand —
has this vulnerability already been exploited? I would check application logs, database audit logs, and
query history for suspicious patterns like unusual SELECT statements, unexpected data dumps, or
# Question Level
DROP and DELETE commands that should not be there. Knowing whether data was already
compromised changes everything about the response.
Third I would apply an immediate temporary mitigation. If the vulnerable endpoint is identifiable I
would either take it offline temporarily, add a WAF rule to block suspicious input patterns, or restrict
access to that endpoint until a proper fix is deployed. Stopping the bleeding comes before writing the
fix.
Fourth I would write and deploy the actual fix as fast as possible. Replace string concatenated
queries with parameterized queries or stored procedures with sp_executesql. This fix is usually small
and surgical — a few lines changed — but it needs proper code review even under pressure. A rushed
fix that introduces another bug is worse than the original problem.
Fifth I would do a full codebase audit. One SQL injection usually means the same pattern exists
elsewhere. I would search the entire codebase for string concatenation with user input in database
queries and fix every instance, not just the one reported.
Sixth if any user data was potentially exposed I would follow the data breach notification
process — which depending on the region and regulations may legally require notifying affected
users and relevant authorities within a specific timeframe.
The lesson I would take forward is adding automated security scanning to the CI/CD pipeline so
vulnerabilities like this get caught before they ever reach production. Prevention is always cheaper
than incident response.
A third-party API your system depends on starts returning 429 (Too Many
Q123 Medium
Requests). How do you handle this gracefully?
Ans A 429 is actually one of the more manageable failures because the third party is telling you exactly
what is wrong — you are sending too many requests. My response would be layered.
The first thing I would do is read the response headers. Most APIs that return 429 include a Retry-
After header telling you exactly how long to wait before retrying. That is the first thing to respect —
blindly retrying immediately just makes the problem worse and could get your API key blocked
entirely.
Second I would implement a retry policy with exponential backoff using Polly. Instead of retrying
immediately, wait progressively longer between attempts — 2 seconds, then 4, then 8. This gives the
third party service breathing room and dramatically improves the chance of eventual success without
hammering their servers.
Third I would implement a circuit breaker on top of the retry policy. If the 429s are sustained —
meaning the service is consistently rate limiting us — the circuit breaker opens and we stop making
calls entirely for a period. This protects both our thread pool and the third party service.
Fourth I would look at why we are hitting the rate limit in the first place. Are we making
redundant calls for the same data? If so, caching the responses is the right fix. If the same data is
requested frequently I would cache it for an appropriate duration so we only call the third party once
and serve the rest from cache.
Fifth I would implement a request queue for non urgent calls. Instead of calling the third party
synchronously on every user request, queue the work and process it at a controlled rate that respects
the API limits. This decouples our system from their rate limits entirely.
# Question Level
Finally I would add proper monitoring and alerting so we know immediately when 429s start
appearing — not when users start complaining. Seeing the pattern early gives us time to respond
before it becomes a user facing problem.
The broader lesson is that any external dependency is a risk. I would always design integrations with
the assumption that the third party can be slow, unavailable, or rate limited — and build resilience in
from the start rather than retrofitting it after an incident.
You need to add a new non-nullable column to a production table with 100
Q124 Hard
million rows. How do you do it without downtime?
Ans This is a classic database migration challenge and doing it wrong on a 100 million row table means
hours of table locks and complete downtime. The key is breaking it into safe incremental steps.
The first thing I would understand is that you cannot simply add a non-nullable column without
a default in one step on a table this size. SQL Server needs to update every single row — that
means a lock on the entire table for potentially hours. That is unacceptable in production.
Step two — backfill the data in small batches. Never update 100 million rows in one statement —
that creates a massive transaction, locks rows for a long time, and fills the transaction log. Instead
update in small batches of 1000 to 5000 rows at a time with a short delay between batches to let other
queries breathe.
Step three — once all rows are populated, add the NOT NULL constraint. In SQL Server 2012
and later, if you add a NOT NULL constraint with a default value it is also a metadata only operation —
no row updates needed.
On the application side I would also handle this carefully. During the migration period the column
is nullable — so the application code must handle null values gracefully. I would deploy the application
update that handles the nullable column first, run the migration, then deploy the final update that treats
# Question Level
it as non-nullable. This is the expand and contract pattern — expand the schema, migrate data,
contract to final state.
Finally I would run this entire process during low traffic hours even though it is designed to be
safe — there is no reason to add unnecessary risk during peak load.
The entire philosophy here is — never do in one step what can be done safely in three. On a table this
size patience and incrementalism is always the right approach.
First I would challenge whether microservices are actually needed. A monolith is not inherently
bad. If the team is small, the domain is not that complex, or the scaling requirements do not justify the
operational overhead — I would keep the monolith and improve it instead. Microservices solve specific
problems but introduce real complexity. I would make sure the problems exist before applying the
solution.
Assuming microservices are justified, the Strangler Fig pattern works by building new
functionality around the outside of the monolith gradually — never touching the core until you
are ready to replace it. Just like the strangler fig tree grows around an existing tree until the original
tree is completely replaced.
The first concrete step is introducing an API Gateway in front of the monolith. All traffic still goes
to the monolith but now there is a routing layer I control. This is the foundation of the entire migration
— without it I cannot redirect traffic incrementally.
Second I would identify the best candidate for the first microservice. I would not start with the
most complex or most critical part of the system. I would look for a bounded context that is relatively
self contained, has clear boundaries, minimal database coupling with the rest of the monolith, and
ideally one that needs independent scaling or frequent deployment. Something like a notification
service or reporting service is a good first candidate.
Third I would extract that service without touching the monolith database immediately. The new
service gets its own codebase and its own deployment pipeline. Initially it might still share the monolith
database — that is acceptable as a temporary state. Database separation comes later. Getting the
service boundary right comes first.
Fourth I would use the API Gateway to redirect traffic for that specific bounded context to the
new service. The monolith still has the old code — I have not deleted anything yet. If the new service
has problems I flip the gateway back to the monolith in seconds. This is the safety net.
Fifth I would separate the database. Once the service is stable and proven I would migrate its data
to its own database. This is usually the hardest step — breaking shared database dependencies
requires careful data synchronization during the transition period. The Outbox pattern and event driven
communication help here to keep data consistent across the boundary.
Then I would repeat this cycle — identify next candidate, extract, redirect traffic, separate database,
validate, then remove the dead code from the monolith. Over time the monolith shrinks and the
strangler fig has fully replaced it.
# Question Level
The most important discipline throughout is — never extract and redesign at the same time.
When extracting a service the behavior must be identical to the monolith. Refactoring and migration in
the same step doubles the risk. Extract first, improve later.
In my honest opinion the teams that succeed at this migration are the ones that treat it as a year long
journey with small safe steps — not a three month sprint to rewrite everything.
⚡ These are common 'gotcha' questions interviewers use to test depth of knowledge. Each should be answered in
under 60 seconds.
Can you catch an exception from a Task that is not awaited? What happens
QB Hard
to it?
Ans No you cannot catch it — the exception is silently swallowed and your try catch is completely useless.
In older .NET versions unobserved task exceptions would crash the process. In .NET 4.5 and later they
are silently swallowed by default — which is actually more dangerous because you never know
something failed.
The fix is simple — always await your tasks. If you genuinely need fire and forget, at minimum attach a
continuation to log the exception.
What it can actually return is dirty data — rows from uncommitted transactions that might get rolled back
and never officially existed. Even worse, due to page splits happening during the read, it can return the
same row twice or skip rows entirely. No exception thrown, no warning — just silently wrong data.
It is not safe for any data that needs to be accurate — financial figures, order statuses, inventory counts.
The only scenario where it is arguably acceptable is rough approximate reporting where a slightly wrong
count does not matter.
The correct alternative is enabling READ COMMITTED SNAPSHOT ISOLATION at the database level
— you get the same concurrency benefit with zero dirty read risk and accurate data every time.
Calling SaveChanges() inside a loop 1000 times means 1000 separate database round trips — each
one opens a connection, sends the command, waits for acknowledgment, closes. Under load this is
catastrophically slow.
EF Core tracks all changes in memory until SaveChanges is called — so adding everything first then
saving once wraps all 1000 inserts in a single transaction with one round trip. Dramatically faster and
more efficient.
For extremely large datasets even one SaveChanges can be slow — in that case batch in chunks of 500
or 1000 rows using EF Core bulk extensions.
What does 'yield return' do? What type does a method with 'yield return'
QF Medium
return?
Ans yield return turns a method into a lazy iterator — instead of building the entire collection in memory
and returning it all at once, it returns items one at a time as the caller requests them.
The key benefit is memory efficiency — if you have a million records you do not load all million into
memory. You process one at a time. The compiler transforms the method into a state machine behind
the scenes — very similar to how async await works.
The reason structs cannot inherit is that structs are value types — inheritance requires reference type
semantics and virtual dispatch which value types do not support. Structs implicitly inherit from
[Link] but you cannot extend that chain yourself.
[Link] blocks the current thread — the thread sits idle doing absolutely nothing for 1 second.
In a web API that means a thread pool thread is wasted just waiting.
[Link] releases the thread back to the thread pool during the wait. The thread goes off and
serves other requests. After 1 second a thread picks up where it left off. Zero threads wasted.
The rule is simple — in any async context never use [Link]. Always use await [Link].
[Link] is only acceptable in non async console apps or truly dedicated background threads
where blocking is intentional.
What SQL Server function would you use to find duplicate rows across
QI Medium
multiple columns?
Ans I would use GROUP BY with HAVING COUNT(*) > 1 — it groups rows by the columns you want to
check for duplicates and filters to only groups with more than one row.
If I also need to see the actual duplicate rows and their IDs — to delete them for example — I would use
ROW_NUMBER to identify which rows to keep and which to remove.
You should always use GETUTCDATE() in production systems — and here is why.
If your server is in Pakistan and your users are in UAE, London, and New York — storing local server
time creates confusion and incorrect time comparisons. If the server ever moves to a different region or
daylight saving time kicks in, all your historical timestamps are now inconsistent.
Store UTC in the database, convert to the user's local timezone only at the presentation layer. This is
the industry standard approach for any system serving users across multiple timezones.
✅ DO ❌ DON'T
Think out loud — show reasoning, not just answers Memorise answers without understanding them
Say 'it depends' and then explain the tradeoffs Say you 'know' SOLID if you can't give code examples
Relate answers to AIBotNexa or real projects you built Forget to mention testing — mention unit tests naturally
Ask clarifying questions before answering system Skip drawing diagrams — visuals show structured
design thinking
Know your SQL execution plans — senior devs love Panic if you don't know — pivot to related knowledge
this Ignore SQL questions — they are heavily tested at all
Admit what you don't know — say how you'd learn it levels