Skip to main content

Amazon Interview ASP.NET Web API Interview Questions

Curated Amazon Interview-level ASP.NET Web API interview questions for developers targeting amazon interview positions. 113 questions available.

Last updated:

ASP.NET Web API Interview Questions & Answers

Skip to Questions

Welcome to our comprehensive collection of ASP.NET Web API interview questions and answers. This page contains expertly curated interview questions covering all aspects of ASP.NET Web API, from fundamental concepts to advanced topics. Whether you're preparing for an entry-level position or a senior role, you'll find questions tailored to your experience level.

Our ASP.NET Web API interview questions are designed to help you:

  • Understand core concepts and best practices in ASP.NET Web API
  • Prepare for technical interviews at all experience levels
  • Master both theoretical knowledge and practical application
  • Build confidence for your next ASP.NET Web API interview

Each question includes detailed answers and explanations to help you understand not just what the answer is, but why it's correct. We cover topics ranging from basic ASP.NET Web API concepts to advanced scenarios that you might encounter in senior-level interviews.

Use the filters below to find questions by difficulty level (Entry, Junior, Mid, Senior, Expert) or focus specifically on code challenges. Each question is carefully crafted to reflect real-world interview scenarios you'll encounter at top tech companies, startups, and MNCs.

Questions

113 questions
Q1:

What is ASP.NET Core Web API and how does it differ from MVC?

Entry

Answer

ASP.NET Core Web API is a framework for building HTTP services that return JSON, XML, or other serialized data.

Differences from MVC:

  • No Razor or HTML rendering
  • Focused on RESTful services
  • Controller methods return data, not views
  • Routing is often attribute-based
Quick Summary: ASP.NET Core Web API builds HTTP APIs (REST) without the View layer. MVC includes Views for server-side HTML rendering. Web API returns JSON/XML data consumed by front-end apps, mobile clients, or other services. Both share the same middleware pipeline, DI, and routing infrastructure. Web API controllers inherit from ControllerBase (no View support); MVC from Controller.
Q2:

Explain the request pipeline in ASP.NET Core Web API.

Entry

Answer

The pipeline consists of middleware components that process HTTP requests in sequence:

  • Request enters server
  • Middleware handles tasks like authentication, logging, routing
  • Endpoint routing selects controller/action
  • Controller executes business logic
  • Response flows back through middleware
Quick Summary: The request pipeline is a chain of middleware components. Each middleware can inspect and modify the request, call the next middleware, and modify the response on the way back. Order matters - defined in Program.cs. For Web API: UseRouting -> UseAuthentication -> UseAuthorization -> MapControllers. Request flows forward through middleware, response flows backward.
Q3:

What are Controllers and how are they structured?

Entry

Answer

Controllers handle incoming HTTP requests.

  • Decorated with [ApiController] and [Route]
  • Contain action methods
  • Use dependency injection via constructor
  • Return IActionResult or data objects
Quick Summary: Controllers group related API endpoints. Each controller class inherits ControllerBase and is decorated with [ApiController] and [Route("api/[controller]")]. Action methods handle specific HTTP verbs ([HttpGet], [HttpPost], [HttpPut], [HttpDelete]). [ApiController] enables automatic model validation, attribute routing, and better error responses. Return IActionResult or ActionResult for typed responses.
Q4:

How does Attribute Routing work in Web API?

Entry

Answer

Attribute routing uses attributes to define URL patterns.

  • [Route("api/[controller]")] sets base route
  • [HttpGet], [HttpPost] define HTTP verbs
  • Supports route parameters, constraints, defaults
Quick Summary: Attribute routing maps HTTP requests to controller actions using attributes directly on methods. [Route("api/users/{id}")] defines the URL template. [HttpGet("{id}")] matches GET requests. Route parameters ({id}) bind to action parameters. Constraints: {id:int}, {name:alpha}. More explicit than convention-based routing - each endpoint's URL is visible right on the action method.
Q5:

Explain model binding and validation.

Entry

Answer

Model binding maps HTTP data to method parameters.

  • [FromBody] binds JSON/XML
  • [FromQuery] binds query parameters
  • [FromRoute] binds URL segments

Validation uses DataAnnotations and ModelState.IsValid.

Quick Summary: Model binding automatically maps HTTP request data (route params, query string, body, headers, form) to action method parameters. [FromBody] binds JSON request body. [FromQuery] binds query string. [FromRoute] binds route parameters. [FromHeader] binds headers. [ApiController] enables automatic validation - if ModelState is invalid, it returns 400 Bad Request without needing to check manually.
Q6:

What are Action Results and why are they important?

Entry

Answer

Action results allow APIs to return proper HTTP responses.

  • Return 200, 404, 400 etc.
  • Provide flexibility using IActionResult
  • Support multiple return formats
Quick Summary: Action Results are objects returned from controller actions that determine the HTTP response. Common: Ok(data) -> 200, Created(uri, data) -> 201, BadRequest(errors) -> 400, Unauthorized() -> 401, NotFound() -> 404, NoContent() -> 204. Use ActionResult as return type for both typed returns and IActionResult alternatives. They abstract HTTP status codes from business logic.
Q7:

What is Content Negotiation in Web API?

Entry

Answer

Content negotiation selects the response format based on:

  • Client's Accept header
  • Configured formatters (JSON, XML)

ASP.NET Core defaults to JSON.

Quick Summary: Content Negotiation lets the client specify what format it wants (JSON, XML) via the Accept header. The server checks available output formatters and picks the best match. ASP.NET Core includes JSON formatter by default. Add XML: services.AddControllers().AddXmlSerializerFormatters(). If no match: returns default format (406 Not Acceptable if configured strictly).
Q8:

How are dependency injection and services handled in Web API?

Entry

Answer

ASP.NET Core has built-in DI.

  • Register services using AddSingleton/AddScoped/AddTransient
  • Injected via controller constructor
  • Improves modularity and testability
Quick Summary: ASP.NET Core has built-in DI. Register services in Program.cs: builder.Services.AddScoped(). Controllers declare dependencies as constructor parameters - DI injects them automatically. This enables loose coupling, testability (inject mocks), and lifetime management. Never create services with new inside controllers - always inject via constructor.
Q9:

Explain the difference between Scoped, Singleton, and Transient lifetimes.

Entry

Answer

Singleton: One instance for entire app.

Scoped: One instance per request.

Transient: New instance per usage.

Quick Summary: Transient: new instance created every time it's requested (stateless, lightweight services). Scoped: one instance per HTTP request - shared within that request (EF Core DbContext). Singleton: one instance for the app lifetime - shared across all requests (config, caches). Never inject Scoped into Singleton - creates a captive dependency (the Scoped object lives longer than intended).
Q10:

How do you handle exceptions in Web API?

Entry

Answer

Best practices include:

  • UseExceptionHandler middleware
  • Exception filters
  • Centralized logging
  • Returning friendly error messages
Quick Summary: Exception handling options: try-catch in action methods, global exception handling middleware (IMiddleware or app.UseExceptionHandler()), or ProblemDetails pattern (RFC 7807). Exception filters catch exceptions from action execution. UseExceptionHandler is the recommended global approach - returns consistent error responses. Never expose stack traces in production.
Q11:

How does ASP.NET Core handle JSON serialization?

Entry

Answer

Uses System.Text.Json by default.

  • High performance
  • Supports converters and casing rules
  • Can switch to Newtonsoft.Json if required
Quick Summary: ASP.NET Core uses System.Text.Json by default (fast, low-allocation). Configure globally in AddControllers(options => ...). Options: JsonNamingPolicy.CamelCase, ReferenceHandler.Preserve for circular refs, custom converters for types like DateOnly. Newtonsoft.Json (AddNewtonsoftJson()) is optional for backwards compatibility. Use [JsonPropertyName("name")] to customize JSON property names per class.
Q12:

What are Action Filters and when do you use them?

Entry

Answer

Action filters run before/after actions.

  • Logging
  • Validation
  • Authentication
  • Response modification
Quick Summary: Action filters run code before/after action execution. Use for: logging, input validation, performance timing, caching headers. Implement IActionFilter (sync) or IAsyncActionFilter (async). OnActionExecuting runs before the action, OnActionExecuted runs after. Apply as [attribute] on controller or action, or register globally in MVC options. Different from middleware: filters have access to action context (controller, action name, parameters).
Q13:

Explain the purpose of FromBody, FromQuery, and FromRoute.

Entry

Answer

[FromBody] - reads body JSON/XML.

[FromQuery] - reads query string.

[FromRoute] - maps URL parameters.

Quick Summary: [FromBody]: deserializes JSON/XML request body into a parameter - use for POST/PUT with complex data. [FromQuery]: reads from URL query string (?name=Alice). [FromRoute]: reads from URL path template ({id}). [FromHeader]: reads from HTTP header. [FromForm]: reads from form data. Without these, [ApiController] uses smart inference: complex types default to [FromBody], primitives to [FromQuery].
Q14:

How do you implement versioning in Web API?

Entry

Answer

API versioning methods:

  • URL versioning: /api/v1/
  • Query string versioning
  • Header versioning (api-version)

Implemented using the Versioning package.

Quick Summary: API versioning strategies: URL path (/api/v1/users), query string (?api-version=1), headers (API-Version: 1). Use the Microsoft.AspNetCore.Mvc.Versioning package. [ApiVersion("1.0")] on controllers. Run multiple versions side by side. Deprecate old versions with [ApiVersion("1.0", Deprecated = true)]. URL path versioning is the most visible and REST-compatible approach.
Q15:

What is CORS and why is it important in Web API?

Entry

Answer

CORS allows cross-domain API access.

Configured using AddCors + middleware.

Needed for browser-based clients.

Quick Summary: CORS (Cross-Origin Resource Sharing) restricts which origins can make requests to your API from browsers. Configure in Program.cs: builder.Services.AddCors() and app.UseCors(). Define policies: AllowAnyOrigin(), WithOrigins("https://yourapp.com"), AllowAnyMethod(), AllowAnyHeader(). Apply globally or per controller/action. Allow only specific trusted origins - avoid AllowAnyOrigin in production.
Q16:

How do you secure a Web API?

Entry

Answer

Security techniques include:

  • JWT Bearer authentication
  • [Authorize] attributes
  • HTTPS enforcement
  • Input validation
  • Rate limiting
Quick Summary: Secure Web API: use JWT or OAuth2 for authentication. Enforce HTTPS. Apply [Authorize] to protect endpoints. Use CORS to restrict origins. Validate all inputs (model validation). Rate limit to prevent abuse. Return minimal error details (no stack traces). Keep dependencies updated. Use HTTPS-only cookies if using cookies. Apply principle of least privilege for service accounts and API keys.
Q17:

Explain the difference between synchronous and asynchronous controllers.

Entry

Answer

Synchronous: Thread waits for completion.

Asynchronous: Releases thread during I/O.

Async improves scalability.

Quick Summary: Synchronous controllers block a thread for the duration of I/O operations. Async controllers: use async Task return type and await I/O calls (DbContext, HttpClient). The thread is released during await, allowing the server to handle other requests. Under load, async prevents thread exhaustion. Rule: always use async for any controller that does I/O (database, HTTP, file).
Q18:

What is Response Caching in Web API?

Entry

Answer

Response caching reduces repeated processing.

  • Uses [ResponseCache] attribute
  • Decreases latency
  • Improves throughput
Quick Summary: Response caching stores HTTP responses to serve repeated requests faster. [ResponseCache] attribute sets Cache-Control headers telling clients/proxies how long to cache. UseResponseCaching() middleware caches on the server side. VaryByQueryKeys caches different versions per query parameter. Not suitable for user-specific or highly dynamic responses. Use distributed caching (Redis) for server-side caching of database results.
Q19:

How do you test a Web API effectively?

Entry

Answer

Testing involves:

  • Unit tests with mocks
  • Integration tests with TestServer
  • API testing tools (Postman, Swagger)
  • Validating status codes, payloads, headers
Quick Summary: Web API testing: unit tests with xUnit/NUnit + Moq (mock services, test action logic in isolation). Integration tests with WebApplicationFactory - spins up the real app with an in-memory or test database, makes HTTP calls with HttpClient. Test all HTTP verbs, status codes, error cases. Use TestServer for lightweight integration tests without a real HTTP server.
Q20:

Why is Swagger/OpenAPI important in Web API?

Entry

Answer

Swagger provides:

  • Interactive API documentation
  • Endpoint visibility
  • Contract testing
  • Client-code generation
Quick Summary: Swagger (OpenAPI) auto-generates interactive API documentation from your code. Developers can explore endpoints, see request/response schemas, and test calls directly in the browser. Add with Swashbuckle.AspNetCore. Integrate XML comments for detailed descriptions. Add JWT auth support in Swagger UI. Essential for API-first development and enabling frontend/mobile teams to understand the API contract.
Q21:

What is Middleware in ASP.NET Core Web API?

Entry

Answer

Middleware are components in the ASP.NET Core request pipeline that execute sequentially.

Each middleware can:

  • Process the request before passing it forward
  • Process the response after the next middleware has executed

Common examples include authentication, logging, CORS, and routing middleware.

Order is critical because each middleware depends on the sequence.

Quick Summary: Middleware is a component in the request pipeline that processes HTTP requests and responses. Each middleware calls next() to pass control forward. Custom middleware: implement IMiddleware or write a request delegate (async (context, next) => {...}). Register with app.UseMiddleware(). Order matters - authentication must run before authorization, error handling must be first.
Q22:

How does the UseRouting and UseEndpoints middleware work?

Entry

Answer

UseRouting identifies the matching endpoint based on the URL.

UseEndpoints executes the matched action.

Authentication, authorization, and CORS middleware should be placed between these two for correct behavior.

Quick Summary: UseRouting() matches the incoming request URL to an endpoint (stores the match in HttpContext). UseEndpoints() (or MapControllers()) executes the matched endpoint. Middleware between UseRouting and UseEndpoints has access to the matched endpoint info (e.g., UseAuthorization can read [Authorize] attributes on the matched action). Without UseRouting first, authorization can't know which endpoint was matched.
Q23:

How do you create custom middleware?

Entry

Answer

Custom middleware involves:

  • Create a class with a constructor accepting RequestDelegate
  • Implement Invoke or InvokeAsync
  • Register with app.UseMiddleware<T>()
Quick Summary: Custom middleware: write an async method with (HttpContext context, RequestDelegate next) parameters, or implement IMiddleware. Call await next(context) to continue pipeline. Modify request before, response after. Register: app.Use(async (context, next) => {...}) or app.UseMiddleware(). Use for: request logging, adding headers, timing, IP filtering - anything that applies to all requests.
Q24:

Explain Filters in ASP.NET Core Web API.

Entry

Answer

Filters run during the execution pipeline and include:

  • Authorization Filters
  • Resource Filters
  • Action Filters
  • Exception Filters
  • Result Filters
Quick Summary: ASP.NET Core filters run at specific points around action execution. Types: Authorization (first - can short-circuit), Resource (before/after model binding), Action (before/after action runs), Exception (handles unhandled exceptions), Result (before/after result executes). Filters are MVC-specific (have access to action context) while middleware applies to all requests including static files.
Q25:

How is model validation applied automatically?

Entry

Answer

Applying [ApiController] automatically triggers model validation.

Invalid models result in 400 Bad Request with error details.

Validation uses DataAnnotations like [Required], [Range], etc.

Quick Summary: [ApiController] attribute enables automatic model validation: if ModelState.IsValid is false after model binding, it automatically returns 400 Bad Request with validation error details - no manual check needed. Define validation with DataAnnotations ([Required], [MaxLength], [EmailAddress]) or FluentValidation. Customize the 400 response using InvalidModelStateResponseFactory in MVC options.
Q26:

How do you implement global exception handling using middleware?

Entry

Answer

Global exception handling steps:

  • Create custom exception middleware
  • Wrap request processing in try/catch
  • Log and return a standardized error response
  • Use app.UseExceptionHandler() for production mode
Quick Summary: Global exception handling with middleware: app.UseExceptionHandler(app => app.Run(async context => { var error = context.Features.Get(); log error; await context.Response.WriteAsJsonAsync(new ProblemDetails {...}); })). In .NET 8: use IExceptionHandler interface and app.AddExceptionHandler(). Returns RFC 7807 ProblemDetails format. Always handle exceptions globally - don't rely on developers to try-catch everywhere.
Q27:

Explain the difference between synchronous and asynchronous middleware.

Entry

Answer

Synchronous middleware: Blocks thread while executing.

Asynchronous middleware: Uses Task and await to release thread during I/O operations.

Async middleware improves scalability in high-load systems.

Quick Summary: Synchronous middleware blocks the thread for its duration. Async middleware uses async/await to release the thread during I/O waits. Use async middleware for any I/O in the pipeline (logging to a service, reading from Redis, DB calls). Synchronous middleware in async pipelines can cause thread pool starvation under load. Always write middleware as async unless it has no I/O.
Q28:

How can you implement logging in Web API?

Entry

Answer

Logging methods:

  • Use ILogger<T> via DI
  • Log levels: Trace ? Critical
  • Send logs to Console, Files, DB, or external providers
  • Use middleware/filters for request & response logging
Quick Summary: ASP.NET Core logging: inject ILogger via DI. Log with logger.LogInformation(), LogWarning(), LogError(). Configure providers in appsettings.json (Console, File via Serilog/NLog, Application Insights). Use structured logging: logger.LogInformation("User {UserId} logged in", userId) - preserves the userId as a queryable field. Serilog or NLog for file sinks and centralized logging.
Q29:

What is diagnostic middleware and why is it important?

Entry

Answer

Diagnostic middleware provides insights into requests and system behavior.

Examples: DeveloperExceptionPage, SerilogRequestLogging, Application Insights.

Helps detect failures, anomalies, and performance issues.

Quick Summary: Diagnostic middleware provides insights into request processing. UseDeveloperExceptionPage() shows detailed error info in development. UseStatusCodePages() adds custom responses for 404/500. Built-in health check middleware (UseHealthChecks) reports app status. Custom diagnostics middleware can log request/response details, timing, and add correlation IDs to all requests for distributed tracing.
Q30:

How do you handle CORS in a Web API?

Entry

Answer

CORS is configured using:

  • AddCors() in Program.cs
  • Define policies with allowed origins, headers, and methods
  • Apply globally or per controller using [EnableCors]
Quick Summary: Handle CORS: add services (AddCors), define a named policy with allowed origins, methods, headers. Apply policy globally (app.UseCors("MyPolicy")), per controller ([EnableCors("MyPolicy")]), or per action. For credentials (cookies, auth headers): call AllowCredentials() and specify exact origins (not wildcard). UseResponseCaching middleware needs CORS configured before it.
Q31:

How do you restrict content types in requests?

Entry

Answer

Use the [Consumes] attribute:

[Consumes("application/json")]

Rejects unsupported media types with HTTP 415.

Quick Summary: Restrict content types with a custom action filter or resource filter that checks request Content-Type header. Reject requests with unsupported content types (return 415 Unsupported Media Type). [Consumes("application/json")] attribute on action methods declares what content types are accepted and restricts routing to matching requests. Prevents processing unexpected content formats.
Q32:

How do you inspect and log request/response bodies safely?

Entry

Answer

To log safely:

  • Use EnableBuffering() for reading request body
  • Wrap the response stream to capture outgoing body
  • Avoid logging sensitive data
Quick Summary: Log request/response bodies: use middleware that buffers the request body (EnableBuffering() to make it re-readable), reads and logs it, then resets the stream position. For responses: replace the original response body stream with a MemoryStream, let the pipeline write to it, log it, then copy to the original. Be careful: don't log sensitive data (passwords, tokens). Limit logged body size.
Q33:

What is the difference between endpoint routing and legacy MVC routing?

Entry

Answer

Endpoint routing: Pre-matches endpoints before controller activation.

Legacy routing: Occurred during MVC action selection.

Endpoint routing is more flexible and enables better middleware integration.

Quick Summary: Endpoint routing (current): UseRouting() matches routes, UseEndpoints() executes them. Middleware in between can inspect the matched endpoint. Supports any endpoint type (controllers, Razor pages, gRPC, health checks). Legacy MVC routing: route matching done inside MVC itself, no separation. Endpoint routing is more flexible, allows authorization to read endpoint metadata before execution.
Q34:

How do you implement API versioning?

Entry

Answer

Use API Versioning package.

  • URL versioning
  • Header versioning
  • Query string versioning

Decorate controllers with [ApiVersion("1.0")].

Quick Summary: API versioning with Microsoft.AspNetCore.Mvc.Versioning: AddApiVersioning() in services. [ApiVersion("1.0")] on controllers. URL path: v1/api/users, query string: ?api-version=1, header: api-version: 1. MapToApiVersion(1.0) maps actions to specific versions. Return supported versions in API-Supported-Versions response header. Deprecate old versions gracefully with documentation.
Q35:

How do you configure JSON serialization globally?

Entry

Answer

Configure using:

AddControllers().AddJsonOptions(options => { ... });

Supports camelCase, converters, and null handling.

Quick Summary: Configure JSON globally: builder.Services.AddControllers().AddJsonOptions(opts => { opts.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase; opts.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull; opts.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()); }). Add custom converters for complex types. Override per controller with [JsonOptions].
Q36:

How do you handle API response formatting?

Entry

Answer

Use IActionResult or ActionResult<T> for flexible responses.

Supports content negotiation and custom response formatting.

Quick Summary: Handle API response formatting: return typed ActionResult for auto-serialization. Use ProducesResponseType attributes for Swagger documentation. Set Content-Type in responses. Implement custom output formatters for non-JSON formats. Use ProblemDetails for error responses (RFC 7807 standard). Consistent response structure: always include status, data, and error fields for predictable client handling.
Q37:

How do you throttle requests in ASP.NET Core Web API?

Entry

Answer

Use libraries like AspNetCoreRateLimit.

  • Define IP or user-based rate limits
  • Prevent abuse and DoS attacks
  • Supports rule-based throttling
Quick Summary: Rate limiting in ASP.NET Core 7+: built-in RateLimiter middleware. Policies: FixedWindowLimiter, SlidingWindowLimiter, TokenBucketLimiter, ConcurrencyLimiter. Add with AddRateLimiter(). Apply globally or per endpoint with [EnableRateLimiting("policy")]. Returns 429 Too Many Requests with Retry-After header. Identify clients by IP, user ID, or API key for per-client limits.
Q38:

What are dependency injection best practices in Web API?

Entry

Answer

Best practices:

  • Use correct lifetimes: Singleton, Scoped, Transient
  • Prefer constructor injection
  • Avoid service locator pattern
  • Group and organize service registrations
Quick Summary: DI best practices: program to interfaces (inject IRepository, not Repository). Use Scoped for request-scoped state (DbContext, user context). Use Singleton for shared stateless services (HttpClient via IHttpClientFactory, configuration). Never capture Scoped in Singleton. Use AddHttpClient() for HttpClient (manages connection pooling). Avoid service locator pattern (don't inject IServiceProvider to call GetService manually).
Q39:

How do you monitor Web API performance in production?

Entry

Answer

Use monitoring platforms like:

  • Application Insights
  • Serilog + Seq
  • ELK Stack
  • Prometheus + Grafana

Track latency, errors, throughput, and resource usage.

Quick Summary: Monitor Web API: Application Insights (auto-collects requests, dependencies, exceptions, performance counters). Health checks endpoint (/health) for load balancer probes. Prometheus + Grafana for metrics. Structured logging with Serilog to ELK/Seq. Key metrics: request rate, error rate, latency (p95/p99), DB query time, thread pool size. Set up alerts on error rate spikes and latency degradation.
Q40:

How do you implement authentication in Web API?

Junior

Answer

Authentication verifies user identity in Web API.

Common implementations:

  • JWT Bearer Tokens – stateless authentication for SPA and mobile apps.
  • OAuth2 / OpenID Connect – external identity providers.
  • Cookie authentication – mainly for browser-based apps.

Configured using AddAuthentication() and UseAuthentication().

Quick Summary: JWT authentication: client sends Authorization: Bearer header. AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer() validates the JWT signature, issuer, audience, and expiration. Claims from the token populate HttpContext.User. Apply [Authorize] to require authentication. Use [Authorize(Roles = "Admin")] for role-based access. Always use HTTPS to protect tokens in transit.
Q41:

How does JWT authentication work?

Junior

Answer

JWT workflow:

  • User logs in ? server generates a signed JWT.
  • Client sends token in Authorization: Bearer <token>.
  • Server validates signature and extracts claims.
  • No server-side session required.
Quick Summary: JWT workflow: client authenticates (username/password) and receives a signed JWT from the auth server. JWT contains claims (user ID, roles, expiry) in a Base64-encoded payload. The server signs with a secret/private key. On subsequent requests, client sends the JWT. Server validates signature and expiry without hitting the database. Short-lived access tokens (15 min) + refresh tokens for renewal.
Q42:

How do you implement role-based authorization?

Junior

Answer

Use role-based authorization with:

[Authorize(Roles="Admin,Manager")]

Roles are validated from claims inside the JWT or identity provider.

Quick Summary: Role-based authorization: add roles as claims in the JWT or use ASP.NET Core Identity roles. [Authorize(Roles = "Admin,Manager")] restricts to users with those roles. Multiple roles in one attribute = OR logic. Stack multiple [Authorize] attributes for AND logic. Check roles in code: User.IsInRole("Admin"). Roles are a simple but coarse-grained authorization mechanism.
Q43:

What is claims-based authorization?

Junior

Answer

Claims-based authorization checks user claims instead of static roles.

Implemented using policy-based authorization:

services.AddAuthorization(options =>
{
    options.AddPolicy("HRPolicy",
        policy => policy.RequireClaim("Department", "HR"));
});
Quick Summary: Claims-based authorization: JWT/Identity tokens carry claims (key-value pairs about the user). [Authorize(Policy = "MinimumAge")] uses a policy that evaluates claims. Define policies: builder.Services.AddAuthorization(opts => opts.AddPolicy("MinimumAge", p => p.RequireClaim("age"))). More flexible than roles - claims can carry any attribute (department, subscription level, specific permissions).
Q44:

How do you create custom authorization policies?

Junior

Answer

Create policies in Program.cs using AddAuthorization.

Apply using [Authorize(Policy="PolicyName")].

Useful for domain-specific access control.

Quick Summary: Custom authorization policies: AddPolicy("CanEdit", policy => policy.Requirements.Add(new CanEditRequirement())). Implement IAuthorizationHandler: check the requirement against user claims and resource. Register handler with DI. Apply with [Authorize(Policy = "CanEdit")]. Resource-based authorization: pass the resource to IAuthorizationService.AuthorizeAsync(User, resource, "CanEdit").
Q45:

What is the difference between authentication and authorization?

Junior

Answer

Authentication: Verifies user identity.

Authorization: Determines what the authenticated user can access.

Quick Summary: Authentication: verifies who the user is (reads JWT/cookie, validates signature, extracts claims into HttpContext.User). Must happen before authorization. Authorization: decides what the authenticated user can do (reads claims, evaluates policies, checks [Authorize] attributes). These are separate concerns and separate middleware. A user can be authenticated (valid token) but not authorized (wrong role).
Q46:

How do you secure sensitive API endpoints?

Junior

Answer

Secure endpoints using:

  • [Authorize] attribute
  • HTTPS enforcement
  • Input validation
  • Rate limiting
  • CORS restrictions
Quick Summary: Secure sensitive endpoints: require authentication ([Authorize]), enforce HTTPS, apply role/policy authorization, rate limit login and sensitive operations, log all access attempts (with user ID and IP), validate all inputs, use parameterized queries for DB access, and return minimal error details. For extra-sensitive data: add IP allowlisting, require MFA, and audit every access.
Q47:

How do you handle token expiration in JWT?

Junior

Answer

JWT includes an exp claim for expiration.

API rejects expired tokens automatically.

Refresh tokens extend the session securely.

Quick Summary: JWT expiration handling: issue short-lived access tokens (15-60 min) and longer-lived refresh tokens. When access token expires, client uses refresh token to get a new access token from the auth endpoint. Validate refresh tokens against a store (Redis/DB) to allow revocation. Rotate refresh tokens on use (detect replay attacks). Use sliding expiration: refresh token TTL resets on each use.
Q48:

How do you protect against CSRF attacks in APIs?

Junior

Answer

API best practices:

  • Use JWT instead of cookies
  • Enable strict CORS policies
  • Use anti-forgery tokens if cookies are used
Quick Summary: CSRF attacks trick authenticated users into making unwanted requests. For stateless JWT APIs (Authorization header): CSRF is not a concern (browsers don't auto-send custom headers). For cookie-based auth: use antiforgery tokens (ValidateAntiforgeryToken), SameSite=Strict/Lax cookie attribute, or custom request header validation. Most REST APIs using Bearer tokens don't need CSRF protection.
Q49:

How do you secure API keys in Web API?

Junior

Answer

Best practices:

  • Store in Key Vault or environment variables
  • Never hard-code keys
  • Rotate keys periodically
Quick Summary: Secure API keys: store in environment variables or Azure Key Vault (never in code or config files). Pass as Authorization header or custom header (not in URL - it gets logged). Hash and store API keys server-side (don't store plaintext). Rotate keys regularly. Scope keys to minimum required permissions. Rate limit per API key. Log all API key usage for auditing.
Q50:

What is OAuth2 and how is it used with Web API?

Junior

Answer

OAuth2 is a secure authorization framework.

Flow: Client ? Auth Server ? Access Token ? API.

Supports scopes, roles, and claims.

Quick Summary: OAuth2 is an authorization framework. Web API acts as a Resource Server that accepts OAuth2 access tokens. An Authorization Server (IdentityServer, Azure AD, Auth0) issues tokens. Clients get tokens by presenting credentials (client credentials flow for machine-to-machine, authorization code flow for users). The API validates tokens using the auth server's public keys (JWKS endpoint).
Q51:

How do scopes differ from roles in OAuth2?

Junior

Answer

Roles: Broad user categories.

Scopes: Fine-grained permissions such as read:orders.

Quick Summary: Roles: coarse-grained groups (Admin, User, Manager) assigned to users. Scopes in OAuth2: specific permissions requested by a client app for what it can do with the API (read:orders, write:products). Roles are about who the user is. Scopes are about what the client application is allowed to do. An API might check both: user must have Admin role AND client must have write scope.
Q52:

How do you implement token revocation?

Junior

Answer

Token revocation strategies:

  • Blacklist tokens in database
  • Short-lived access tokens
  • Rotating refresh tokens
Quick Summary: Token revocation: JWTs are stateless - no built-in revocation. To revoke: maintain a token blocklist in Redis (check on each request, fast lookup). Short-lived tokens reduce the window. Use refresh token rotation - invalidate refresh token on use or logout. For immediate revocation (compromised account): store user's "token issued before" timestamp and reject tokens issued before logout.
Q53:

How do you implement multi-tenant security?

Junior

Answer

Multi-tenant API security includes:

  • Tenant ID in claims or headers
  • Middleware-based access validation
  • Database filtering by tenant context
Quick Summary: Multi-tenant security: include tenant ID in JWT claims. Validate tenant claim on every request. Filter all DB queries by tenant ID (row-level security or query filters in EF Core). Use separate schemas or databases per tenant for stronger isolation. Prevent tenant data leakage in error messages. Audit cross-tenant access attempts. Use EF Core global query filters to automatically apply tenant filtering.
Q54:

How do you prevent over-posting attacks?

Junior

Answer

Use DTOs instead of binding directly to entity models.

Expose only allowed fields.

Always validate incoming payloads.

Quick Summary: Over-posting: client sends extra fields that get bound to the model and saved unintentionally (e.g., sending IsAdmin=true and having it bound to the user object). Prevent with: separate DTOs for input (only include fields clients should set), [BindNever] to exclude properties, or explicit model mapping. Never bind domain entities directly to HTTP request bodies in production APIs.
Q55:

What are best practices for securing Web API endpoints?

Junior

Answer

  • Force HTTPS
  • Use [Authorize]
  • Limit payload size
  • Use secure headers
  • Validate all inputs
  • Implement logging & monitoring
Quick Summary: Web API security best practices: always use HTTPS, authenticate every endpoint ([Authorize]), validate all inputs, use parameterized queries for DB access, return minimal error details (no stack traces), implement rate limiting, keep dependencies updated, scan for vulnerabilities (Snyk, OWASP), log security events (failed auth, suspicious requests), and apply CORS restrictions to trusted origins only.
Q56:

How do you implement refresh tokens securely?

Junior

Answer

Best practices:

  • Store refresh tokens securely
  • Use rotating refresh tokens
  • Issue short-lived access tokens
  • Revoke tokens on suspicious activity
Quick Summary: Refresh tokens securely: store server-side as hashed values (never plaintext) in DB/Redis. Issue new access token + new refresh token on each refresh (rotation). Invalidate old refresh token after rotation. Detect reuse: if a rotated token is presented again, revoke all tokens for that user (indicates theft). Set refresh token expiry (7-30 days). Store in HttpOnly cookie or secure storage (not localStorage).
Q57:

How do you check roles and claims programmatically?

Junior

Answer

Use HttpContext methods:

  • User.IsInRole("Admin")
  • User.Claims to inspect claim values
Quick Summary: Check roles and claims in code: User.IsInRole("Admin"), User.HasClaim(c => c.Type == "dept" && c.Value == "Engineering"), User.FindFirst(ClaimTypes.Email)?.Value. In controllers with [Authorize] applied, HttpContext.User is always populated with the authenticated user's claims. Use IAuthorizationService.AuthorizeAsync() for resource-based checks where the specific resource matters.
Q58:

How do you implement custom JWT claims?

Junior

Answer

Add claims during token creation (email, role, custom fields).

Validate claims in controllers or authorization policies.

Quick Summary: Custom JWT claims: add claims when generating the token: new Claim("subscription", "premium"), new Claim("tenant_id", tenantId). Read in controllers: User.FindFirst("subscription")?.Value. Map custom claims to a strongly-typed object with custom IClaimsTransformation. Use claim names consistently with reverse-DNS format (com.company.claim-name) to avoid conflicts with standard claim names.
Q59:

How do you audit API usage for security?

Junior

Answer

Audit using structured logs including:

  • User identity
  • Action invoked
  • Timestamp
  • IP address
  • Request and response metadata

Essential for compliance and threat detection.

Quick Summary: Audit API usage: log every authenticated request with user ID, endpoint, timestamp, source IP, and response status. Use structured logging (Serilog/NLog) to a searchable log store. Action filters or middleware for consistent audit logging across all endpoints. Flag anomalous patterns (many requests in short time, unusual endpoints). Retain audit logs per compliance requirements (GDPR, PCI-DSS).
Q60:

How do you implement API versioning effectively?

Mid

Answer

API versioning ensures backward compatibility and predictable updates.

Common approaches:

  • URL versioning: /api/v1/resource
  • Query versioning: ?api-version=1.0
  • Header versioning: api-version: 1.0

Use the Microsoft.AspNetCore.Mvc.Versioning package and decorate controllers with [ApiVersion("1.0")].

Quick Summary: API versioning effectively: choose strategy (URL path is most common: /api/v1/). Use Microsoft.AspNetCore.Mvc.Versioning package. [ApiVersion("1.0")] on controllers, [MapToApiVersion] on actions. Maintain old versions as long as clients use them. Track version usage via analytics. Deprecate with advance notice and a sunset date. Never break an existing version without a major version bump.
Q61:

How do you implement compression in Web API?

Mid

Answer

Enable compression using:

services.AddResponseCompression()

Supports Gzip and Brotli to reduce payload size and improve performance.

Quick Summary: Response compression reduces payload size. UseResponseCompression() middleware compresses responses. Add providers: AddResponseCompression(opts => opts.Providers.Add()). Client signals support via Accept-Encoding: gzip header. Compress text responses (JSON, HTML) but not already-compressed files. Set minimum size threshold to avoid compressing tiny responses (overhead > benefit).
Q62:

How do you handle exceptions globally?

Mid

Answer

Global exception handling centralizes error responses.

Use:

  • UseExceptionHandler() middleware
  • Custom exception-handling middleware
  • Standardized error payloads and logging
Quick Summary: Global exception handling: use app.UseExceptionHandler() middleware. Catches unhandled exceptions, logs them, and returns a structured error response. .NET 8: implement IExceptionHandler interface, register with AddExceptionHandler(). Return ProblemDetails (RFC 7807) for consistent error format across all endpoints. Never expose exception details (stack trace, internal messages) to API clients in production.
Q63:

What are best practices for structured error responses?

Mid

Answer

Include:

  • statusCode
  • message
  • errors (validation details)
  • traceId

Avoid exposing internal details for security.

Quick Summary: Structured error responses: use RFC 7807 ProblemDetails format: {type, title, status, detail, instance}. Return consistent error shapes for all error types. Include a unique error code that clients can reference. For validation errors: include field-level details. Configure in AddProblemDetails() (ASP.NET Core 7+). Clients can parse errors reliably rather than parsing varied error message strings.
Q64:

How do you implement rate limiting / throttling?

Mid

Answer

Use libraries like AspNetCoreRateLimit to:

  • Limit requests per IP or client
  • Protect server from abuse
  • Apply global or endpoint-specific rules
Quick Summary: Rate limiting in .NET 7+: AddRateLimiter() in services. Policies: FixedWindowLimiter (X requests per window), SlidingWindowLimiter (smoother counting), TokenBucketLimiter (allows bursts), ConcurrencyLimiter (max simultaneous requests). Identify clients by IP or user ID with a partitioning key. Returns 429 Too Many Requests with Retry-After. Apply per-route or globally.
Q65:

How do you handle large payloads efficiently?

Mid

Answer

Use streaming techniques:

  • IFormFile for uploads
  • Avoid full in-memory buffering
  • Enable compression where needed
Quick Summary: Handle large payloads: increase RequestSizeLimitAttribute per endpoint or globally in Kestrel options. Use streaming: read request body as a stream instead of loading entirely into memory (IFormFile for file uploads, JsonSerializer.DeserializeAsync with Stream). Enable request body buffering only when needed. For very large uploads, use direct-to-blob streaming (Azure Blob, S3) rather than proxying through the API.
Q66:

How do you implement conditional requests?

Mid

Answer

Use:

  • ETag
  • Last-Modified
  • If-None-Match or If-Modified-Since

Returns 304 Not Modified when content is unchanged.

Quick Summary: Conditional requests reduce bandwidth. Server sends ETag (hash of content) and Last-Modified in responses. Client caches and sends If-None-Match/If-Modified-Since on next request. Server compares: if unchanged, return 304 Not Modified (no body). Implement in middleware or action filters. Useful for read-heavy endpoints where data changes infrequently. Reduces server load and network traffic for unchanged resources.
Q67:

How do you prevent over-fetching in Web APIs?

Mid

Answer

Use field selection / projection such as:

?fields=name,email

Implement DTOs to avoid returning unnecessary properties.

Quick Summary: Prevent over-fetching: return only requested fields. Use GraphQL for client-specified field selection. Or implement sparse fieldsets: GET /api/users?fields=id,name,email. Design DTOs per use case (list DTO with fewer fields, detail DTO with more). Avoid returning entire entity graphs when only a few fields are needed. Reduces payload size and serialization cost.
Q68:

How do you implement HATEOAS in Web API?

Mid

Answer

HATEOAS enriches responses with navigational links.

Example:

Order response may include:

  • self link
  • update link
  • cancel link
Quick Summary: HATEOAS (Hypermedia As The Engine Of Application State): responses include links to related actions. Example: GET /api/orders/123 returns the order plus links: {self: /api/orders/123, cancel: /api/orders/123/cancel, items: /api/orders/123/items}. Clients discover available actions from responses rather than hardcoding URLs. Adds flexibility but increases response size and client complexity. Rarely implemented in practice.
Q69:

How do you implement distributed caching?

Mid

Answer

Use:

  • Redis
  • SQL Server distributed cache
  • Memcached

Useful for multi-instance API deployments.

Quick Summary: Distributed caching with Redis: IDistributedCache interface injected, backed by Redis. cache.GetStringAsync(key), SetStringAsync(key, value, options). Set TTL with DistributedCacheEntryOptions. Use for: session state, frequently read but rarely changing data, pre-computed responses. IMemoryCache is per-server (lost on restart, not shared in scaled apps). Redis is shared across all instances.
Q70:

How do you secure sensitive data in responses?

Mid

Answer

Avoid sending PII or sensitive fields.

Use DTOs, masking, or encryption.

Always enforce HTTPS.

Quick Summary: Secure sensitive data in responses: never return passwords or hashed passwords. Exclude PII fields not needed by the client (use [JsonIgnore] or response DTOs). Mask sensitive fields (show last 4 digits of card). Encrypt sensitive data stored in DB. Use HTTPS to protect in-transit data. Implement field-level encryption for highly sensitive fields. Audit access to sensitive data endpoints.
Q71:

How do you handle versioning breaking changes?

Mid

Answer

Best practices:

  • Maintain old versions
  • Introduce new versioned endpoints
  • Document migration paths
Quick Summary: Handle versioning breaking changes: increment major version for breaking changes (/api/v2/). Maintain v1 until clients migrate. Track which clients use which version via analytics. Communicate deprecation schedule early. Use API changelog and migration guide. Breaking changes include: removing fields, changing field types, changing required/optional status, removing endpoints. Adding optional fields is non-breaking.
Q72:

How do you implement pagination?

Mid

Answer

Use Skip and Take (LINQ).

Include:

  • page
  • pageSize
  • totalCount
  • totalPages
Quick Summary: Pagination: return page of results with metadata. Offset-based: GET /api/users?page=2&pageSize=20 - simple but slow for large offsets. Cursor-based (keyset): GET /api/users?after=lastId&limit=20 - efficient for large datasets. Response: {data: [...], nextCursor: "...", totalCount: N}. Use EF Core Skip/Take for offset or WHERE id > cursor for keyset. Return Link headers for page navigation.
Q73:

How do you implement filtering and sorting?

Mid

Answer

Expose query parameters for filtering and sorting:

  • ?status=active
  • ?sort=name_desc

Combine with pagination for scalable responses.

Quick Summary: Filtering and sorting: accept filter params in query string: GET /api/orders?status=active&minAmount=100. Sorting: GET /api/users?sort=lastName&dir=asc. Use a filter model class bound with [FromQuery]. Map to EF Core LINQ: .Where(o => o.Status == filter.Status). For complex filtering, use specification pattern or OData. Sanitize sort field names against a whitelist to prevent injection.
Q74:

How do you monitor API performance in production?

Mid

Answer

Use monitoring tools:

  • Application Insights
  • Prometheus + Grafana
  • Serilog

Track duration, throughput, failure rates, response sizes.

Quick Summary: Monitor API performance: track request rate, error rate, and latency (p50/p95/p99) with Application Insights, Prometheus, or Datadog. Add custom metrics (business KPIs, cache hit rate). Health checks endpoint for infrastructure probes. Distributed tracing (OpenTelemetry) to trace requests across services. Alert on: error rate > 1%, p99 latency > threshold, health check failures.
Q75:

How do you implement API health checks?

Mid

Answer

Use built-in health checks:

services.AddHealthChecks();

Expose /health endpoint to monitor DB, disk, and external services.

Quick Summary: Health checks: AddHealthChecks() in services, MapHealthChecks("/health") to expose. Add checks for DB (AddDbContextCheck()), Redis (AddRedis()), and custom checks. Separate /health/live (is the process running) from /health/ready (is it ready for traffic). Kubernetes uses liveness and readiness probes against these endpoints. Return 200 (healthy), 503 (unhealthy).
Q76:

How do you maintain backward compatibility while refactoring endpoints?

Mid

Answer

Keep older versions active.

Deprecate API versions gradually.

Provide documentation for migration.

Quick Summary: Backward compatibility while refactoring: don't rename, remove, or change required/optional on existing endpoint parameters. Add new endpoints rather than modifying old ones. Use API versioning to introduce breaking changes as v2. Mark old behavior as deprecated with deprecation warnings. Write contract tests that validate the existing API contract is preserved after each refactor.
Q77:

How do you implement API documentation effectively?

Mid

Answer

Use Swagger / OpenAPI:

  • Interactive documentation
  • Multiple version support
  • Authentication integration
  • Schema validation
Quick Summary: API documentation with Swagger: install Swashbuckle.AspNetCore. AddSwaggerGen() in services, UseSwagger() and UseSwaggerUI() in middleware. Add XML comments: tags and [ProducesResponseType] attributes generate rich docs. Configure JWT auth in Swagger UI for testing protected endpoints. Generate OpenAPI spec for client code generation. Keep docs in sync - use contract-first approach.
Q78:

How do you integrate Entity Framework Core with Web API?

Mid

Answer

To integrate EF Core with Web API:

  • Install EF Core packages such as Microsoft.EntityFrameworkCore and Microsoft.EntityFrameworkCore.SqlServer.
  • Register your DbContext in Program.cs using AddDbContext.
  • Inject DbContext via constructor injection in controllers or services.
  • Use migrations and LINQ for strongly-typed database access.
Quick Summary: EF Core integration: install EF Core package + DB provider (EF Core SqlServer, Npgsql). Add DbContext via AddDbContext() with connection string from config. Use Scoped lifetime (one instance per request). Access entities via DbSet. Use async methods (ToListAsync, FirstOrDefaultAsync) for all DB operations. Apply migrations to manage schema changes.
Q79:

What is the difference between DbContext and DbSet?

Mid

Answer

DbContext manages the database connection, querying, saving, and tracking of entities.

DbSet<T> represents a table and allows querying and CRUD operations for that entity type.

Quick Summary: DbContext is the unit of work and gateway to the database. It manages the connection and tracks entity changes. DbSet represents a table - use it to query (LINQ) and modify (Add, Remove) entities. One DbContext instance per request (Scoped). Multiple DbSet properties (one per entity type) in a DbContext. SaveChangesAsync() persists all tracked changes to the DB in one transaction.
Q80:

How do you implement DTOs and why?

Mid

Answer

DTOs decouple API contracts from internal entity models.

Benefits:

  • Prevents over-posting
  • Improves security
  • Helps with API versioning
  • Simplifies maintenance

Mapping can be done manually or using AutoMapper.

Quick Summary: DTOs (Data Transfer Objects) separate the API contract from domain entities. Input DTOs: define exactly what clients should send (prevent over-posting). Output DTOs: define exactly what clients receive (prevent leaking sensitive fields). DTOs are stable even when domain entities change. Use AutoMapper or manual mapping to convert. Never expose domain entities directly as API request/response models.
Q81:

What is the Repository Pattern and why use it?

Mid

Answer

The Repository Pattern abstracts the data access layer.

It provides:

  • Clean separation of concerns
  • Mockable interfaces for testing
  • Consistent CRUD interface
Quick Summary: Repository pattern abstracts data access behind an interface. IUserRepository defines operations (FindByIdAsync, GetAll, Add). Implementation uses EF Core. Controllers inject IUserRepository - decoupled from EF Core. Benefits: testability (mock the repository), swappable data source, centralized query logic. Debate: EF Core DbContext already implements repository pattern - adding another layer may be unnecessary overhead.
Q82:

How do you implement Unit of Work pattern?

Mid

Answer

The Unit of Work pattern groups operations under one transaction.

DbContext naturally acts as a Unit of Work; calling SaveChangesAsync commits all changes atomically.

Quick Summary: Unit of Work coordinates multiple repository operations in a single transaction. IUnitOfWork holds references to repositories and has SaveChangesAsync(). All operations complete before committing. If any fails, all roll back. In practice with EF Core: DbContext IS the Unit of Work (tracks all changes across DbSets and commits them together). Adding a separate UoW layer over EF Core is often redundant.
Q83:

How do you handle transactions in EF Core?

Mid

Answer

Use explicit transactions via:

await context.Database.BeginTransactionAsync();

Wrap operations in try/catch to commit or rollback.

Quick Summary: EF Core transactions: by default, SaveChangesAsync() wraps all changes in a transaction. Explicit transactions: using var tx = await context.Database.BeginTransactionAsync(); try { ... await context.SaveChangesAsync(); await tx.CommitAsync(); } catch { await tx.RollbackAsync(); }. Use explicit transactions when you need multiple SaveChanges or mix EF Core with raw SQL in one transaction.
Q84:

How do you implement asynchronous queries in EF Core?

Mid

Answer

Use async LINQ extensions:

  • ToListAsync()
  • FirstOrDefaultAsync()
  • SingleOrDefaultAsync()

Improves scalability by freeing threads during database I/O.

Quick Summary: Async EF Core queries: always use async methods - ToListAsync(), FirstOrDefaultAsync(), SingleOrDefaultAsync(), CountAsync(), AnyAsync(), SaveChangesAsync(). These return Task and release the thread during DB I/O. Mixing sync and async EF Core operations in the same DbContext instance can cause issues. Never use .Result or .Wait() on EF Core async operations.
Q85:

How do you implement filtering and sorting with EF Core?

Mid

Answer

Use LINQ:

  • Where() for filtering
  • OrderBy()/OrderByDescending() for sorting
  • Skip()/Take() for pagination
Quick Summary: Filtering with EF Core: apply Where() predicates that translate to SQL WHERE clauses. Sorting: OrderBy(x => x.Name).ThenBy(x => x.Id). Dynamic sorting: use reflection or a library like System.Linq.Dynamic.Core to build expressions from string sort fields. Always validate sort field names against allowed values to prevent injection. Apply pagination after filtering and sorting.
Q86:

How do you prevent over-posting when updating entities?

Mid

Answer

Use DTOs and map only allowed fields.

Avoid binding client input directly to entity models.

Quick Summary: Prevent over-posting in EF Core updates: never use context.Update(entity) with a fully entity-mapped request body. Instead: load the existing entity from DB, map only allowed fields from the DTO to the entity, call SaveChangesAsync(). Only the mapped fields change. Or use separate update DTOs with [BindNever] on sensitive properties. Entity.Entry(entity).Property(x => x.Name).IsModified = true for granular updates.
Q87:

How do you implement soft deletes?

Mid

Answer

Add an IsDeleted flag and filter queries:

.Where(x => !x.IsDeleted)

Useful for audits and data recovery.

Quick Summary: Soft deletes mark records as deleted without removing them. Add IsDeleted bool and DeletedAt timestamp columns. Override SaveChangesAsync to auto-set these on delete. Use EF Core global query filters: modelBuilder.Entity().HasQueryFilter(x => !x.IsDeleted) - automatically excludes deleted records from all queries. Disable with IgnoreQueryFilters() when needed. Useful for audit trails and data recovery.
Q88:

How do you implement optimistic concurrency in EF Core?

Mid

Answer

Use a RowVersion (timestamp) column.

EF detects conflicts and throws DbUpdateConcurrencyException.

Quick Summary: Optimistic concurrency: add a rowversion/timestamp column. EF Core adds it to UPDATE WHERE clause - if another process changed the row, the WHERE fails (0 rows affected) and throws DbUpdateConcurrencyException. Handle: catch the exception, reload the entity (fresh values), show conflict to user or auto-merge based on rules. [Timestamp] attribute on byte[] property enables rowversion-based concurrency.
Q89:

How do you implement eager, lazy, and explicit loading?

Mid

Answer

Eager: Include()

Lazy: Navigation property auto-loading (requires proxies)

Explicit: context.Entry(entity).Collection(...).Load()

Quick Summary: Eager loading: Include() loads related entities in one query (JOIN). Good when you always need the related data. Lazy loading: related entities load when first accessed (requires proxy). Risk of N+1 queries - avoid in Web API. Explicit loading: context.Entry(entity).Collection(x => x.Orders).LoadAsync() - load on demand. Choose eager for predictable queries, explicit for conditional loading, avoid lazy in APIs.
Q90:

How do you handle many-to-many relationships in EF Core?

Mid

Answer

EF Core 5+ supports many-to-many with:

HasMany().WithMany()

Junction table is auto-created unless custom entity is needed.

Quick Summary: Many-to-many in EF Core 5+: define navigation collections on both sides, EF Core creates the join table automatically (no explicit join entity needed). modelBuilder.Entity().HasMany(s => s.Courses).WithMany(c => c.Students). For a join entity with extra fields (enrollment date): use explicit join entity with two foreign keys. Query: student.Courses or context.StudentCourses.Where(...).
Q91:

How do you handle transactions across multiple DbContext instances?

Mid

Answer

Use TransactionScope for distributed transactions.

Or share the same database connection among contexts.

Quick Summary: Multiple DbContext transactions: use TransactionScope (distributed) or manually share a connection. Better approach: use a single DbContext that spans all operations. If you must use multiple DbContexts, create a shared IDbContextTransaction: var outer = await context1.Database.BeginTransactionAsync(); await context2.Database.UseTransactionAsync(outer.GetDbTransaction()). Rarely needed - redesign to use one DbContext.
Q92:

How do you execute raw SQL queries in EF Core?

Mid

Answer

Use:

  • FromSqlRaw() for queries
  • ExecuteSqlRaw() for commands

Always use parameters to prevent SQL injection.

Quick Summary: Raw SQL in EF Core: context.Database.ExecuteSqlRawAsync("DELETE FROM Logs WHERE CreatedAt < {0}", cutoff) for commands. context.Users.FromSqlRaw("SELECT * FROM Users WHERE Name = {0}", name) for queries (still tracked). Use parameterized queries (not string concatenation) to prevent SQL injection. Return mapped entities with FromSqlRaw, anonymous types with Dapper alongside EF Core.
Q93:

How do you implement caching for database queries?

Mid

Answer

Use:

  • IMemoryCache for local cache
  • Redis for distributed cache

Cache expensive queries and invalidate on updates.

Quick Summary: Cache DB queries: IMemoryCache for single-server in-process cache. IDistributedCache (Redis) for multi-server. Pattern: check cache first (cache.TryGetValue(key, out var result)), on miss query DB and cache result with TTL, on data change invalidate cache. EF Core Second Level Cache NuGet packages automate this. Cache reference data (countries, categories) aggressively; user-specific data with short TTL or not at all.
Q94:

How do you implement pagination efficiently in EF Core?

Mid

Answer

Use:

Skip((page-1)*pageSize).Take(pageSize)

Combine with filtering and sorting before applying pagination.

Quick Summary: Efficient pagination with EF Core: offset-based: .Skip((page-1)*pageSize).Take(pageSize) - gets slow for large offsets. Keyset pagination: WHERE id > lastSeenId LIMIT pageSize - stays fast regardless of depth. Return totalCount separately (COUNT() query) only when needed (expensive on large tables). Use async: ToListAsync(). Include an index on the sort column for performance.
Q95:

How do you handle migrations in EF Core?

Mid

Answer

Use:

  • Add-Migration
  • Update-Database

Supports schema evolution and controlled deployments.

Quick Summary: EF Core migrations: dotnet ef migrations add MigrationName generates a migration file. dotnet ef database update applies it. Review generated SQL before applying to production. Store migration files in source control. Use CI/CD to apply migrations automatically (Database.MigrateAsync() on startup or migration runner). Never delete applied migration files. Use --idempotent flag for generating idempotent SQL scripts.
Q96:

How do you manage large datasets in EF Core?

Mid

Answer

Best practices:

  • Use projection via Select()
  • Use pagination
  • Avoid ToList() on large tables
  • Optimize queries with indexes
Quick Summary: Large datasets with EF Core: use AsNoTracking() for read-only queries (no change tracking overhead). Stream results with AsAsyncEnumerable() and await foreach instead of loading all into memory. Use pagination (Skip/Take). Use raw SQL (FromSqlRaw) for complex queries that EF Core translates poorly. Enable connection resiliency for transient failures. Split large queries into batches.
Q97:

How do you test Web API with EF Core?

Mid

Answer

Testing strategies:

  • Use InMemory provider for unit tests
  • Use SQLite in-memory for integration tests
  • Mock repositories/DbContext for isolation
Quick Summary: Test Web API with EF Core: use WebApplicationFactory with UseInMemoryDatabase for integration tests (or SQLite for more complete testing). Reset DB state between tests. Unit test: mock IRepository or use an in-memory context. Don't test EF Core queries with just mocks - you need a real DB to verify query translation. TestContainers library spins up a real PostgreSQL/SQL Server container for tests.
Q98:

What are common Web API design patterns?

Senior

Answer

Common Web API design patterns improve maintainability, scalability, and testability:

  • Repository Pattern – Abstracts data access; simplifies unit testing and business logic separation.
  • Unit of Work – Groups operations under a single transaction for consistency.
  • CQRS – Separates read and write operations for scalability and performance.
  • Mediator / MediatR – Decouples request-handling logic using command/query handlers.
  • Decorator Pattern – Adds logging, caching, or auditing without modifying core business logic.
Quick Summary: Common Web API design patterns: Repository (abstract data access), CQRS (separate read/write), Mediator (decouple controller from handlers - MediatR library), DTO (separate API contract from domain), Decorator (add behavior without modifying service), Factory (create complex objects), Options pattern (strongly-typed config). These patterns together create maintainable, testable APIs.
Q99:

How do you implement centralized logging?

Senior

Answer

Centralized logging ensures consistent tracking across all API requests.

  • Use ILogger<T> via dependency injection.
  • Capture structured logs with levels (Trace ? Critical).
  • Write logs to console, files, databases, or providers like Seq, ELK, Splunk, or Application Insights.
  • Use middleware to log incoming requests, outgoing responses, and execution duration.
Quick Summary: Centralized logging: use ILogger everywhere. Configure Serilog: WriteTo.File(), WriteTo.Seq(), WriteTo.Elasticsearch(). Structure log entries with context (UserId, CorrelationId, RequestPath). Use Serilog.Enrichers.CorrelationId. Forward to centralized system (ELK, Datadog, Application Insights). Configure log levels per namespace in appsettings.json to control verbosity.
Q100:

How do you implement safe request and response logging?

Senior

Answer

To log request/response bodies safely:

  • Use custom middleware to intercept HTTP pipeline.
  • Enable request buffering using HttpRequest.EnableBuffering().
  • Buffer and copy response streams using a wrapper.
  • Avoid logging sensitive fields such as passwords, tokens, and PII.
  • Include traceId or correlationId for cross-service tracking.
Quick Summary: Safe request/response logging: log route, HTTP method, status code, duration for every request. For body logging: use middleware that buffers body (EnableBuffering()), reads it, logs it, resets stream. Avoid logging: Authorization headers, passwords, PII (mask or exclude these fields). Set max logged body size (e.g., 10KB). Use structured logging so sensitive fields can be redacted via enrichers.
Q101:

How do you implement response caching effectively?

Senior

Answer

Effective caching improves performance and reduces database load:

  • Use the [ResponseCache] attribute for client caching.
  • Use server-side caching middleware for heavy endpoints.
  • Leverage distributed caches like Redis or Memcached for load-balanced apps.
  • Apply cache invalidation strategies to prevent stale data.
Quick Summary: Response caching: [ResponseCache(Duration = 60)] sets Cache-Control: public, max-age=60. UseResponseCaching() middleware caches on server. For user-specific responses: [ResponseCache(Location = ResponseCacheLocation.Client)] (client-side only). Vary by query string: VaryByQueryKeys = new[]{"q"}. CDN caches public API responses at the edge. Use ETags for conditional requests to reduce bandwidth.
Q102:

How do you implement API documentation with Swagger?

Senior

Answer

Swagger/OpenAPI improves discoverability and client integration.

  • Install Swashbuckle.AspNetCore.
  • Configure AddSwaggerGen() in Program.cs.
  • Include XML comments for controllers and models.
  • Support authentication, versioning, schema examples, and UI customization.
Quick Summary: Swagger documentation: AddSwaggerGen() with XML comments enabled (true). Add [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(UserDto))] on actions. Configure JWT auth: c.AddSecurityDefinition and c.AddSecurityRequirement. Add operation filters for common headers. UseSwaggerUI() with ReDocUI as an alternative. Use SwaggerDoc for versioned docs.
Q103:

How do you organize Web API endpoints for large applications?

Senior

Answer

Large-scale APIs require structured endpoint organization:

  • Use feature-based folder structure instead of traditional controller-based.
  • Group routes using /api/v1/[module]/[controller].
  • Use Areas for large domains.
  • Apply consistent naming and versioning strategies.
Quick Summary: Organize large Web API endpoints: feature-based folder structure (Features/Orders/OrdersController.cs). Keep controllers thin - delegate to services/handlers. Use MediatR: each action dispatches a command/query, handler contains logic. Version namespaces (Controllers/V1/, Controllers/V2/). Separate API routes by domain area. Keep controller files small - split by resource if they grow large.
Q104:

How do you handle unhandled exceptions in asynchronous code?

Senior

Answer

To handle async exceptions:

  • Wrap async operations in try/catch.
  • Ensure thrown exceptions bubble to global exception middleware.
  • Capture structured logs for debugging.
  • Avoid async void except for event handlers.
Quick Summary: Unhandled exceptions in async code: exceptions in fire-and-forget tasks (Task.Run without await) are swallowed. Fix: always await tasks or attach .ContinueWith for error handling. Set TaskScheduler.UnobservedTaskException to log errors from abandoned tasks. In controllers: always await async calls - never return void from async action methods. Use IHostedService with proper exception handling for background work.
Q105:

How do you implement health checks?

Senior

Answer

Health checks monitor service and dependency availability.

  • Use Microsoft.Extensions.Diagnostics.HealthChecks.
  • Expose a /health endpoint.
  • Check database connections, external APIs, disk, cache, etc.
  • Integrate with monitoring tools (Kubernetes, Azure, AWS, Prometheus).
Quick Summary: Health checks: AddHealthChecks() with checks for DB, Redis, message queues, external APIs. MapHealthChecks("/health/ready") and MapHealthChecks("/health/live"). HealthCheckPublisher for pushing metrics to monitoring systems. UI: add AspNetCore.HealthChecks.UI for a visual dashboard. Tag checks (db, cache) and filter by tag in separate endpoints for different probe types.
Q106:

How do you implement retry policies and resilience?

Expert

Answer

Resilience protects APIs from transient failures and cascading outages:

  • Use Polly for retry, circuit breaker, timeout, fallback, and bulkhead isolation policies.
  • Retry only for safe operations (idempotent GET or PUT).
  • Use exponential backoff and jitter to avoid retry storms.
  • Wrap external API calls, DB operations, and messaging clients with policies.
  • Monitor policy behavior to detect fragile dependencies.
Quick Summary: Retry policies with Polly: Install Microsoft.Extensions.Http.Polly. AddHttpClient().AddTransientHttpErrorPolicy(p => p.WaitAndRetryAsync(3, retry => TimeSpan.FromSeconds(Math.Pow(2, retry)))). Circuit breaker: AdvancedCircuitBreakerAsync(0.5, TimeSpan.FromSeconds(60), 10, TimeSpan.FromSeconds(30)). Retry + circuit breaker is the standard resilience combo for outgoing HTTP calls.
Q107:

How do you implement versioned Swagger documentation?

Expert

Answer

Versioned Swagger ensures clarity when multiple API versions coexist:

  • Configure multiple SwaggerDoc groups in AddSwaggerGen().
  • Use ApiExplorerSettings to group endpoints by version.
  • Apply versioned routes (v1, v2) or header/query-based versioning.
  • Expose separate Swagger UI endpoints for each version.
  • Helps clients migrate safely while maintaining backward compatibility.
Quick Summary: Versioned Swagger docs: call SwaggerDoc("v1", ...) and SwaggerDoc("v2", ...) in AddSwaggerGen. Use DocInclusionPredicate to match controllers to docs versions. UseSwaggerUI with multiple endpoints: c.SwaggerEndpoint("/swagger/v1/swagger.json", "V1") and v2. Combine with Microsoft.AspNetCore.Mvc.Versioning so each versioned controller appears in the correct Swagger doc.
Q108:

How do you implement pagination, filtering, and sorting consistently?

Expert

Answer

Consistent querying ensures scalable and predictable API behavior:

  • Use query parameters: page, pageSize, sort, filter.
  • Implement logic in repositories or service layer for maintainability.
  • Combine pagination with filtering and sorting before DB execution.
  • Cache frequently accessed listings for performance.
  • Return metadata: total records, total pages, current page, page size.
Quick Summary: Implement pagination, filtering, and sorting consistently: create a shared PagedRequest base class with page, pageSize, sortBy, sortDir fields. Create a PagedResponse with items, totalCount, pageNumber, totalPages. Apply across all list endpoints. Extract filtering/sorting to a reusable query builder. Return consistent metadata so clients can build paginated UIs without endpoint-specific logic.
Q109:

How do you implement HATEOAS for large APIs?

Expert

Answer

HATEOAS improves API discoverability and client navigation:

  • Embed hypermedia links (self, edit, delete, related resources) in response models.
  • Generate URLs using UrlHelper or route names.
  • Encapsulate link-building logic in DTOs or dedicated services.
  • Useful in large RESTful ecosystems where clients discover workflows dynamically.
Quick Summary: HATEOAS for large APIs: create a resource wrapper that includes _links. IActionLinkGenerator generates typed links. Use an IResourceAssembler to add links to response DTOs. Implement link templates following RFC 5988. In practice: most APIs use semi-HATEOAS (return IDs and common related endpoints) rather than full HATEOAS, as it adds complexity that clients rarely use fully.
Q110:

How do you implement correlation IDs for request tracing?

Expert

Answer

Correlation IDs enable tracking a request across microservices:

  • Generate or read a CorrelationId header in middleware.
  • Pass it to downstream services and logs.
  • Use logging scopes so all log entries share the same ID.
  • Send correlationId in the API response for client troubleshooting.
  • Critical for debugging distributed API flows.
Quick Summary: Correlation IDs for request tracing: generate a UUID per request in middleware (or read from X-Correlation-Id header if sent by client). Add to HttpContext.Items and to the log context (Serilog LogContext.PushProperty). Include in all outgoing HTTP calls via HttpClient handler. Return in X-Correlation-Id response header so clients can reference it in support requests. Links logs across all services for one user request.
Q111:

How do you compress responses dynamically?

Expert

Answer

Response compression improves performance for large payloads:

  • Enable AddResponseCompression() middleware.
  • Use Gzip or Brotli for optimal compression ratios.
  • Whitelisted MIME types ensure only necessary content is compressed.
  • Compression reduces bandwidth use and improves client response times.
Quick Summary: Dynamic response compression: UseResponseCompression() with GzipCompressionProvider and BrotliCompressionProvider. Client sends Accept-Encoding: gzip, br. Middleware picks best supported encoding. Set compression level: Fastest (less CPU, larger), Optimal (balance). Apply only to compressible content types (JSON, HTML, text). Minimum response size threshold to avoid compressing tiny responses.
Q112:

How do you test APIs effectively?

Expert

Answer

Effective testing ensures correctness, stability, and performance:

  • Unit test controllers using mocked services (Moq, NSubstitute).
  • Use WebApplicationFactory or TestServer for integration tests.
  • Use Postman/Newman or CI pipelines for end-to-end validation.
  • Validate headers, status codes, responses, and edge cases.
  • Load test APIs using JMeter, k6, or Locust to verify scalability.
Quick Summary: Test APIs effectively: unit tests for business logic (mock dependencies). Integration tests with WebApplicationFactory making real HTTP calls to the full pipeline. Test happy paths, error cases, authentication/authorization, input validation (malformed data, missing required fields), and boundary conditions. Use a test database (SQLite or TestContainers). Automate tests in CI/CD pipeline.
Q113:

How do you maintain API backward compatibility?

Expert

Answer

Backward compatibility prevents breaking existing clients:

  • Version APIs instead of modifying existing contracts.
  • Deprecate older versions gradually with communication.
  • Use DTOs to control exposed data without altering entities.
  • Document breaking changes and provide migration guides.
  • Avoid removing fields abruptly; mark them as deprecated first.
Quick Summary: Maintain API backward compatibility: never remove or rename existing fields - add new optional fields instead. Use Expand-Contract migration pattern for breaking changes. Add new optional query parameters without removing old ones. Document deprecated fields with [Obsolete] comments in Swagger. Version the entire API when breaking changes are unavoidable. Run contract tests (Pact) to catch accidental breaking changes.

Curated Sets for ASP.NET Web API

No curated sets yet. Group questions into collections from the admin panel to feature them here.

Ready to level up? Start Practice