.NET / C# Interview Questions - Answers & Explanations
🟢 1. C# Fundamentals
What are data types in C#?
Interview Answer: C# has value types (stored on stack: int, bool, struct, enum) and reference types (stored on heap, variable holds reference: class, interface, delegate, string, arrays). Also nullable value types (int?).
Rich Explanation: Value types hold the data directly; reference types hold a reference to the data. Value types have default values (0, false); reference types default to null. This affects assignment semantics—copying a value type copies the value; copying a reference type copies the reference.
What is the difference between int and Int32?
Interview Answer: There is no functional difference. int is a C# keyword and alias for System.Int32. They compile to the same IL. Use int in C# for readability; Int32 appears in framework APIs.
Rich Explanation: Same for long/Int64, short/Int16, string/String, etc. Keywords are language conveniences.
What is the difference between List<T> and an array?
Interview Answer: Array has fixed size, defined at creation. List<T> is dynamically sized, grows as you add elements. List is implemented over an array internally. Arrays have slightly better performance for fixed-size scenarios; List offers Add, Remove, and other collection operations.
Rich Explanation: Use arrays when size is known and constant. Use List for dynamic collections. List resizes by allocating a larger array and copying when capacity is exceeded.
What are collections in C#?
Interview Answer: Collections are types that hold groups of objects. Key types: List<T>, Dictionary<TKey,TValue>, HashSet<T>, Queue<T>, Stack<T>, LinkedList<T>. They implement interfaces like IEnumerable<T>, ICollection<T>, IList<T>.
Rich Explanation: Choose by access pattern: List for index access, Dictionary for key lookup, HashSet for unique elements, Queue/Stack for FIFO/LIFO.
What is boxing and unboxing in C#?
Interview Answer: Boxing is converting a value type to a reference type (e.g., int to object). The value is copied to the heap. Unboxing is converting back—casting the boxed object to the value type. Both have performance cost.
Rich Explanation: Boxing allocates heap memory and copies the value. Unboxing copies back to the stack. Avoid in tight loops. Generics (List<int>) avoid boxing that ArrayList would cause.
What is the difference between a value type and a reference type?
Interview Answer: Value types store data directly; copies are independent. Reference types store a reference; copies point to the same object. Value types: struct, enum, primitives. Reference types: class, interface, delegate, string, array.
Rich Explanation: Value types live on the stack (or inline in objects). Reference types live on the heap. Mutating a value-type copy doesn't affect the original; mutating through a reference-type copy does.
Explain the concept of a nullable type.
Interview Answer: Nullable types allow value types to represent "no value." Syntax: int? or Nullable<int>. They have HasValue and Value. Default is null (no value). Use for optional value-type data (e.g., DateTime? for optional dates).
Rich Explanation: Under the hood, int? is a struct with a value and a bool. Nullable reference types (string?) in C# 8+ indicate reference types that may be null.
Explain the difference between string and StringBuilder.
Interview Answer: string is immutable—each "change" creates a new object. StringBuilder is mutable—it builds the string in place with minimal allocations. Use string for few/small concatenations; use StringBuilder for many concatenations or large strings.
Rich Explanation: str += "x" in a loop allocates a new string each time. StringBuilder.Append("x") modifies internal buffer and only allocates when capacity is exceeded. For many concatenations, StringBuilder is much faster and uses less memory.
What are generics in C#?
Interview Answer: Generics allow type parameters—you write code once and use it with different types. Example: List<T>, Dictionary<TKey,TValue>. Benefits: type safety (no casting), no boxing for value types, and code reuse.
Rich Explanation: The compiler generates specialized versions for each type parameter used. Constraints (where T : IComparable) limit what types can be used and enable operations on T.
What is a dynamic type in C#?
Interview Answer: dynamic bypasses compile-time type checking. Resolution happens at runtime. Use for COM interop, reflection-heavy code, or when working with dynamic languages (e.g., JSON, dynamic objects).
Rich Explanation: The compiler defers type checking. Any operation on dynamic is resolved at runtime; errors appear only when executed. Avoid when static typing is possible—you lose IntelliSense and early error detection.
What are the differences between const and readonly?
Interview Answer: const is compile-time constant; value must be known at compile time. readonly is set in constructor; value can be computed at runtime. const is implicitly static; readonly can be instance or static. const is inlined by compiler; readonly is a field.
Rich Explanation: Use const for literals (e.g., Math.PI). Use readonly for values set in constructor (e.g., configuration, injected dependencies). Const cannot be used with reference types except string.
🔵 2. OOP & Design Principles
What is OOP?
Interview Answer: OOP has four pillars: Encapsulation (hide implementation, expose interface), Inheritance (reuse via base class), Polymorphism (same interface, different behavior), Abstraction (focus on what, not how).
Rich Explanation: Encapsulation via access modifiers. Inheritance for "is-a" relationships. Polymorphism via virtual/override and interfaces. Abstraction via abstract classes and interfaces.
What is the difference between abstract classes and interfaces?
Interview Answer: Abstract class can have implementation, constructors, fields; single inheritance. Interface defines contract only (no implementation before C# 8 default interface members); multiple inheritance. Use abstract class for shared base logic; use interface for capabilities/contracts.
Rich Explanation: Abstract class = "is a" (e.g., Animal). Interface = "can do" (e.g., IFlyable). Prefer interfaces for flexibility and testability. Use abstract class when you have common implementation to share.
What are design patterns? Can you name a few?
Interview Answer: Design patterns are reusable solutions to common design problems. Examples: Singleton, Factory, Repository, Strategy, Observer, Dependency Injection, Decorator, Adapter.
Rich Explanation: Patterns provide vocabulary and proven approaches. Singleton: one instance. Factory: creation logic. Repository: data access abstraction. Strategy: interchangeable algorithms.
What is SOLID?
Interview Answer: SOLID is five principles: Single Responsibility (one reason to change), Open/Closed (open for extension, closed for modification), Liskov Substitution (subtypes replaceable), Interface Segregation (many specific interfaces), Dependency Inversion (depend on abstractions).
Rich Explanation: SRP keeps classes focused. OCP: extend via new types, not by changing existing code. LSP: derived classes must honor base contracts. ISP: avoid fat interfaces. DIP: inject interfaces, not concrete classes.
What is dependency injection?
Interview Answer: DI is a pattern where dependencies are provided (injected) from outside instead of created inside the class. Benefits: testability (mock dependencies), flexibility, and loose coupling. DI container (e.g., built-in in ASP.NET Core) manages lifetimes and wiring.
Rich Explanation: Constructor injection is preferred. The class declares what it needs; the container supplies implementations. Enables unit testing with fakes and makes swapping implementations easy.
🟣 3. Delegates, Events, and Advanced Features
What is a delegate, event, Func, Action, Predicate?
Interview Answer: Delegate is a type-safe function pointer—references a method. Event is a mechanism for pub/sub using delegates; subscribers register without direct dependency. Func<T> returns a value; Action returns void; Predicate<T> returns bool. Func/Action/Predicate are built-in delegate types.
Rich Explanation: Func<int, string> = method that takes int, returns string. Action = method with no return. Events use delegate invocation but restrict who can raise them (only the declaring class).
What are extension methods?
Interview Answer: Extension methods add methods to existing types without modifying them. Defined as static methods in a static class, with this on the first parameter. Called as instance methods: str.MyExtension().
Rich Explanation: LINQ uses extension methods (Where, Select). Use for readability and to extend types you don't own. Must be in scope via using to be visible.
What is reflection?
Interview Answer: Reflection allows inspecting and invoking types, members, and attributes at runtime. Use Type, MethodInfo, PropertyInfo, etc. Common for serialization, ORMs, dependency injection, and plugins.
Rich Explanation: typeof(MyClass).GetMethods() lists methods. Reflection is powerful but has performance cost. Use sparingly; prefer compile-time solutions when possible.
Explain the concept of attributes in C#.
Interview Answer: Attributes add metadata to code elements (classes, methods, properties). Declared in brackets: [Obsolete], [Serializable], [HttpPost]. Used for serialization, validation, routing, and cross-cutting concerns.
Rich Explanation: Custom attributes inherit from Attribute. Consumers use reflection to read them. ASP.NET Core uses attributes heavily for routing and validation.
Explain the role of attributes and reflection in C#.
Interview Answer: Attributes store metadata; reflection reads it. Together they enable runtime behavior based on declarative metadata—e.g., [Required] read by model validation, [Authorize] read by authorization middleware.
Rich Explanation: The framework discovers attributes via reflection and applies behavior. This enables convention-over-configuration patterns.
Explain the use of yield in C#.
Interview Answer: yield return creates an iterator—lazy enumeration. The method returns IEnumerable<T> or IEnumerator<T> and yields values one at a time. yield break stops iteration. Enables streaming and memory efficiency.
Rich Explanation: The compiler generates a state machine. Values are produced on demand during foreach. Use for large sequences or infinite sequences. Each yield return pauses; next MoveNext resumes.
🟡 4. LINQ & Data Processing
What is LINQ, and how does it work?
Interview Answer: LINQ (Language Integrated Query) provides a unified syntax to query data from collections, databases, XML, etc. It uses extension methods (Where, Select, OrderBy) and query syntax. For IQueryable, expressions are translated to SQL (e.g., EF Core).
Rich Explanation: LINQ to Objects runs in memory. LINQ to SQL/EF translates to SQL. The same syntax works across providers. Deferred execution means the query runs when enumerated.
Deferred Execution vs. Immediate Execution?
Interview Answer: Deferred (lazy): Query is not executed when defined; runs when enumerated (foreach, ToList, etc.). Immediate: Executes right away—e.g., Count(), ToList(), ToArray(), First().
Rich Explanation: Deferred allows composing queries and single execution. Immediate forces execution at that point. Be aware when debugging—break on ToList, not on Where.
What are the main differences between IEnumerable and IQueryable?
Interview Answer: IEnumerable operates in memory; all data is processed client-side. IQueryable builds an expression tree and executes on the provider (e.g., database). IQueryable extends IEnumerable. Use IQueryable for database to push filtering to SQL; IEnumerable for in-memory.
Rich Explanation: Converting to IEnumerable (e.g., AsEnumerable) too early pulls all data and runs further logic in memory. Keep IQueryable as long as possible for server-side execution.
What is the difference between IEnumerable and ICollection?
Interview Answer: IEnumerable supports enumeration only (foreach). ICollection extends IEnumerable and adds Count, Add, Remove, Clear. ICollection is for modifiable collections. IList extends ICollection with indexer.
Rich Explanation: IEnumerable = read-only iteration. ICollection = knows count and can mutate. Use the most specific interface needed by your API.
🔴 5. Memory Management & Runtime
What is garbage collection?
Interview Answer: GC automatically reclaims memory for objects no longer referenced. The CLR's GC is generational (Gen 0, 1, 2). Short-lived objects in Gen 0; long-lived promoted. Reduces manual memory management and many memory bugs.
Rich Explanation: GC runs when needed (memory pressure, allocation threshold). Gen 0 is collected often; Gen 2 less often. Avoid unnecessary allocations in hot paths to reduce GC pressure.
What is the difference between Finalize and Dispose?
Interview Answer: Finalize (destructor) is called by GC before collection—unreliable timing, not for cleanup. Dispose is explicit cleanup for unmanaged resources. Implement IDisposable and call Dispose() (or use using). Use Finalize only as fallback if Dispose wasn't called.
Rich Explanation: Finalize runs on GC thread; don't block. Dispose frees unmanaged resources (handles, connections) promptly. Pattern: Dispose(bool disposing) with finalizer calling Dispose(false).
How does the IDisposable interface work?
Interview Answer: IDisposable defines Dispose(). Callers use using or try/finally to ensure Dispose is called. Implement Dispose to release unmanaged resources and optionally suppress finalization.
Rich Explanation: using (var obj = new Disposable()) { } guarantees Dispose. In Dispose, free unmanaged resources, set references to null, call GC.SuppressFinalize(this) if you have a finalizer.
What is the Common Language Runtime (CLR)?
Interview Answer: The CLR is .NET's execution engine. It loads assemblies, JIT-compiles IL to native code, manages memory (GC), handles exceptions, and provides services (threading, security). All .NET languages compile to IL and run on the CLR.
Rich Explanation: CLR provides the runtime environment. JIT compiles methods on first use. The runtime handles type safety, security checks, and interoperability.
What is CIL (Common Intermediate Language)?
Interview Answer: CIL (MSIL) is the intermediate language .NET compilers produce. It's platform-agnostic; the CLR compiles it to native code (JIT or AOT). Enables language interoperability—C#, F#, VB.NET all compile to CIL.
Rich Explanation: CIL is stack-based and portable. Tools like ildasm can inspect it. Ahead-of-time compilation (AOT) can compile CIL to native code before execution.
What is the difference between managed and unmanaged code?
Interview Answer: Managed code runs under the CLR—GC, type safety, exception handling. Unmanaged code runs outside the CLR (e.g., native C++, COM). P/Invoke and COM interop bridge them. Unmanaged resources (handles, native memory) must be explicitly freed.
Rich Explanation: Managed code is .NET. Unmanaged is native. When managed code uses unmanaged resources, implement IDisposable to free them properly.
🟠 6. Async, Multithreading & Concurrency
Explain the async and await keywords.
Interview Answer: async marks a method as asynchronous; it can use await. await suspends the method until the awaited task completes, without blocking the thread. The method returns a Task or Task<T>. Enables responsive apps and better scalability.
Rich Explanation: await yields to the caller; the thread is freed. When the task completes, execution resumes (possibly on a different thread). Never block on async code with .Result or .Wait()—causes deadlocks.
What is the purpose of the async keyword?
Interview Answer: async enables await inside the method and changes the return type to Task/Task<T>. It signals that the method performs asynchronous work. Without async, you cannot use await.
Rich Explanation: Async doesn't make code run on a different thread by itself—it enables non-blocking waiting. The actual work may run on thread pool or I/O completion.
How do you implement asynchronous programming in C#?
Interview Answer: Use async/await with Task and Task<T>. Call async APIs (e.g., HttpClient.GetStringAsync, File.ReadAllTextAsync). Return Task from async methods. Use Task.Run for CPU-bound work to offload to thread pool.
Rich Explanation: async all the way—don't mix sync and async incorrectly. Use ConfigureAwait(false) in library code to avoid capturing context. Prefer ValueTask for hot paths when appropriate.
How do you handle threading in C#?
Interview Answer: Use Task and async/await for most scenarios. For explicit threads: Thread, ThreadPool.QueueUserWorkItem. For parallelism: Parallel.For, Parallel.ForEach, Task.WhenAll. Use lock, Monitor, or SemaphoreSlim for synchronization.
Rich Explanation: Prefer tasks over raw threads. Use ConcurrentDictionary, BlockingCollection for thread-safe collections. Avoid lock on public objects; use private lock objects.
What is the difference between Task and Thread?
Interview Answer: Thread is a low-level OS thread; expensive to create. Task is a higher-level unit of work; can run on thread pool, support continuation, and integrate with async/await. Tasks are preferred for scalability.
Rich Explanation: Tasks abstract threading. Multiple tasks can share few threads. Thread is for low-level control; Task for most application code.
What are the main benefits of using async/await in web applications?
Interview Answer: Scalability—threads aren't blocked waiting for I/O; more requests can be served with fewer threads. Responsiveness—UI stays responsive. Resource efficiency—threads are released during I/O waits.
Rich Explanation: Under load, async I/O allows handling thousands of concurrent requests with a small thread pool. Sync I/O would block threads and limit throughput.
What is a state machine?
Interview Answer: The compiler transforms async methods into a state machine—a struct/class that implements the state transitions. Each await is a state boundary; when resumed, execution continues from the correct state.
Rich Explanation: This is how await "pauses" and "resumes." The state machine preserves local variables and program counter. Understanding this explains why async methods have some overhead and restrictions.
🟢 7. ASP.NET Core
What is the ASP.NET Core pipeline?
Interview Answer: The pipeline is a sequence of middleware components. Each middleware can process the request, call the next middleware, and process the response. Request flows in; response flows out. Order matters.
Rich Explanation: Middleware is configured in Startup/Program.cs. Examples: routing, authentication, authorization, CORS, static files. The pipeline ends with the endpoint (controller action, minimal API).
Explain middleware in ASP.NET Core.
Interview Answer: Middleware is a component that handles requests and responses. Signature: RequestDelegate (next) => async (context) => . Call await next(context) to pass to the next middleware. Used for logging, auth, error handling, etc.
Rich Explanation: Middleware is added with Use, UseWhen, Map. Short-circuit by not calling next. Order defines behavior—e.g., exception handling middleware should be first.
What is model binding in ASP.NET Core MVC?
Interview Answer: Model binding maps HTTP request data (route, query, form, body) to controller action parameters. Automatic for simple types and complex types. Supports [FromRoute], [FromQuery], [FromBody], [FromHeader].
Rich Explanation: The framework matches names and binds JSON, form data, etc. Use attributes to specify source when ambiguous. Custom model binders extend this for special cases.
What is model validation, and how do you handle it?
Interview Answer: Validation checks model state (required, range, regex, etc.) using data annotations or IValidatableObject. Check ModelState.IsValid in the action. Invalid state returns 400 with validation errors. Use [ApiController] for automatic 400 responses.
Rich Explanation: Annotations: [Required], [MaxLength], [Range], [EmailAddress]. Custom validators implement ValidationAttribute. FluentValidation is a popular alternative.
What are the different service lifetimes in ASP.NET Core?
Interview Answer: Transient—new instance per request. Scoped—one instance per request (same within a request). Singleton—one instance for the app lifetime. Choose based on usage: DbContext → Scoped; stateless utilities → Transient; caches → Singleton.
Rich Explanation: Scoped is the default for DbContext—don't use Singleton for DbContext (not thread-safe). Transient for lightweight, stateless services. Be careful with captive dependencies (Scoped inside Singleton = bug).
Explain the difference between IActionResult and ActionResult.
Interview Answer: IActionResult is the interface; ActionResult is the base class. Both represent an operation result. ActionResult<T> adds type for OpenAPI. Methods can return IActionResult and return Ok(), NotFound(), View(), etc.
Rich Explanation: IActionResult allows returning different result types (Ok, NotFound, Redirect). ActionResult<T> preserves response type for API documentation while allowing error responses.
How do you configure and use CORS in .NET Core?
Interview Answer: Add AddCors() in ConfigureServices and UseCors() in the pipeline. Configure policy: WithOrigins, WithMethods, WithHeaders, AllowCredentials. Apply with [EnableCors] or globally.
Rich Explanation: CORS is a browser security feature. Server must send proper headers. Configure specific origins in production—avoid wildcard with credentials. Order: CORS before auth/endpoints.
What is Kestrel, and why is it used?
Interview Answer: Kestrel is the cross-platform, high-performance web server for ASP.NET Core. It's the default server that listens for HTTP requests. Can run standalone or behind a reverse proxy (IIS, nginx).
Rich Explanation: Kestrel is fast and lightweight. For production, typically put nginx or IIS in front as reverse proxy for SSL termination, load balancing, and static files. Kestrel handles the application.
🔵 8. Security & Authentication
How do you handle security in a C# web application?
Interview Answer: Use HTTPS, validate input, avoid SQL injection (parameterized queries, ORM), prevent XSS (encoding output), use CSRF tokens, implement authentication and authorization, keep dependencies updated, follow OWASP guidelines.
Rich Explanation: Defense in depth—multiple layers. Input validation, output encoding, secure headers, principle of least privilege. Use built-in security features (Identity, Data Protection).
How do you implement authentication and authorization?
Interview Answer: Authentication (who are you): Use Identity, JWT, or OAuth/OpenID Connect. Authorization (what can you do): Use [Authorize], policies, role-based or claim-based. Configure in AddAuthentication and AddAuthorization.
Rich Explanation: Authentication validates identity (cookie, bearer token). Authorization checks permissions (policies, roles, claims). Implement both; authentication without authorization is insufficient.
How do you secure Web APIs using JWT?
Interview Answer: Add AddAuthentication(JwtBearerDefaults.AuthenticationScheme) with JWT options (validation parameters, issuer, audience, key). Use [Authorize] on controllers/actions. Client sends token in Authorization: Bearer <token>.
Rich Explanation: JWT is stateless—server validates signature. Store secret securely; use short expiry. Consider refresh tokens for long sessions. Validate issuer, audience, and expiration.
How do you implement JWT refresh tokens securely?
Interview Answer: Issue short-lived access token (minutes) and long-lived refresh token (days/weeks). Store refresh tokens hashed in DB; associate with user and device. On access token expiry, client sends refresh token to get new access token. Rotate refresh tokens; revoke on logout.
Rich Explanation: Refresh tokens allow re-authentication without credentials. Store hashed; validate and rotate on use. Implement token blacklisting or versioning for logout. Secure storage on client (httpOnly cookie preferred over localStorage for refresh token).
How do you integrate OAuth2 and OpenID Connect?
Interview Answer: Use AddAuthentication().AddOpenIdConnect() or AddOAuth(). Configure authority, client ID, client secret, scopes, callbacks. For APIs, validate tokens from the identity provider. OpenID Connect adds identity layer on top of OAuth2.
Rich Explanation: OAuth2 = authorization framework. OpenID Connect = authentication layer (ID token, user info). Use for "Login with Google/GitHub" and federated identity.
How do you integrate Identity Server with .NET Core?
Interview Answer: IdentityServer is an OpenID Connect and OAuth2 framework. Add IdentityServer middleware, configure clients, resources, and users. Use for centralized auth in microservices—issues and validates tokens. Duende IdentityServer is the commercial version.
Rich Explanation: IdentityServer acts as the token authority. Clients (SPAs, APIs) authenticate against it. Configure clients (e.g., implicit, client credentials, resource owner password) per use case.
🟣 9. Database, EF Core & Data Access
What is the role of Entity Framework Core?
Interview Answer: EF Core is an ORM—maps objects to database tables. Handles CRUD, change tracking, migrations, and LINQ-to-SQL translation. Supports multiple providers (SQL Server, PostgreSQL, SQLite). Reduces boilerplate and handles SQL generation.
Rich Explanation: DbContext represents the session. DbSet represents tables. Use for rapid development; optimize hot paths with raw SQL or Dapper when needed.
How do you perform database migrations with EF?
Interview Answer: dotnet ef migrations add MigrationName creates migration from model changes. dotnet ef database update applies migrations. Migrations are code; review before applying. Use in CI/CD for automated deployment.
Rich Explanation: Migrations track schema changes over time. Generate script with dotnet ef migrations script for manual deployment. Handle data migrations in custom migration code when needed.
Explain eager loading vs lazy loading.
Interview Answer: Eager loading loads related data in the initial query (e.g., Include()). Lazy loading loads on access (requires proxy/configuration). Eager avoids N+1; lazy can cause N+1. Prefer eager for predictable access; use lazy cautiously.
Rich Explanation: Include/ThenInclude for eager. Lazy requires UseLazyLoadingProxies() and virtual navigation properties. Lazy can cause surprises and N+1—document and test.
What are best practices for EF Core?
Interview Answer: Use async methods; avoid N+1 (Include/Select); use AsNoTracking for read-only; index frequently queried columns; avoid SELECT *; use compiled queries for hot paths; keep DbContext scope short (Scoped per request); use raw SQL for complex queries when needed.
Rich Explanation: Profile and optimize. Disable change tracking for reads. Consider splitting read/write (CQRS). Use bulk extensions for large inserts. Keep migrations small and reviewable.
How do you optimize SQL queries using Dapper?
Interview Answer: Dapper is a micro-ORM—raw SQL with object mapping. Use parameterized queries to avoid SQL injection. Use Query<T> or QueryFirstOrDefault. Multi-mapping for joins. Avoid N+1 with multi-result QueryMultiple. Good for performance-critical, complex queries.
Rich Explanation: Dapper doesn't track changes—read-only. Use for reports, complex joins, stored procedures. Combine with EF for mixed scenarios (EF for writes, Dapper for reads).
How do you create a custom collection?
Interview Answer: Implement IEnumerable<T> (and optionally ICollection<T>, IList<T>). Implement GetEnumerator, Add, Remove, etc. For custom iteration logic, use yield return or a custom enumerator class. Consider inheriting from Collection<T> for simple cases.
Rich Explanation: Collection<T> provides virtual methods to override. For full control, implement interfaces directly. Ensure thread safety if used from multiple threads.
🟡 10. System Design / Architecture / Tools
Explain CQRS
Interview Answer: CQRS (Command Query Responsibility Segregation) separates read and write models. Commands change state; queries return data. Different models can be optimized—e.g., denormalized read model, normalized write model. Often used with event sourcing.
Rich Explanation: Enables scaling reads and writes independently. Read model can be a cache, different DB, or projection. Use when read and write patterns differ significantly.
What is a circular reference?
Interview Answer: A circular reference occurs when objects reference each other (A→B→A) or when a type references itself. Can cause serialization issues (JSON), infinite loops, or memory issues. Resolve with DTOs, [JsonIgnore], or reference handling in serializers.
Rich Explanation: Common in ORM entities (Order has Customer, Customer has Orders). Use projection to DTOs for APIs. Configure serializer to handle cycles if needed (e.g., ReferenceHandler.IgnoreCycles).
How do you implement logging in C# applications?
Interview Answer: Use ILogger<T> from Microsoft.Extensions.Logging. Configure providers (Console, File, Application Insights). Log levels: Trace, Debug, Information, Warning, Error, Critical. Use structured logging with named parameters. Inject ILogger; use Serilog or NLog for rich features.
Rich Explanation: Avoid string interpolation in log calls—use template: LogInformation("User {UserId} logged in", userId). Configure levels per namespace. Use correlation IDs for tracing.
How do you handle logging and error handling in production?
Interview Answer: Log errors with context (user, request ID, exception). Use global exception middleware to catch unhandled exceptions. Avoid exposing internals to clients. Use health checks. Monitor logs (Application Insights, Seq, ELK). Implement retries and circuit breakers where appropriate.
Rich Explanation: Centralized error handling. Return generic messages to clients; log details server-side. Correlate logs with request IDs. Set up alerts on error rates.
How do you serialize and deserialize an object?
Interview Answer: Use System.Text.Json (preferred) or Newtonsoft.Json. JsonSerializer.Serialize(obj) and JsonSerializer.Deserialize<T>(json). Configure options (naming policy, ignore nulls). Use attributes or custom converters for special types.
Rich Explanation: System.Text.Json is faster and built-in. Newtonsoft has more features. For APIs, configure globally in AddControllers/AddJsonOptions. Handle circular references and custom types.
What are REST vs SOAP?
Interview Answer: REST is architectural style—resource-based URLs, HTTP methods (GET, POST, PUT, DELETE), stateless, JSON/XML. SOAP is XML-based protocol—strict contract (WSDL), built-in security (WS-*), more complex. REST is prevalent for APIs; SOAP for enterprise integration.
Rich Explanation: REST is lightweight, cacheable. SOAP has comprehensive standards. Choose REST for modern web/mobile APIs; SOAP when integrating with legacy or specific enterprise requirements.
How do you optimize performance in .NET?
Interview Answer: Profile first. Use async I/O; avoid blocking. Reduce allocations (Span, stackalloc, object pooling). Cache expensive operations. Use appropriate collections. Optimize database (indexes, queries, connection pooling). Use response caching, output caching. Consider CDN for static assets. Use minimal APIs or trim unnecessary middleware.
Rich Explanation: Measure before optimizing. Use dotTrace, PerfView, Application Insights. Hot path optimizations matter most. Balance readability and performance.
How do you monitor performance and health?
Interview Answer: Use health checks (AddHealthChecks, /health endpoint)—database, external services. Application Insights for APM—requests, dependencies, exceptions. Prometheus + Grafana for metrics. Log aggregation (Seq, ELK). Set up alerts and dashboards.
Rich Explanation: Health checks for readiness/liveness. APM for latency, throughput, failures. Correlate logs, metrics, traces. Define SLOs and alert on violations.
☁️ 11. Cloud / Microservices / Advanced Topics
How do you work with RabbitMQ?
Interview Answer: Use RabbitMQ.Client or MassTransit. Connect to broker; declare exchanges, queues, bindings. Publish messages; consume with handlers. Use patterns: direct, topic, fanout. Ensure idempotency and handle failures (dead letter, retries).
Rich Explanation: RabbitMQ is a message broker. Use for decoupling, async processing, load leveling. Configure connection resilience. Consider MassTransit for abstractions and conventions.
How do you integrate Docker?
Interview Answer: Add Dockerfile to project. Multi-stage builds for smaller images. Use docker build and docker run. In development, use docker-compose for app + dependencies (DB, Redis). For production, use orchestration (Kubernetes, AKS).
Rich Explanation: .NET images on mcr.microsoft.com. Use alpine for smaller size. Set ASPNETCORE_URLS. Map ports and volumes. Use health checks in container.
How do you work with Azure Functions?
Interview Answer: Create function app; add functions with triggers (HTTP, Timer, Queue, Blob). Use [FunctionName] and bindings. Supports multiple languages; C# uses same runtime. Deploy to Azure; configure app settings, connection strings. Use Durable Functions for workflows.
Rich Explanation: Serverless—pay per execution. Triggers and bindings simplify integration. Use for event-driven, scheduled, or HTTP-triggered workloads. Cold start considerations for low traffic.
How do you integrate Elasticsearch?
Interview Answer: Use NEST or Elastic.Clients.Elasticsearch client. Configure connection (cloud or self-hosted). Index documents; query with DSL or LINQ-like API. Use for full-text search, logging (ELK), analytics. Implement indexing strategy and mapping.
Rich Explanation: Elasticsearch for search and analytics. Bulk index for ingestion. Use aggregations for analytics. Consider OpenSearch as open-source alternative.
How do you implement API Gateway?
Interview Answer: Use Ocelot, YARP, or Azure API Management. Gateway routes requests to backend services, handles auth, rate limiting, and aggregation. Configure routes, authentication, and transformations. Can implement BFF (Backend for Frontend) pattern.
Rich Explanation: Gateway as single entry point. Handles cross-cutting concerns. Ocelot for .NET; YARP is Microsoft's configurable proxy. Cloud providers offer managed gateways.
How do you enable response caching?
Interview Answer: Add AddResponseCaching() and UseResponseCaching(). Use [ResponseCache] on actions (Duration, Location, VaryByQuery). For distributed cache, use AddStackExchangeRedisCache(). Set appropriate cache headers (Cache-Control). Consider output caching in .NET 7+.
Rich Explanation: Response caching stores full responses. Configure cache profiles. Use VaryBy to cache per user/query when needed. Redis for multi-instance scenarios.