Top ASP.NET Core Interview Questions

ASP.NET CoreMediator PatternDesign Patterns
The Mediator pattern reduces direct dependencies between components, promoting loose coupling. Use it in ASP.NET Core for CQRS, where commands and queries are handled by mediators (e.g., MediatR). It simplifies complex interactions, improves testability, and centralizes request handling.
Example:
public class GetProductQuery : IRequest { public int Id { get; set; } }

public class GetProductHandler : IRequestHandler
{
    public async Task Handle(GetProductQuery request, CancellationToken cancellationToken)
    {
        return new ProductDto { Id = request.Id, Name = "Test" };
    }
}

// Controller
public class ProductsController : ControllerBase
{
    private readonly IMediator _mediator;
    public ProductsController(IMediator mediator) => _mediator = mediator;

    [HttpGet("{id}")]
    public async Task Get(int id) => Ok(await _mediator.Send(new GetProductQuery { Id = id }));
}

ASP.NET CoreAPI DesignScalabilityEnterprise
Design a scalable ASP.NET Core API using Clean Architecture, microservices, and Domain-Driven Design. Use EF Core with repository patterns, implement CQRS for separation of concerns, and leverage dependency injection for loose coupling. Ensure scalability with load balancing, caching (e.g., Redis), and async operations. Maintainability is achieved through modular code, comprehensive logging, and automated tests.
Example:
public class Program
{
    public static void Main(string[] args)
    {
        var builder = WebApplication.CreateBuilder(args);
        builder.Services.AddControllers();
        builder.Services.AddDbContext();
        builder.Services.AddScoped();
        var app = builder.Build();
        app.UseRouting();
        app.MapControllers();
        app.Run();
    }
}

ASP.NET CoreCross-Cutting ConcernsLoggingCachingValidation
Manage cross-cutting concerns using middleware for global concerns, filters for MVC-specific logic, and decorators or interceptors for services. Use ILogger for logging, IMemoryCache or Redis for caching, and data annotations or FluentValidation for validation.
Example:
public class MyService
{
    private readonly IMemoryCache _cache;
    private readonly ILogger _logger;
    public MyService(IMemoryCache cache, ILogger logger)
    {
        _cache = cache;
        _logger = logger;
    }

    public string GetData(string key)
    {
        if (!_cache.TryGetValue(key, out string value))
        {
            _logger.LogInformation("Cache miss for {Key}", key);
            value = "Data";
            _cache.Set(key, value, TimeSpan.FromMinutes(10));
        }
        return value;
    }
}

ASP.NET CoreRepository PatternUnit of WorkEF Core
The Repository pattern abstracts data access, while Unit of Work manages transactions. Implement repositories for each entity and a Unit of Work to coordinate multiple repositories, using EF Core’s DbContext as the Unit of Work.
Example:
public interface IRepository { Task> GetAllAsync(); }
public class Repository : IRepository where T : class
{
    private readonly MyDbContext _context;
    public Repository(MyDbContext context) => _context = context;
    public async Task> GetAllAsync() => await _context.Set().ToListAsync();
}

public interface IUnitOfWork
{
    IRepository Products { get; }
    Task SaveChangesAsync();
}

public class UnitOfWork : IUnitOfWork
{
    private readonly MyDbContext _context;
    public IRepository Products { get; }
    public UnitOfWork(MyDbContext context)
    {
        _context = context;
        Products = new Repository(context);
    }
    public async Task SaveChangesAsync() => await _context.SaveChangesAsync();
}

ASP.NET CoreClean ArchitectureOnion Architecture
Clean Architecture organizes code into layers: Domain (core entities), Application (business logic), Infrastructure (data access, external services), and Presentation (API/UI). In an ASP.NET Core project, the Domain layer defines entities, the Application layer contains use cases and interfaces, Infrastructure implements repositories with EF Core, and Presentation exposes APIs. Dependency injection wires layers, ensuring loose coupling.
Example:
// Application Layer
public interface IProductService
{
    Task> GetAllAsync();
}

// Infrastructure Layer
public class ProductRepository : IProductRepository
{
    private readonly MyDbContext _context;
    public ProductRepository(MyDbContext context) => _context = context;
    public async Task> GetAllAsync() => await _context.Products.ToListAsync();
}

ASP.NET CoreCQRSArchitecture
CQRS separates read (queries) and write (commands) operations, improving scalability and maintainability. Implement using MediatR to dispatch commands and queries to separate handlers, with distinct models for reads and writes.
Example:
public class CreateProductCommand : IRequest { public string Name { get; set; } }
public class CreateProductHandler : IRequestHandler
{
    private readonly MyDbContext _context;
    public CreateProductHandler(MyDbContext context) => _context = context;
    public async Task Handle(CreateProductCommand request, CancellationToken cancellationToken)
    {
        var product = new Product { Name = request.Name };
        _context.Products.Add(product);
        await _context.SaveChangesAsync();
        return product.Id;
    }
}

ASP.NET CoreStrategy PatternDesign Patterns
The Strategy pattern defines interchangeable algorithms. In ASP.NET Core, use it for dynamic behavior, like payment processing with different providers (e.g., PayPal, Stripe).
Example:
public interface IPaymentStrategy
{
    Task ProcessPayment(decimal amount);
}

public class PayPalStrategy : IPaymentStrategy
{
    public async Task ProcessPayment(decimal amount) => await Task.CompletedTask; // PayPal logic
}

public class PaymentService
{
    private readonly IPaymentStrategy _strategy;
    public PaymentService(IPaymentStrategy strategy) => _strategy = strategy;
    public async Task Process(decimal amount) => await _strategy.ProcessPayment(amount);
}

public void ConfigureServices(IServiceCollection services)
{
    services.AddScoped();
}

ASP.NET CoreProject StructureMulti-Project Solution
Structure a multi-project solution with separate projects for Domain, Application, Infrastructure, and Presentation. Use Clean Architecture, maintain clear boundaries, and reference projects unidirectionally (e.g., Presentation -> Application -> Domain). Include test projects for unit and integration tests.

ASP.NET CoreDependency CyclesScalability
Resolve dependency cycles by refactoring to use interfaces, dependency inversion, or mediator patterns. Break cycles by introducing abstractions or redesigning service responsibilities.
Example:
public interface IServiceA { void DoWork(); }
public interface IServiceB { void DoWork(); }

public class ServiceA : IServiceA
{
    private readonly IServiceB _serviceB;
    public ServiceA(IServiceB serviceB) => _serviceB = serviceB;
    public void DoWork() => _serviceB.DoWork();
}

ASP.NET CoreEF CorePerformance TuningQuery Optimization
Optimize EF Core queries by using `AsNoTracking`, selecting only needed columns, avoiding N+1 queries with `Include`, and using raw SQL for complex queries. Profile with tools like SQL Server Profiler.
Example:
public async Task> GetProductsAsync()
{
    return await _context.Products
        .AsNoTracking()
        .Select(p => new ProductDto { Id = p.Id, Name = p.Name })
        .ToListAsync();
}

ASP.NET CoreGeneric RepositoryEF CoreDrawbacks
Generic repositories can lead to bloated interfaces and hide EF Core’s capabilities (e.g., query optimization). Improve by using specific repositories tailored to entities, exposing only needed methods, and leveraging EF Core’s queryable features directly.
Example:
public interface IProductRepository
{
    Task GetByIdAsync(int id);
}

public class ProductRepository : IProductRepository
{
    private readonly MyDbContext _context;
    public ProductRepository(MyDbContext context) => _context = context;
    public async Task GetByIdAsync(int id) => await _context.Products.FindAsync(id);
}

ASP.NET CoreAsNoTrackingTracking QueriesEF Core
AsNoTracking disables change tracking, improving performance for read-only queries. Tracking queries enable change tracking for updates. Use `AsNoTracking` for reads, tracking for updates.
Example:
var products = await _context.Products.AsNoTracking().ToListAsync(); // Read-only
var product = await _context.Products.FirstOrDefaultAsync(p => p.Id == 1); // Update

ASP.NET CoreShadow PropertiesValue ConversionsEF Core
Shadow properties are database columns not defined in the entity class, configured in `OnModelCreating`. Value conversions map CLR types to database types (e.g., enums to strings).
Example:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity().Property("LastUpdated");
    modelBuilder.Entity().Property("Status")
        .HasConversion(v => v.ToString(), v => Enum.Parse(v));
}

ASP.NET CoreRelationshipsNavigation PropertiesEF Core
Handle relationships with fluent API or data annotations, using `Include`/`ThenInclude` for eager loading or projections for selective data. Avoid lazy loading in performance-critical apps.
Example:
var order = await _context.Orders
    .Include(o => o.Customer)
    .ThenInclude(c => c.Address)
    .FirstOrDefaultAsync(o => o.Id == 1);

ASP.NET CoreCode-FirstDatabase-FirstEF Core
Code-first allows full control over models and migrations but requires manual schema alignment. Database-first is faster for existing databases but less flexible. Use code-first for new projects, database-first for legacy systems.
Example:
// Code-first
public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
}

ASP.NET CoreEF Core MigrationsMicroservices
Manage migrations with a dedicated migration project, apply via CLI (`dotnet ef database update`) or programmatically in startup. Use environment-specific connection strings and automate with CI/CD pipelines.
Example:
public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext(options =>
        options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
}

ASP.NET CoreConcurrency ControlEF Core
Handle concurrency with optimistic locking using a concurrency token (e.g., `RowVersion`) or pessimistic locking with transactions. EF Core throws `DbUpdateConcurrencyException` on conflicts.
Example:
public class Product
{
    public int Id { get; set; }
    [ConcurrencyCheck]
    public string Name { get; set; }
}

public async Task UpdateProductAsync(int id, string name)
{
    var product = await _context.Products.FindAsync(id);
    product.Name = name;
    try
    {
        await _context.SaveChangesAsync();
    }
    catch (DbUpdateConcurrencyException)
    {
        // Handle conflict
    }
}

ASP.NET CoreSoft DeleteEF Core
Implement soft deletes with an `IsDeleted` flag and global query filters. Override `SaveChanges` to set the flag instead of deleting.
Example:
public class Product
{
    public int Id { get; set; }
    public bool IsDeleted { get; set; }
}

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity().HasQueryFilter(p => !p.IsDeleted);
}

public class MyDbContext : DbContext
{
    public override Task SaveChangesAsync(CancellationToken cancellationToken = default)
    {
        foreach (var entry in ChangeTracker.Entries().Where(e => e.State == EntityState.Deleted))
        {
            entry.State = EntityState.Modified;
            entry.Entity.GetType().GetProperty("IsDeleted")?.SetValue(entry.Entity, true);
        }
        return base.SaveChangesAsync(cancellationToken);
    }
}

ASP.NET CoreIncludeThenIncludeProjectionEF Core
Include() loads related data eagerly. ThenInclude() continues loading deeper relationships. Projections (Select) map to DTOs, reducing data transfer. Use projections for read-only, Include for updates.
Example:
var products = await _context.Products
    .Include(p => p.Category)
    .ThenInclude(c => c.Supplier)
    .Select(p => new { p.Id, p.Name })
    .ToListAsync();

ASP.NET CoreEF Core LimitationsWorkarounds
Limitations include complex query performance, lack of bulk operations, and limited SQL support. Workarounds include raw SQL queries, libraries like EFCore.BulkExtensions, and optimizing with projections.
Example:
var products = await _context.Products
    .FromSqlRaw("SELECT * FROM Products WHERE IsActive = 1")
    .ToListAsync();

ASP.NET CoreSingle Responsibility PrincipleSOLID
Apply SRP by ensuring controllers handle HTTP concerns and services handle business logic. Each class should have one reason to change.
Example:
public class ProductController : ControllerBase
{
    private readonly IProductService _service;
    public ProductController(IProductService service) => _service = service;

    [HttpGet]
    public async Task Get() => Ok(await _service.GetAllAsync());
}

public class ProductService : IProductService
{
    public async Task> GetAllAsync() => await Task.FromResult(new List());
}

ASP.NET CoreOpen/Closed PrincipleService Layer
The Open/Closed Principle allows extension without modification. Example: A notification service with pluggable providers (e.g., Email, SMS) using interfaces.
Example:
public interface INotificationProvider
{
    Task SendAsync(string message);
}

public class EmailProvider : INotificationProvider
{
    public async Task SendAsync(string message) => await Task.CompletedTask;
}

public class NotificationService
{
    private readonly INotificationProvider _provider;
    public NotificationService(INotificationProvider provider) => _provider = provider;
    public async Task NotifyAsync(string message) => await _provider.SendAsync(message);
}

ASP.NET CoreLiskov Substitution PrincipleSOLID
LSP is violated if a derived class breaks the base class’s contract. Avoid by ensuring derived classes fully support base class behavior and adhering to interface contracts.
Example:
public interface IRepository
{
    Task SaveAsync();
}

public class ValidRepository : IRepository
{
    public async Task SaveAsync() => await Task.CompletedTask;
}

// Violates LSP
public class InvalidRepository : IRepository
{
    public Task SaveAsync() => throw new NotSupportedException();
}

ASP.NET CoreDecouplingDependency Injection
Decouple services by defining interfaces for dependencies and injecting them via DI. Use abstractions to isolate implementation details.
Example:
public interface IMyService { string GetData(); }
public class MyService : IMyService { public string GetData() => "Data"; }

public class MyController : ControllerBase
{
    private readonly IMyService _service;
    public MyController(IMyService service) => _service = service;
    [HttpGet]
    public IActionResult Get() => Ok(_service.GetData());
}

public void ConfigureServices(IServiceCollection services)
{
    services.AddScoped();
}

ASP.NET CoreInterface Segregation PrincipleSOLID
ISP states clients should not be forced to implement unneeded interfaces. Enforce by splitting large interfaces into smaller, specific ones.
Example:
public interface IReadRepository { Task> GetAllAsync(); }
public interface IWriteRepository { Task SaveAsync(Product product); }

public class ProductRepository : IReadRepository, IWriteRepository
{
    public async Task> GetAllAsync() => await Task.FromResult(new List());
    public async Task SaveAsync(Product product) => await Task.CompletedTask;
}

ASP.NET CoreJWT AuthenticationRefresh TokensSecurity
Implement JWT authentication with `AddJwtBearer` and refresh tokens stored securely (e.g., database). Validate tokens and issue new ones on refresh.
Example:
public void ConfigureServices(IServiceCollection services)
{
    services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        .AddJwtBearer(options =>
        {
            options.TokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuer = true,
                ValidateAudience = true,
                ValidIssuer = "MyIssuer",
                ValidAudience = "MyAudience",
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("my-secret-key"))
            };
        });
}

public class AuthController : ControllerBase
{
    [HttpPost("refresh")]
    public IActionResult Refresh(string refreshToken)
    {
        // Validate and issue new JWT
        return Ok(new { token = "new-jwt", refreshToken = "new-refresh-token" });
    }
}

ASP.NET CoreDependency Inversion PrincipleSOLID
DIP states high-level modules should depend on abstractions, not implementations. In ASP.NET Core, apply DIP using interfaces and DI to decouple services.
Example:
public interface IMyService { string GetData(); }
public class MyService : IMyService { public string GetData() => "Data"; }

public void ConfigureServices(IServiceCollection services)
{
    services.AddScoped();
}

ASP.NET CoreGlobal Exception HandlingLoggingCorrelation IDs
Use middleware for global exception handling and ILogger with correlation IDs (e.g., from headers or generated) for tracing requests across services.
Example:
public class CorrelationIdMiddleware
{
    private readonly RequestDelegate _next;
    public CorrelationIdMiddleware(RequestDelegate next) => _next = next;

    Underwood async Task InvokeAsync(HttpContext context, ILogger logger)
    {
        var correlationId = context.Request.Headers["CorrelationId"].FirstOrDefault() ?? Guid.NewGuid().ToString();
        logger.LogInformation("Request with CorrelationId: {CorrelationId}", correlationId);
        try
        {
            await _next(context);
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "Error with CorrelationId: {CorrelationId}", correlationId);
            context.Response.StatusCode = 500;
            await context.Response.WriteAsync("Internal Server Error");
        }
    }
}

app.UseMiddleware();

ASP.NET CoreSecurity VulnerabilitiesXSSCSRF
Common vulnerabilities include XSS (prevent with output encoding), CSRF (use anti-forgery tokens), SQL injection (use parameterized queries), and insecure APIs (use authentication/authorization).
Example:

@Html.AntiForgeryToken()
public class MyController : Controller { [HttpPost] [ValidateAntiForgeryToken] public IActionResult Post() => Ok(); }

ASP.NET CoreCachingIn-Memory CachingDistributed Caching
Enable caching with `IMemoryCache` for in-memory or `IDistributedCache` (e.g., Redis) for distributed. Use in-memory for single-instance apps, distributed for scalability across multiple instances.
Example:
public void ConfigureServices(IServiceCollection services)
{
    services.AddMemoryCache();
    services.AddStackExchangeRedisCache(options => options.Configuration = "localhost:6379");
}

public class MyService
{
    private readonly IMemoryCache _cache;
    public MyService(IMemoryCache cache) => _cache = cache;
    public string GetData(string key)
    {
        if (!_cache.TryGetValue(key, out string value))
        {
            value = "Data";
            _cache.Set(key, value, TimeSpan.FromMinutes(10));
        }
        return value;
    }
}

ASP.NET CoreAsync Best PracticesEF CorePerformance
Use `async`/`await` consistently, avoid blocking calls (e.g., `.Result`), use `ConfigureAwait(false)` for library code, and optimize EF Core queries with async methods and projections.
Example:
public async Task> GetProductsAsync()
{
    return await _context.Products
        .AsNoTracking()
        .Select(p => new Product { Id = p.Id, Name = p.Name })
        .ToListAsync()
        .ConfigureAwait(false);
}

ASP.NET CoreLoad BalancingScalingMicroservices
Scale with Kubernetes (using replicas, ingress) or Azure (App Services, AKS). Use load balancers, distributed caching, and stateless services. Implement health checks for service discovery.
Example:
public void ConfigureServices(IServiceCollection services)
{
    services.AddHealthChecks();
}

public void Configure(IApplicationBuilder app)
{
    app.UseHealthChecks("/health");
}

ASP.NET CoreHealth ChecksMicroservices
Implement health checks using `AddHealthChecks` and custom checks for dependencies (e.g., database). Expose endpoints for liveness and readiness probes.
Example:
public void ConfigureServices(IServiceCollection services)
{
    services.AddHealthChecks()
        .AddDbContextCheck();
}

public void Configure(IApplicationBuilder app)
{
    app.UseHealthChecks("/health");
}

ASP.NET CoreFeature TogglesA/B Testing
Implement feature toggles with configuration (e.g., `appsettings.json`) or libraries like Microsoft.FeatureManagement. For A/B testing, route users to different features based on conditions.
Example:
public void ConfigureServices(IServiceCollection services)
{
    services.AddFeatureManagement();
}

public class MyController : ControllerBase
{
    private readonly IFeatureManager _featureManager;
    public MyController(IFeatureManager featureManager) => _featureManager = featureManager;

    [HttpGet]
    public async Task Get()
    {
        if (await _featureManager.IsEnabledAsync("NewFeature"))
            return Ok("New Feature Enabled");
        return Ok("Old Feature");
    }
}

ASP.NET CoreTestingMockingEF Core
Mock EF Core with in-memory databases or Moq. Mock HTTP calls with `HttpClient` fakes or libraries like WireMock. Use `WebApplicationFactory` for integration tests.
Example:
public class ProductServiceTests
{
    [Fact]
    public async Task GetProducts_ReturnsProducts()
    {
        var options = new DbContextOptionsBuilder().UseInMemoryDatabase("TestDb").Options;
        using var context = new MyDbContext(options);
        context.Products.Add(new Product { Id = 1, Name = "Test" });
        await context.SaveChangesAsync();

        var service = new ProductService(context);
        var products = await service.GetAllAsync();
        Assert.Single(products);
    }
}