If you’re preparing for a .NET developer interview, these are five fundamental ASP.NET Core questions that appear regularly. Here’s a breakdown with added depth, like you’d expect in a real-world selection process.
How does Routing work in ASP.NET Core?
Routing in ASP.NET Core is handled by the Endpoint Routing system, introduced in ASP.NET Core 3.0 and now the standard. Routing maps incoming HTTP requests to executable endpoints in your app: typically controller actions, Razor Pages, or Minimal API delegates.
Pipeline Configuration
Routing is configured in Program.cs
using:
1
2
3
4
5
6
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
Here’s what happens:
UseRouting()
discovers route definitions.UseAuthorization()
and other middleware can act on matched routes.UseEndpoints()
finalizes and executes the match.
Route Types
- Attribute Routing:
[HttpGet("api/products/{id}")]
- Convention-based Routing:
endpoints.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}");
Routing Constraints and Attributes
You can add constraints and annotations for more control:
- Route constraints:
[HttpGet("api/user/{id:int:min(1)}")]
- String-only required segments:
[HttpGet("api/user/{id:string:required}")]
- Use
[FromBody]
,[FromQuery]
,[FromRoute]
to explicitly bind parameters - Nullable checks:
[FromBody, NotNull] User user
Example:
1
2
[HttpPost("api/user/{id:guid}")]
public IActionResult CreateUser([FromRoute] Guid id, [FromBody, NotNull] CreateUserRequest body)
This ensures:
id
must be aGuid
body
must be present in request and notnull
If you have more time, investigate further at Microsoft Learn!
Routing Order
- Minimal APIs and endpoints are matched in order of registration.
- Attribute routes override conventional ones.
What is Middleware and in what order do they execute?
Middleware is software assembled into an application pipeline to handle requests and responses. Think of it as a chain of delegates. Each middleware component can:
- Process request
- Pass the request to the next component via
await next()
- Process the response after next middleware completes
Middleware can also be custom-built to handle specific needs, like logging, request throttling, or custom authentication. But beware: don’t rewrite the wheel or overengineer your pipeline. The more middleware you have, the harder it is to maintain and debug. Aim for simplicity: the fewer middleware components, the better.
Execution Order
They execute in the order registered in Program.cs
. For example:
1
2
3
4
app.UseRouting(); // 1
app.UseAuthentication(); // 2
app.UseAuthorization(); // 3
app.UseEndpoints(); // 4
Custom Middleware
Custom middleware can be created as a class or inline using:
1
2
3
4
5
6
app.Use(async (context, next) =>
{
// Before next middleware
await next();
// After next middleware
});
How can you stop other middlewares from executing?
You can stop the pipeline by not calling await next()
. Example:
1
2
3
4
5
6
7
8
9
10
app.Use(async (context, next) =>
{
if (!context.User.Identity.IsAuthenticated)
{
context.Response.StatusCode = 401;
await context.Response.WriteAsync("Unauthorized");
return; // Prevent further middleware
}
await next();
});
Once you short-circuit, subsequent middleware (and endpoint handlers) won’t run.
This is common for:
- Authentication/authorization failures
- Maintenance mode
- Early return with cached response
What is the difference between MVC and Razor Pages?
Both are built on the same infrastructure, but they differ in structure and use case.
Feature | MVC | Razor Pages |
---|---|---|
Structure | Controller + View + Model | View + PageModel in one |
Suited for | Large, complex apps | CRUD, page-focused apps |
Routing | Convention/Attribute | Folder/File-based |
Testability | More granular | Page-focused integration |
Separation | Logic and view are split | Logic/view are together |
What is Razor Pages?
Razor Pages is a newer feature introduced in ASP.NET Core 2.0. Instead of separating controller logic from views like MVC does, Razor Pages keeps them together. Each page has a .cshtml
view and an associated .cshtml.cs
PageModel file. This model simplifies development for page-centric apps like admin dashboards, CRUD pages, or forms.
Side-by-side Code Example
MVC
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// Controller
public class ProductsController : Controller
{
public IActionResult Details(int id)
{
var product = productService.GetById(id);
return View(product);
}
[HttpPost]
public IActionResult Add([FromForm] Product product)
{
productService.Add(product);
return RedirectToAction("Details", new { id = product.Id });
}
}
// View: Views/Products/Details.cshtml
@model Product
<h2>@Model.Name</h2>
<form method="post" asp-action="Add">
<input asp-for="Name" />
<input asp-for="Price" />
<button type="submit">Add</button>
</form>
Razor Pages
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// Pages/Products/Details.cshtml.cs
public class DetailsModel : PageModel
{
private readonly IProductService productService;
public Product Product { get; private set; }
[BindProperty]
public Product NewProduct { get; set; }
public DetailsModel(IProductService productService) => this.productService = productService;
public void OnGet(int id)
{
Product = productService.GetById(id);
}
public IActionResult OnPost()
{
if (!ModelState.IsValid) return Page();
productService.Add(NewProduct);
return RedirectToPage("./Details", new { id = NewProduct.Id });
}
}
// Pages/Products/Details.cshtml
@page "{id}"
@model DetailsModel
<h2>@Model.Product.Name</h2>
<form method="post">
<input asp-for="NewProduct.Name" />
<input asp-for="NewProduct.Price" />
<button type="submit">Add</button>
</form>
When to use each?
Use Razor Pages if:
- Your app is primarily made of pages, not APIs
- You want a simpler, organized structure with logic close to the view
- You’re building internal tools or admin panels
Use MVC if:
- You need full control over routing and separation of concerns
- Your app has a complex domain layer
- You’re building an API-first or service-oriented system
Name 3 ways to create Middleware
- Inline Middleware:
1
app.Use(async (context, next) => { await next(); });
- Middleware Class with Invoke:
1
2
3
4
5
6
7
8
9
10
public class LoggingMiddleware
{
private readonly RequestDelegate _next;
public LoggingMiddleware(RequestDelegate next) => _next = next;
public async Task Invoke(HttpContext context)
{
Console.WriteLine("Request: " + context.Request.Path);
await _next(context);
}
}
And register with:
1
app.UseMiddleware<LoggingMiddleware>();
- IMiddleware + DI:
More testable, services are injected via constructor.
1
2
3
4
public class AuthMiddleware : IMiddleware
{
public async Task InvokeAsync(HttpContext context, RequestDelegate next) { ... }
}
Register:
1
2
services.AddTransient<AuthMiddleware>();
app.UseMiddleware<AuthMiddleware>();
✅ Tip: Understand not just “how” middleware works, but also “why” the order matters: it can define the security, performance, and behavior of your app.
In the next posts I’ll be adding more and more posts about interviewing questions and stuff related to that, so keep posted.