đŒ Questions d'Entretien Technique - ASP.NET Core
đ Organisationâ
Ce document contient 50+ questions techniques organisées par niveau de difficulté pour préparer vos entretiens techniques et missions consultant ASP.NET Core.
Niveaux de difficultĂ©â
- âȘ NĂCESSAIRE - Concepts essentiels, attendus de tout dĂ©veloppeur ASP.NET
- đą BASIQUE - Fondamentaux ASP.NET Core
- đĄ INTERMĂDIAIRE - Concepts avancĂ©s et patterns courants
- đŽ AVANCĂ - Optimisations, architecture, problĂšmes complexes
âȘ NĂCESSAIRE (Concepts essentiels)â
Q1. Qu'est-ce qu'ASP.NET Core et en quoi diffĂšre-t-il d'ASP.NET Framework ?â
Réponse attendue :
ASP.NET Core est un framework web open-source et cross-platform pour construire des applications web modernes.
Différences clés avec ASP.NET Framework :
| Aspect | ASP.NET Core | ASP.NET Framework |
|---|---|---|
| Plateforme | Cross-platform (Windows, Linux, macOS) | Windows uniquement |
| Open Source | Oui (MIT License) | Partiellement |
| Performance | TrÚs performant (optimisé) | Moins performant |
| Déploiement | Self-contained ou framework-dependent | Framework-dependent uniquement |
| Modularité | Packages NuGet modulaires | Monolithique |
| Hébergement | Kestrel, IIS, Nginx, Apache, Docker | IIS principalement |
Q2. Qu'est-ce que le pattern MVC et comment fonctionne-t-il dans ASP.NET Core ?â
Réponse attendue :
MVC = Model-View-Controller, un pattern architectural qui sépare l'application en 3 composants :
1. Model (ModÚle) : Représente les données et la logique métier
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
2. View (Vue) : Interface utilisateur (fichiers .cshtml avec Razor)
@model Product
<h1>@Model.Name</h1>
<p>Prix : @Model.Price âŹ</p>
3. Controller (ContrĂŽleur) : GĂšre les requĂȘtes, coordonne Model et View
public class ProductController : Controller
{
public IActionResult Index()
{
var products = GetProducts(); // Logique métier
return View(products); // Retourne la vue avec les données
}
}
Flux : RequĂȘte â Routing â Controller â Model â View â RĂ©ponse
Q3. Qu'est-ce que le Dependency Injection (DI) dans ASP.NET Core ?â
Réponse attendue :
Dependency Injection est un pattern permettant d'injecter les dépendances d'une classe plutÎt que de les créer manuellement. ASP.NET Core a un DI container intégré.
Exemple :
// Interface
public interface IProductService
{
List<Product> GetAll();
}
// Implémentation
public class ProductService : IProductService
{
public List<Product> GetAll() => new List<Product>();
}
// Enregistrement dans Program.cs
builder.Services.AddScoped<IProductService, ProductService>();
// Injection dans un contrĂŽleur
public class ProductController : Controller
{
private readonly IProductService _productService;
public ProductController(IProductService productService) // Injection
{
_productService = productService;
}
}
Avantages : Testabilité, découplage, maintenance facilitée
Q4. Quelle est la diffĂ©rence entre AddScoped, AddTransient et AddSingleton ?â
Réponse attendue :
Durée de vie des services injectés :
| Lifetime | Durée de vie | Usage typique |
|---|---|---|
| Transient | Nouvelle instance à chaque injection | Services légers, stateless |
| Scoped | Nouvelle instance par requĂȘte HTTP | DbContext, services liĂ©s Ă une requĂȘte |
| Singleton | Instance unique pour toute l'application | Configuration, cache, services coûteux |
Exemple :
// Transient - nouvelle instance Ă chaque fois
builder.Services.AddTransient<IEmailService, EmailService>();
// Scoped - une instance par requĂȘte HTTP
builder.Services.AddScoped<IOrderService, OrderService>();
builder.Services.AddDbContext<AppDbContext>(); // Scoped par défaut
// Singleton - instance unique
builder.Services.AddSingleton<ICacheService, MemoryCacheService>();
â ïž Attention : Ne jamais injecter un Scoped service dans un Singleton (problĂšme de captive dependency)
Q5. Qu'est-ce que le Middleware dans ASP.NET Core ?â
Réponse attendue :
Middleware = composants qui forment un pipeline pour traiter les requĂȘtes/rĂ©ponses HTTP.
Pipeline :
RequĂȘte â Middleware 1 â Middleware 2 â ... â Endpoint â ... â Middleware 2 â Middleware 1 â RĂ©ponse
Exemple de configuration :
var app = builder.Build();
// Ordre important !
app.UseHttpsRedirection(); // 1. Redirection HTTPS
app.UseStaticFiles(); // 2. Fichiers statiques
app.UseRouting(); // 3. Routing
app.UseAuthentication(); // 4. Authentification
app.UseAuthorization(); // 5. Autorisation
app.MapControllers(); // 6. Endpoints
app.Run();
Middleware personnalisé :
app.Use(async (context, next) =>
{
// Code avant l'appel suivant
await next(); // Appelle le middleware suivant
// Code aprĂšs l'appel suivant
});
Usages : Logging, authentification, gestion d'erreurs, compression, CORS
Q6. Qu'est-ce que Routing dans ASP.NET Core ?â
Réponse attendue :
Routing = systĂšme qui associe les URLs aux endpoints (contrĂŽleurs/actions).
Convention-based routing (MVC) :
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
// URL: /Products/Details/5
// Controller: ProductsController
// Action: Details(int id)
Attribute routing (recommandé) :
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
[HttpGet] // GET /api/products
public IActionResult GetAll() { }
[HttpGet("{id}")] // GET /api/products/5
public IActionResult Get(int id) { }
[HttpPost] // POST /api/products
public IActionResult Create([FromBody] Product product) { }
}
đą BASIQUE (Fondamentaux)â
Q7. Quelle est la diffĂ©rence entre ViewData, ViewBag et TempData ?â
Réponse attendue :
Mécanismes pour passer des données du contrÎleur à la vue :
| Type | Description | Durée de vie | Type |
|---|---|---|---|
| ViewData | Dictionnaire clĂ©-valeur | RequĂȘte actuelle uniquement | ViewDataDictionary (cast requis) |
| ViewBag | PropriĂ©tĂ© dynamique | RequĂȘte actuelle uniquement | dynamic (pas de cast) |
| TempData | Stockage temporaire | Jusqu'Ă lecture (1 redirect) | ITempDataDictionary |
Exemple :
// Controller
public IActionResult Index()
{
ViewData["Message"] = "Hello"; // Dictionary
ViewBag.Count = 10; // Dynamic
TempData["Success"] = "Sauvegardé !"; // Persiste aprÚs redirect
return View();
}
// View
<p>@ViewData["Message"]</p> <!-- Besoin du cast si complex type -->
<p>@ViewBag.Count</p> <!-- Pas de cast -->
<p>@TempData["Success"]</p> <!-- Disponible aprĂšs redirect -->
Usage TempData : Messages de succĂšs/erreur aprĂšs un RedirectToAction
Q8. Qu'est-ce qu'un ActionResult et quels sont les types courants ?â
Réponse attendue :
ActionResult = type de retour d'une action de contrÎleur représentant le résultat HTTP.
Types courants :
// 1. ViewResult - Retourne une vue Razor
public IActionResult Index()
{
return View(); // ou View("ViewName", model)
}
// 2. JsonResult - Retourne du JSON
public IActionResult GetData()
{
return Json(new { Name = "John", Age = 30 });
}
// 3. RedirectToActionResult - Redirige vers une autre action
public IActionResult Create()
{
return RedirectToAction("Index");
}
// 4. ContentResult - Retourne du texte brut
public IActionResult Text()
{
return Content("Hello World");
}
// 5. StatusCodeResult - Retourne un code HTTP
public IActionResult NotFound()
{
return NotFound(); // 404
// Ou : StatusCode(404)
}
// 6. FileResult - Retourne un fichier
public IActionResult Download()
{
return File(bytes, "application/pdf", "document.pdf");
}
API Controllers : Utiliser ActionResult<T> pour typage fort
public ActionResult<Product> Get(int id)
{
var product = _service.Find(id);
if (product == null) return NotFound();
return product; // Conversion implicite
}
Q9. Comment fonctionne la validation de modĂšles (Model Validation) ?â
Réponse attendue :
Model Validation = validation automatique des données avec des Data Annotations.
Attributs courants :
public class Product
{
[Required(ErrorMessage = "Le nom est requis")]
[StringLength(100, MinimumLength = 3)]
public string Name { get; set; }
[Range(0.01, 10000, ErrorMessage = "Prix entre 0.01 et 10000")]
public decimal Price { get; set; }
[EmailAddress]
public string Email { get; set; }
[RegularExpression(@"^\d{5}$", ErrorMessage = "Code postal invalide")]
public string ZipCode { get; set; }
}
Validation dans le contrĂŽleur :
[HttpPost]
public IActionResult Create([FromBody] Product product)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState); // Retourne les erreurs
}
// Logique si valide
_service.Add(product);
return Ok(product);
}
Dans les vues (MVC) :
@model Product
<form asp-action="Create">
<div>
<label asp-for="Name"></label>
<input asp-for="Name" />
<span asp-validation-for="Name"></span> <!-- Affiche l'erreur -->
</div>
<button type="submit">Envoyer</button>
</form>
@section Scripts {
<partial name="_ValidationScriptsPartial" />
}
Q10. Qu'est-ce que les Minimal APIs dans .NET 6+ ?â
Réponse attendue :
Minimal APIs = approche simplifiée pour créer des APIs sans contrÎleurs, introduite dans .NET 6.
Exemple :
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
// Définition directe des endpoints
app.MapGet("/", () => "Hello World!");
app.MapGet("/products", () => new[]
{
new { Id = 1, Name = "Product 1" },
new { Id = 2, Name = "Product 2" }
});
app.MapGet("/products/{id}", (int id) =>
new { Id = id, Name = $"Product {id}" });
app.MapPost("/products", (Product product) =>
{
// Logique de création
return Results.Created($"/products/{product.Id}", product);
});
app.Run();
Avantages :
- Moins de boilerplate
- Performance légÚrement meilleure
- Parfait pour microservices et APIs simples
Quand utiliser :
- â APIs simples, microservices
- â Applications complexes avec beaucoup de logique (prĂ©fĂ©rer MVC)
Q11. Comment gĂ©rer les erreurs globalement dans ASP.NET Core ?â
Réponse attendue :
3 approches principales :
1. Middleware d'exception (Development) :
if (app.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage(); // Page détaillée
}
else
{
app.UseExceptionHandler("/Error"); // Page custom
app.UseHsts();
}
2. Middleware personnalisé :
app.Use(async (context, next) =>
{
try
{
await next();
}
catch (Exception ex)
{
context.Response.StatusCode = 500;
await context.Response.WriteAsJsonAsync(new
{
Error = "Une erreur est survenue",
Message = ex.Message
});
}
});
3. Exception Filter (API Controllers) :
public class GlobalExceptionFilter : IExceptionFilter
{
public void OnException(ExceptionContext context)
{
var result = new ObjectResult(new
{
Error = context.Exception.Message
})
{
StatusCode = 500
};
context.Result = result;
context.ExceptionHandled = true;
}
}
// Enregistrement
builder.Services.AddControllers(options =>
{
options.Filters.Add<GlobalExceptionFilter>();
});
Q12. Qu'est-ce que Entity Framework Core et comment l'utiliser avec ASP.NET Core ?â
Réponse attendue :
EF Core = ORM (Object-Relational Mapper) pour .NET permettant de manipuler des bases de données avec du code C#.
Configuration :
// 1. Installation
// dotnet add package Microsoft.EntityFrameworkCore.SqlServer
// 2. DbContext
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options)
: base(options) { }
public DbSet<Product> Products { get; set; }
}
// 3. Enregistrement dans Program.cs
builder.Services.AddDbContext<AppDbContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
// 4. Création d'un service (bonne pratique)
public interface IProductService
{
Task<List<Product>> GetAllProductsAsync();
Task<Product> GetProductByIdAsync(int id);
}
public class ProductService : IProductService
{
private readonly AppDbContext _context;
public ProductService(AppDbContext context)
{
_context = context;
}
public async Task<List<Product>> GetAllProductsAsync()
{
return await _context.Products.ToListAsync();
}
public async Task<Product> GetProductByIdAsync(int id)
{
return await _context.Products.FindAsync(id);
}
}
// 5. Enregistrement du service
builder.Services.AddScoped<IProductService, ProductService>();
// 6. Injection dans le contrĂŽleur (bonne pratique)
public class ProductsController : Controller
{
private readonly IProductService _productService;
public ProductsController(IProductService productService)
{
_productService = productService; // â
Injecter un service, pas le DbContext
}
public async Task<IActionResult> Index()
{
var products = await _productService.GetAllProductsAsync();
return View(products);
}
}
â ïž Important : Ne jamais injecter DbContext directement dans un contrĂŽleur. Utilisez toujours une couche service/repository pour :
- Respecter la séparation des responsabilités (SRP)
- Faciliter les tests unitaires (mock du service)
- Centraliser la logique d'accÚs aux données
Migrations :
dotnet ef migrations add InitialCreate
dotnet ef database update
đĄ INTERMĂDIAIRE (Concepts avancĂ©s)â
Q13. Expliquez le cycle de vie d'une requĂȘte ASP.NET Core (Request Pipeline).â
Réponse attendue :
Pipeline de requĂȘte :
1. RequĂȘte HTTP arrive sur Kestrel (serveur web)
â
2. Passe par les Middlewares (dans l'ordre défini)
- UseHttpsRedirection
- UseStaticFiles
- UseRouting
- UseAuthentication
- UseAuthorization
â
3. Routing identifie l'endpoint (contrĂŽleur/action)
â
4. Model Binding dĂ©sĂ©rialise les donnĂ©es de la requĂȘte
â
5. Model Validation valide les données
â
6. Filters s'exĂ©cutent (Authorization â Action â Result)
â
7. Action du contrÎleur s'exécute
â
8. ActionResult est retourné
â
9. Filters post-exĂ©cution (Result â Exception)
â
10. Réponse passe par les Middlewares (ordre inverse)
â
11. Réponse HTTP retournée au client
Schéma détaillé :
app.Use(async (context, next) => // Middleware 1 - début
{
Console.WriteLine("Avant Middleware 2");
await next(); // Passe au suivant
Console.WriteLine("AprĂšs Middleware 2");
});
app.Use(async (context, next) => // Middleware 2 - début
{
Console.WriteLine("Avant Endpoint");
await next(); // Passe Ă l'endpoint
Console.WriteLine("AprĂšs Endpoint");
});
app.MapGet("/", () => "Hello"); // Endpoint
// Output:
// Avant Middleware 2
// Avant Endpoint
// [Endpoint exécuté]
// AprĂšs Endpoint
// AprĂšs Middleware 2
Q14. Qu'est-ce que les Filters dans ASP.NET Core MVC et quels sont les types ?â
Réponse attendue :
Filters = attributs exécutés à différentes étapes du pipeline MVC.
Types de filters (ordre d'exécution) :
- Authorization Filters - Vérifient l'autorisation
- Resource Filters - Avant model binding
- Action Filters - Avant/aprÚs l'exécution de l'action
- Exception Filters - GĂšrent les exceptions
- Result Filters - Avant/aprÚs l'exécution du résultat
Exemple - Action Filter :
public class LogActionFilter : IActionFilter
{
public void OnActionExecuting(ActionExecutingContext context)
{
Console.WriteLine($"Avant: {context.ActionDescriptor.DisplayName}");
}
public void OnActionExecuted(ActionExecutedContext context)
{
Console.WriteLine($"AprĂšs: {context.ActionDescriptor.DisplayName}");
}
}
// Utilisation
[LogActionFilter]
public IActionResult Index()
{
return View();
}
// Ou global
builder.Services.AddControllers(options =>
{
options.Filters.Add<LogActionFilter>();
});
Filters intégrés courants :
[Authorize]- Authorization Filter[ValidateAntiForgeryToken]- Action Filter[ResponseCache]- Result Filter
Q15. Comment implĂ©menter l'authentification JWT dans ASP.NET Core ?â
Réponse attendue :
JWT (JSON Web Token) = standard pour sécuriser les APIs stateless.
Configuration :
// 1. Installation
// dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer
// 2. Configuration dans Program.cs
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = "your-issuer",
ValidAudience = "your-audience",
IssuerSigningKey = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes("your-secret-key-min-32-chars"))
};
});
// 3. Activation
app.UseAuthentication();
app.UseAuthorization();
// 4. Génération du token
public string GenerateToken(User user)
{
var claims = new[]
{
new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
new Claim(ClaimTypes.Name, user.Username),
new Claim(ClaimTypes.Role, "Admin")
};
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("secret-key"));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(
issuer: "your-issuer",
audience: "your-audience",
claims: claims,
expires: DateTime.Now.AddHours(1),
signingCredentials: creds);
return new JwtSecurityTokenHandler().WriteToken(token);
}
// 5. Protection des endpoints
[Authorize] // Nécessite un token valide
public IActionResult SecureEndpoint()
{
var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
return Ok($"User ID: {userId}");
}
[Authorize(Roles = "Admin")] // Nécessite role Admin
public IActionResult AdminOnly()
{
return Ok("Admin access");
}
Q16. Qu'est-ce que CORS et comment le configurer dans ASP.NET Core ?â
Réponse attendue :
CORS (Cross-Origin Resource Sharing) = mécanisme permettant à une application web d'accéder à des ressources d'un domaine différent.
ProblĂšme : Par dĂ©faut, les navigateurs bloquent les requĂȘtes cross-origin pour sĂ©curitĂ©.
Configuration :
// 1. Configuration dans Program.cs
builder.Services.AddCors(options =>
{
// Policy permissive (développement)
options.AddPolicy("AllowAll", policy =>
{
policy.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
});
// Policy restrictive (production)
options.AddPolicy("AllowSpecific", policy =>
{
policy.WithOrigins("https://example.com", "https://app.example.com")
.WithMethods("GET", "POST")
.WithHeaders("Content-Type", "Authorization")
.AllowCredentials(); // Cookies/Auth headers
});
});
// 2. Activation globale
app.UseCors("AllowSpecific"); // Avant UseAuthorization
// 3. Ou par endpoint
app.MapGet("/api/data", () => "Data")
.RequireCors("AllowAll");
// 4. Ou par contrĂŽleur
[EnableCors("AllowSpecific")]
public class ProductsController : ControllerBase { }
â ïž SĂ©curitĂ© : Ne jamais utiliser AllowAnyOrigin() en production
Q17. Comment implĂ©menter le caching dans ASP.NET Core ?â
Réponse attendue :
3 types de caching :
1. Response Caching (HTTP Cache) :
// Configuration
builder.Services.AddResponseCaching();
app.UseResponseCaching();
// Utilisation
[ResponseCache(Duration = 60)] // Cache 60 secondes
public IActionResult Index()
{
return View();
}
2. In-Memory Caching :
// Configuration
builder.Services.AddMemoryCache();
// Utilisation
public class ProductService
{
private readonly IMemoryCache _cache;
public ProductService(IMemoryCache cache)
{
_cache = cache;
}
public async Task<Product> GetProduct(int id)
{
return await _cache.GetOrCreateAsync($"product_{id}", async entry =>
{
entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(10);
return await _repository.GetByIdAsync(id);
});
}
}
3. Distributed Cache (Redis) :
// Configuration
builder.Services.AddStackExchangeRedisCache(options =>
{
options.Configuration = "localhost:6379";
});
// Utilisation
public class CacheService
{
private readonly IDistributedCache _cache;
public async Task<string> GetOrSetAsync(string key, Func<Task<string>> factory)
{
var cached = await _cache.GetStringAsync(key);
if (cached != null) return cached;
var value = await factory();
await _cache.SetStringAsync(key, value, new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1)
});
return value;
}
}
Q18. Qu'est-ce que Blazor et quelles sont les diffĂ©rences entre Blazor Server et Blazor WebAssembly ?â
Réponse attendue :
Blazor = framework pour construire des applications web interactives avec C# au lieu de JavaScript.
Comparaison :
| Aspect | Blazor Server | Blazor WebAssembly |
|---|---|---|
| Exécution | CÎté serveur (SignalR) | CÎté client (navigateur) |
| Latence | Dépend du réseau | Locale (rapide) |
| Taille téléchargement | Petite (HTML/CSS) | Grande (~2-3 MB .NET runtime) |
| Offline | â NĂ©cessite connexion | â Fonctionne offline (PWA) |
| DĂ©bogage | â Facile | Plus complexe |
| ScalabilitĂ© | Limite (connexions SignalR) | â Excellente (client-side) |
| Sécurité | Code cÎté serveur (sécurisé) | Code téléchargé (visible) |
Exemple Blazor Server :
// Counter.razor
@page "/counter"
<h1>Counter</h1>
<p>Current count: @currentCount</p>
<button @onclick="IncrementCount">Click me</button>
@code {
private int currentCount = 0;
private void IncrementCount()
{
currentCount++; // Exécuté sur le serveur
}
}
Quand utiliser :
- Blazor Server : Applications internes, dashboards, faible latence réseau
- Blazor WASM : Applications publiques, PWA, offline-first
đ Ressources complĂ©mentairesâ
- Documentation officielle ASP.NET Core
- .NET 9 What's New
- ASP.NET Core Performance Best Practices
- Blazor Documentation
- .NET Aspire Documentation
Bon courage pour vos entretiens ! đȘ