Web API - realestateexplorer/relatedToCh GitHub Wiki
create web API interview questions and answers in .Net core
Of course! Here is a comprehensive set of .NET Core Web API interview questions and answers, categorized by difficulty level from Junior to Senior.
These questions focus on fundamental concepts and the basic building blocks of an ASP.NET Core Web API.
Answer: An ASP.NET Core Web API is a framework for building HTTP-based services that can be accessed by a wide range of clients, including browsers, mobile devices, and other backend services. It's built on .NET Core, making it cross-platform (runs on Windows, macOS, and Linux), high-performance, and open-source. It's ideal for creating RESTful services.
Answer: Kestrel is the default, cross-platform web server for ASP.NET Core. It's lightweight, extremely fast, and included by default in ASP.NET Core project templates. While Kestrel is a powerful server on its own, it's often used behind a more robust reverse proxy server like IIS (on Windows), Nginx, or Apache in production environments. The reverse proxy can handle tasks like load balancing, SSL termination, and serving static content.
Answer:
In .NET 6 and later, the Startup.cs
and Program.cs
files were merged into a single Program.cs
file for a more simplified and concise setup.
-
Program.cs
: This is the main entry point of the application. It's where you:- Create a
WebApplicationBuilder
. -
Configure services for Dependency Injection (e.g.,
builder.Services.AddControllers();
,builder.Services.AddDbContext<...>();
). -
Build the app (
var app = builder.Build();
). -
Configure the HTTP request pipeline (Middleware) (e.g.,
app.UseHttpsRedirection();
,app.MapControllers();
). -
Run the application (
app.Run();
).
- Create a
-
appsettings.json
: This file is used for application configuration, such as database connection strings, logging settings, and custom app settings. -
Controllers
Folder: This folder contains the API controller classes that handle incoming HTTP requests. -
launchSettings.json
: This file contains project-specific settings for running and debugging the application in different profiles (e.g., setting environment variables, launch URLs).
Answer: HTTP verbs (or methods) define the action to be performed on a resource. The most common ones used in RESTful APIs are:
- GET: Retrieves a resource. It should be safe and idempotent (making the same request multiple times has the same effect as a single request).
- POST: Creates a new resource. It is not idempotent.
- PUT: Updates an existing resource completely. If the resource doesn't exist, it can optionally create it. It is idempotent.
- PATCH: Partially updates an existing resource. It is not necessarily idempotent.
- DELETE: Deletes a resource. It is idempotent.
Answer:
The [ApiController]
attribute is applied to a controller class to enable specific, opinionated API behaviors. Key features include:
-
Automatic HTTP 400 Bad Request: It automatically triggers an HTTP 400 response if model validation fails, so you don't need to write
if (!ModelState.IsValid)
in every action. -
Attribute Routing Requirement: It enforces that you must use attribute routing (
[Route(...)]
) for actions in that controller. -
Binding Source Inference: It makes intelligent guesses about where to get data from. For example, complex types are assumed to come
[FromBody]
and simple types from the route or query string.
Example:
[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
// ...
}
These questions delve into core architectural concepts like middleware, dependency injection, and error handling.
Answer: Middleware components are software components that are assembled into an application pipeline to handle requests and responses. Each component can:
- Choose whether to pass the request to the next component in the pipeline.
- Perform work before and after the next component in the pipeline is invoked.
The request pipeline is the chain of these middleware components. The order is critical. For example, Authentication middleware must run before Authorization middleware.
Example Program.cs
Pipeline:
// ...
var app = builder.Build();
// Pipeline configuration
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
// 1. Redirects HTTP requests to HTTPS
app.UseHttpsRedirection();
// 2. Checks if the user is authenticated
app.UseAuthentication();
// 3. Checks if the authenticated user has permission
app.UseAuthorization();
// 4. Maps requests to controller actions
app.MapControllers();
app.Run();
Answer: Dependency Injection is a core design pattern in ASP.NET Core. When registering services, you must specify a lifetime, which determines how long the service instance will live.
Lifetime | Description |
---|---|
Singleton | A single instance is created for the entire application's lifetime. It's created the first time it's requested and then shared for all subsequent requests. |
Scoped | A new instance is created once per client request (connection). It's shared within the scope of that single HTTP request. |
Transient | A new instance is created every time it's requested. This is a lightweight, stateless service. |
How to register them in Program.cs
:
builder.Services.AddSingleton<IMySingletonService, MySingletonService>();
builder.Services.AddScoped<IMyScopedService, MyScopedService>();
builder.Services.AddTransient<IMyTransientService, MyTransientService>();
Answer:
ASP.NET Core has a built-in configuration system that can read settings from various sources. The standard way to handle environment-specific configuration is by using different appsettings.json
files.
-
appsettings.json
: Contains the base/default configuration shared across all environments. -
appsettings.{Environment}.json
: Contains settings that override the base file for a specific environment. For example,appsettings.Development.json
orappsettings.Production.json
. - The environment is determined by the
ASPNETCORE_ENVIRONMENT
environment variable.
The configuration provider loads these files in order, with later files overriding earlier ones. So, appsettings.Production.json
will override appsettings.json
.
Answer:
-
Authentication (Who are you?): This is the process of verifying a user's identity. It answers the question, "Who are you?". Common mechanisms include JWTs (JSON Web Tokens), OAuth, and cookies. In ASP.NET Core, you configure this with
app.UseAuthentication()
. -
Authorization (What are you allowed to do?): This is the process of determining if an authenticated user has permission to access a specific resource or perform an action. It answers the question, "Are you allowed to do this?". This is typically handled with attributes like
[Authorize]
and policies. In ASP.NET Core, you configure this withapp.UseAuthorization()
.
Analogy: Authentication is showing your ID to enter a building. Authorization is checking if your keycard opens a specific door inside that building.
Answer:
API versioning is crucial for managing changes without breaking existing clients. The most common way to implement this in ASP.NET Core is using the Microsoft.AspNetCore.Mvc.Versioning
NuGet package.
There are several versioning schemes:
-
URL Path Versioning (Most common):
api/v1/products
-
Query String Versioning:
api/products?api-version=1.0
-
Header Versioning:
Accept: application/json;v=1.0
Example Setup (URL Path Versioning):
- Install the NuGet package:
Microsoft.AspNetCore.Mvc.Versioning
- Configure in
Program.cs
:builder.Services.AddApiVersioning(options => { options.AssumeDefaultVersionWhenUnspecified = true; options.DefaultApiVersion = new ApiVersion(1, 0); options.ReportApiVersions = true; // Adds api-supported-versions header });
- Apply attributes to controllers:
[ApiController] [ApiVersion("1.0")] [Route("api/v{version:apiVersion}/[controller]")] public class ProductsController : ControllerBase { /* ... V1 actions ... */ } [ApiController] [ApiVersion("2.0")] [Route("api/v{version:apiVersion}/[controller]")] public class ProductsController : ControllerBase { /* ... V2 actions ... */ }
These questions test deeper knowledge of architecture, performance, security, and advanced framework features.
Answer: Both filters and middleware can be used to handle cross-cutting concerns, but they operate at different levels of the MVC pipeline.
Feature | Middleware | Filters |
---|---|---|
Scope | Operates on the entire HTTP request pipeline. It's unaware of the MVC context (like which action or controller is running). | Operates within the MVC action invocation pipeline. It has access to the MVC context (e.g., ActionExecutingContext ). |
Granularity | Applied globally to all requests. | Can be applied globally, to a controller, or to a specific action method. |
Use Cases | Logging, static file serving, routing, CORS, authentication. | Authorization, exception handling, response caching, custom model validation. |
Types of Filters:
- Authorization Filters
- Resource Filters
- Action Filters
- Exception Filters
- Result Filters
In summary: Use middleware when you need to act on every request and don't need MVC-specific context. Use filters when your logic is tied to the MVC action execution process.
Answer: There are two primary approaches for robust global exception handling:
-
Exception Handler Middleware (Recommended for APIs): This is the most common and flexible method. You can create a custom middleware or use the built-in
UseExceptionHandler
. It catches exceptions from downstream middleware, logs them, and generates a clean error response.In
Program.cs
:// ... if (app.Environment.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { // Custom error handling middleware for production app.UseExceptionHandler(appError => { appError.Run(async context => { context.Response.StatusCode = (int)HttpStatusCode.InternalServerError; context.Response.ContentType = "application/json"; var contextFeature = context.Features.Get<IExceptionHandlerFeature>(); if (contextFeature != null) { // Log contextFeature.Error here await context.Response.WriteAsync(new ErrorDetails() { StatusCode = context.Response.StatusCode, Message = "Internal Server Error. An unexpected error occurred." }.ToString()); // Using a custom ErrorDetails class } }); }); } // ...
-
Exception Filters: An exception filter runs only for exceptions that occur during the MVC action pipeline (e.g., in controller creation, model binding, or the action method itself). It won't catch exceptions from middleware. It's useful for handling specific exceptions differently based on the MVC context.
Answer:
CORS (Cross-Origin Resource Sharing) is a browser security mechanism that restricts a web page from making requests to a different domain than the one that served the page. To allow a browser-based client (like a React or Angular app on http://localhost:3000
) to call your API (on http://localhost:5000
), you must explicitly enable CORS on the server.
Configuration in Program.cs
:
var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
var builder = WebApplication.CreateBuilder(args);
// 1. Add CORS services
builder.Services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("http://example.com", "http://www.contoso.com")
.WithMethods("GET", "POST", "PUT") // Specify allowed methods
.WithHeaders("Content-Type", "Authorization"); // Specify allowed headers
});
});
var app = builder.Build();
// ...
// 2. Use the CORS middleware (must be placed before UseAuthorization and MapControllers)
app.UseCors(MyAllowSpecificOrigins);
app.UseAuthorization();
app.MapControllers();
// ...
14. Explain Minimal APIs. What are their pros and cons compared to traditional controller-based APIs?
Answer: Minimal APIs, introduced in .NET 6, provide a streamlined way to build HTTP APIs with minimal code and dependencies. They don't use the traditional controller structure.
Example Minimal API:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/hello", () => "Hello, World!");
app.MapPost("/users", (User user) => {
// Logic to create a user
return Results.Created($"/users/{user.Id}", user);
});
app.Run();
Pros:
- Less Boilerplate: Radically reduces the amount of code needed for simple endpoints.
- Performance: Can be slightly faster as it bypasses parts of the MVC pipeline not needed for simple APIs.
- Clarity for Microservices: Excellent for small, focused microservices where the overhead of controllers is unnecessary.
- Easy to Learn: Lower barrier to entry for developers new to .NET.
Cons:
- Less Structured: For large, complex APIs, the lack of a controller structure can lead to disorganized code ("spaghetti code") if not managed carefully.
- Limited Filter Support (in early versions): While improved, advanced filter-based logic and conventions are more mature in the controller-based approach.
- Less "Opinionated": The controller-based approach provides a clear, conventional structure for organizing code, which can be beneficial for large teams and projects.
Answer: Caching is a key strategy for improving performance by storing and reusing frequently accessed data. ASP.NET Core supports several caching mechanisms:
-
In-Memory Caching (
IMemoryCache
):- What it is: Caches data in the web server's memory. It's the simplest form of caching.
- Pros: Extremely fast.
- Cons: Cache is lost if the app restarts. Not shared across multiple server instances (not suitable for a load-balanced farm).
-
Implementation:
// Register in Program.cs builder.Services.AddMemoryCache(); // Use in a service/controller public class MyService(IMemoryCache cache) { public async Task<MyData> GetDataAsync(string key) { return await cache.GetOrCreateAsync(key, entry => { entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(5); return FetchDataFromDatabase(); }); } }
-
Distributed Caching (
IDistributedCache
):- What it is: An external cache that is shared by multiple app servers. Common providers include Redis and SQL Server.
- Pros: Cache persists through app restarts and is shared across a server farm.
- Cons: Slower than in-memory cache due to network latency. Requires setup and maintenance of an external service.
-
Implementation:
// Register in Program.cs (example for Redis) builder.Services.AddStackExchangeRedisCache(options => { options.Configuration = builder.Configuration.GetConnectionString("Redis"); options.InstanceName = "MyApi_"; }); // Usage is similar to IMemoryCache, but it stores byte[] or strings. // You often need to serialize/deserialize your objects.