LearnThatStack Ace your next interview

ASP.NET Core.
Cheat sheet.

Quick reference for ASP.NET Core - sectioned for fast scanning. Skim the part you're shaky on, walk in confident.

Backend Development 21-section reference ~9 min read

Summary

ASP.NET Core is Microsoft's cross-platform, high-performance web framework for building modern web applications and APIs. This cheatsheet covers essential concepts including fundamentals, dependency injection, middleware, routing, authentication, Entity Framework Core, and performance optimization. Key topics include the request pipeline, service lifetimes, model binding, filters, and best practices for building scalable web applications.

1. ASP.NET Core Fundamentals

What is ASP.NET Core?

  • Cross-platform, high-performance, open-source framework
  • Built on .NET Core (now .NET 5+)
  • Supports Windows, Linux, macOS
  • Unified framework for web UI and APIs

Key Features

  • Cross-platform: Run on Windows, Linux, macOS
  • High Performance: One of the fastest web frameworks
  • Dependency Injection: Built-in DI container
  • Modular: NuGet-based, use only what you need
  • Cloud-ready: Configuration, logging, DI designed for cloud

Hosting Models

  • Kestrel: Cross-platform web server (recommended)
  • IIS: Windows-only, acts as reverse proxy to Kestrel
  • HTTP.sys: Windows-only, alternative to Kestrel

2. Project Structure

Program.cs (Minimal API .NET 6+)

var builder = WebApplication.CreateBuilder(args);

// Add services
builder.Services.AddControllers();
builder.Services.AddDbContext<AppDbContext>();

var app = builder.Build();

// Configure middleware pipeline
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();

app.Run();

Key Folders

  • Controllers: API/MVC controllers
  • Models: Data models/DTOs
  • Views: Razor views (MVC)
  • wwwroot: Static files (CSS, JS, images)
  • appsettings.json: Configuration

3. Dependency Injection (DI)

Service Lifetimes

// Transient: New instance each time
builder.Services.AddTransient<IEmailService, EmailService>();

// Scoped: One instance per request
builder.Services.AddScoped<IUserService, UserService>();

// Singleton: One instance for app lifetime
builder.Services.AddSingleton<ICacheService, CacheService>();

Constructor Injection

public class UserController : ControllerBase
{
    private readonly IUserService _userService;
    
    public UserController(IUserService userService)
    {
        _userService = userService;
    }
}

4. Middleware

What is Middleware?

  • Components that handle HTTP requests/responses
  • Executed in order (pipeline)
  • Can short-circuit the pipeline

Built-in Middleware Order (Important!)

app.UseExceptionHandler("/Error");  // 1. Exception handling (first)
app.UseHsts();                      // 2. HTTPS Strict Transport Security
app.UseHttpsRedirection();          // 3. HTTPS redirection
app.UseStaticFiles();               // 4. Static files (before routing)
app.UseRouting();                   // 5. Route matching
app.UseCors();                      // 6. CORS (after routing)
app.UseAuthentication();            // 7. Authentication (before authorization)
app.UseAuthorization();             // 8. Authorization (after authentication)
app.MapControllers();               // 9. Map endpoints (.NET 6+)

Custom Middleware

public class LoggingMiddleware
{
    private readonly RequestDelegate _next;
    
    public LoggingMiddleware(RequestDelegate next)
    {
        _next = next;
    }
    
    public async Task InvokeAsync(HttpContext context)
    {
        // Before
        Console.WriteLine($"Request: {context.Request.Path}");
        
        await _next(context);
        
        // After
        Console.WriteLine($"Response: {context.Response.StatusCode}");
    }
}

// Register
app.UseMiddleware<LoggingMiddleware>();

5. Routing

Attribute Routing

[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
    [HttpGet]
    public IActionResult GetAll() { }
    
    [HttpGet("{id:int}")]
    public IActionResult GetById(int id) { }
    
    [HttpPost]
    public IActionResult Create([FromBody] Product product) { }
    
    [HttpPut("{id}")]
    public IActionResult Update(int id, [FromBody] Product product) { }
    
    [HttpDelete("{id}")]
    public IActionResult Delete(int id) { }
}

Route Constraints

[HttpGet("{id:int:min(1)}")]  // int, minimum value 1
[HttpGet("{name:alpha}")]      // alphabetic only
[HttpGet("{price:decimal}")]   // decimal values
[HttpGet("{date:datetime}")]   // DateTime
[HttpGet("{id:guid}")]         // GUID

6. Controllers and Actions

Action Results

// Status Codes
return Ok(data);                    // 200
return Created(uri, data);          // 201
return NoContent();                 // 204
return BadRequest(error);           // 400
return Unauthorized();              // 401
return NotFound();                  // 404
return Conflict();                  // 409

// Generic Results
return StatusCode(500, "Error");
return new JsonResult(data);
return File(bytes, "application/pdf");
return Redirect("https://example.com");

Model Binding Sources

public IActionResult Search(
    [FromQuery] string q,           // From query string
    [FromRoute] int id,            // From route data
    [FromBody] Product product,     // From request body
    [FromHeader] string auth,       // From headers
    [FromForm] IFormFile file)      // From form data
{
    // Implementation
}

7. Model Validation

Data Annotations

public class ProductDto
{
    [Required(ErrorMessage = "Name is required")]
    [StringLength(100, MinimumLength = 3)]
    public string Name { get; set; }
    
    [Range(0.01, 10000)]
    public decimal Price { get; set; }
    
    [EmailAddress]
    public string Email { get; set; }
    
    [RegularExpression(@"^\d{3}-\d{3}-\d{4}$")]
    public string Phone { get; set; }
    
    [Compare("Password")]
    public string ConfirmPassword { get; set; }
}

Manual Validation

[HttpPost]
public IActionResult Create(ProductDto product)
{
    if (!ModelState.IsValid)
        return BadRequest(ModelState);
    
    // Custom validation
    if (product.Price < 0)
        ModelState.AddModelError("Price", "Price cannot be negative");
    
    return Ok();
}

8. Filters

Filter Types (Execution Order)

  1. Authorization Filters: First to run
  2. Resource Filters: Before/after model binding
  3. Action Filters: Before/after action execution
  4. Exception Filters: Handle exceptions
  5. Result Filters: Before/after action result

Custom Action Filter

public class LogActionFilter : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext context)
    {
        // Before action executes
        Log($"Executing {context.ActionDescriptor.DisplayName}");
    }
    
    public override void OnActionExecuted(ActionExecutedContext context)
    {
        // After action executes
        Log($"Executed {context.ActionDescriptor.DisplayName}");
    }
}

// Usage
[LogActionFilter]
public class ProductsController : ControllerBase { }

9. Configuration

appsettings.json

{
  "ConnectionStrings": {
    "DefaultConnection": "Server=.;Database=MyDb;Trusted_Connection=true;"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information"
    }
  },
  "AppSettings": {
    "ApiKey": "your-api-key",
    "MaxItems": 100
  }
}

Accessing Configuration

// Using IConfiguration
public class MyService
{
    private readonly IConfiguration _config;
    
    public MyService(IConfiguration config)
    {
        _config = config;
        var connString = _config.GetConnectionString("DefaultConnection");
        var apiKey = _config["AppSettings:ApiKey"];
    }
}

// Using Options Pattern
public class AppSettings
{
    public string ApiKey { get; set; }
    public int MaxItems { get; set; }
}

// Startup
builder.Services.Configure<AppSettings>(
    builder.Configuration.GetSection("AppSettings"));

// Usage
public class MyService
{
    private readonly AppSettings _settings;
    
    public MyService(IOptions<AppSettings> options)
    {
        _settings = options.Value;
    }
}

10. Logging

Built-in Logging

public class ProductService
{
    private readonly ILogger<ProductService> _logger;
    
    public ProductService(ILogger<ProductService> logger)
    {
        _logger = logger;
    }
    
    public void ProcessProduct(int id)
    {
        _logger.LogInformation("Processing product {ProductId}", id);
        
        try
        {
            // Process
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error processing product {ProductId}", id);
        }
    }
}

Log Levels

  • Trace: Most detailed messages
  • Debug: Debugging information
  • Information: General flow
  • Warning: Abnormal or unexpected events
  • Error: Error messages
  • Critical: Failures requiring immediate attention
  • None: Not used for logging

11. Entity Framework Core

DbContext Setup

public class AppDbContext : DbContext
{
    public AppDbContext(DbContextOptions<AppDbContext> options)
        : base(options) { }
    
    public DbSet<Product> Products { get; set; }
    public DbSet<Category> Categories { get; set; }
    
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        // Fluent API configuration
        modelBuilder.Entity<Product>()
            .HasKey(p => p.Id);
            
        modelBuilder.Entity<Product>()
            .Property(p => p.Name)
            .IsRequired()
            .HasMaxLength(100);
    }
}

// Registration
builder.Services.AddDbContext<AppDbContext>(options =>
    options.UseSqlServer(connectionString));

Common Operations

// Query with filtering and ordering
var products = await _context.Products
    .Where(p => p.Price > 100)
    .OrderBy(p => p.Name)
    .ToListAsync();

// Include related data (eager loading)
var productsWithCategory = await _context.Products
    .Include(p => p.Category)
    .ToListAsync();

// Projection (select specific fields)
var productNames = await _context.Products
    .Select(p => p.Name)
    .ToListAsync();

// CRUD Operations
// Create
_context.Products.Add(new Product { Name = "New Product" });
await _context.SaveChangesAsync();

// Read
var product = await _context.Products.FindAsync(id);

// Update
product.Name = "Updated Name";
await _context.SaveChangesAsync();

// Delete
_context.Products.Remove(product);
await _context.SaveChangesAsync();

12. Authentication & Authorization

JWT Authentication Setup

// 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"))
        };
    });

// Generate JWT Token
public string GenerateToken(User user)
{
    var claims = new[]
    {
        new Claim(ClaimTypes.Name, user.Username),
        new Claim(ClaimTypes.Role, user.Role)
    };
    
    var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_secretKey));
    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);
}

Authorization

// Basic Authorization
[Authorize]
public class SecureController : ControllerBase { }

// Role-based
[Authorize(Roles = "Admin")]
public IActionResult AdminOnly() { }

// Policy-based
builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("MinimumAge", policy =>
        policy.Requirements.Add(new MinimumAgeRequirement(18)));
});

[Authorize(Policy = "MinimumAge")]
public IActionResult AdultContent() { }

13. Web API Best Practices

API Versioning

// Install: Microsoft.AspNetCore.Mvc.Versioning
builder.Services.AddApiVersioning(options =>
{
    options.DefaultApiVersion = new ApiVersion(1, 0);
    options.AssumeDefaultVersionWhenUnspecified = true;
    options.ReportApiVersions = true;
});

[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/[controller]")]
public class ProductsController : ControllerBase { }

Response Caching

// Response caching
[HttpGet]
[ResponseCache(Duration = 60)] // Cache for 60 seconds
public IActionResult GetProducts() { }

// In-memory caching
public class ProductService
{
    private readonly IMemoryCache _cache;
    
    public async Task<Product> GetProductAsync(int id)
    {
        var cacheKey = $"product_{id}";
        
        if (!_cache.TryGetValue(cacheKey, out Product product))
        {
            product = await _repository.GetByIdAsync(id);
            
            _cache.Set(cacheKey, product, TimeSpan.FromMinutes(5));
        }
        
        return product;
    }
}

Global Exception Handling

public class GlobalExceptionMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger<GlobalExceptionMiddleware> _logger;
    
    public async Task InvokeAsync(HttpContext context)
    {
        try
        {
            await _next(context);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "An unhandled exception occurred");
            await HandleExceptionAsync(context, ex);
        }
    }
    
    private static async Task HandleExceptionAsync(
        HttpContext context, Exception exception)
    {
        context.Response.ContentType = "application/json";
        context.Response.StatusCode = StatusCodes.Status500InternalServerError;
        
        var response = new
        {
            error = new
            {
                message = "An error occurred processing your request",
                detail = exception.Message // Only in development
            }
        };
        
        await context.Response.WriteAsync(JsonSerializer.Serialize(response));
    }
}

14. Performance Optimization

Async/Await Best Practices

// Good - Async all the way
public async Task<IActionResult> GetProductsAsync()
{
    var products = await _service.GetProductsAsync();
    return Ok(products);
}

// Avoid - Sync over async
public IActionResult GetProducts()
{
    var products = _service.GetProductsAsync().Result; // Blocks thread
    return Ok(products);
}

// Parallel execution
public async Task<IActionResult> GetDashboardData()
{
    var productsTask = _productService.GetProductsAsync();
    var ordersTask = _orderService.GetOrdersAsync();
    
    await Task.WhenAll(productsTask, ordersTask);
    
    return Ok(new
    {
        Products = productsTask.Result,
        Orders = ordersTask.Result
    });
}

Response Compression

// Enable response compression
builder.Services.AddResponseCompression(options =>
{
    options.EnableForHttps = true;
    options.Providers.Add<GzipCompressionProvider>();
});

app.UseResponseCompression();

16. Quick Reference - Common Attributes

Controller Attributes

  • [ApiController]: Enables API-specific behaviors (auto model validation, binding source inference)
  • [Route("api/[controller]")]: Defines route template
  • [Authorize]: Requires authentication
  • [AllowAnonymous]: Allows anonymous access

Action Attributes

  • [HttpGet], [HttpPost], [HttpPut], [HttpDelete]: HTTP verb constraints
  • [FromBody], [FromQuery], [FromRoute], [FromHeader]: Binding sources
  • [ResponseCache(Duration = 60)]: Response caching
  • [ValidateAntiForgeryToken]: CSRF protection

Model Validation Attributes

  • [Required]: Field is mandatory
  • [StringLength(100, MinimumLength = 3)]: String length constraints
  • [Range(1, 100)]: Numeric range validation
  • [EmailAddress]: Email format validation
  • [RegularExpression("pattern")]: Custom pattern validation
  • [Compare("PropertyName")]: Compare with another property

17. Testing

Unit Testing Controllers

[Fact]
public async Task GetProduct_ReturnsProduct_WhenProductExists()
{
    // Arrange
    var mockService = new Mock<IProductService>();
    mockService.Setup(s => s.GetByIdAsync(1))
        .ReturnsAsync(new Product { Id = 1, Name = "Test" });
    
    var controller = new ProductsController(mockService.Object);
    
    // Act
    var result = await controller.GetById(1);
    
    // Assert
    var okResult = Assert.IsType<OkObjectResult>(result);
    var product = Assert.IsType<Product>(okResult.Value);
    Assert.Equal(1, product.Id);
}

Integration Testing

public class ProductsControllerTests : IClassFixture<WebApplicationFactory<Program>>
{
    private readonly WebApplicationFactory<Program> _factory;
    
    public ProductsControllerTests(WebApplicationFactory<Program> factory)
    {
        _factory = factory;
    }
    
    [Fact]
    public async Task Get_Products_ReturnsSuccessStatusCode()
    {
        // Arrange
        var client = _factory.CreateClient();
        
        // Act
        var response = await client.GetAsync("/api/products");
        
        // Assert
        response.EnsureSuccessStatusCode();
        Assert.Equal("application/json", 
            response.Content.Headers.ContentType.MediaType);
    }
}

18. Security Best Practices

CORS Configuration

builder.Services.AddCors(options =>
{
    options.AddPolicy("AllowSpecificOrigin",
        builder => builder
            .WithOrigins("https://example.com")
            .AllowAnyMethod()
            .AllowAnyHeader()
            .AllowCredentials());
});

app.UseCors("AllowSpecificOrigin");

Data Protection

// Protect sensitive data
public class User
{
    public int Id { get; set; }
    public string Username { get; set; }
    
    [JsonIgnore] // Don't serialize
    public string Password { get; set; }
}

// Input validation
[HttpPost]
public IActionResult Create([FromBody] ProductDto product)
{
    // Validate input
    if (string.IsNullOrWhiteSpace(product.Name))
        return BadRequest("Product name is required");
    
    // Sanitize input
    product.Name = product.Name.Trim();
    
    // Process...
}

19. Key Concepts & Comparisons

.NET Core vs .NET Framework

Feature .NET Core .NET Framework
Platform Cross-platform Windows only
Performance Higher Lower
Deployment Self-contained System-wide
Open Source Yes Partially
Future Active development Maintenance mode

Data Passing Methods (MVC)

  • ViewData: Dictionary-based, requires casting, weak typing
  • ViewBag: Dynamic wrapper around ViewData
  • TempData: Persists for one request, uses session storage
  • Model: Strongly typed, compile-time checking (recommended)

Action Result Types

Result Type Purpose Status Code
ViewResult Return a view 200
JsonResult Return JSON data 200
ContentResult Return plain text 200
FileResult Return file download 200
RedirectResult Redirect to URL 302
StatusCodeResult Custom status code Variable

Authentication vs Authorization

  • Authentication: Identity verification ("Who are you?")
  • Authorization: Permission checking ("What can you do?")
  • Flow: Authentication → Authorization → Access granted/denied

Performance Optimization Strategies

  • Async/Await: Use consistently, avoid blocking calls
  • Caching: Response caching, in-memory, distributed (Redis)
  • Database: Use projections, includes, avoid N+1 queries
  • Compression: Enable Gzip compression for responses
  • Pagination: Limit large dataset responses
  • CDN: Serve static content from edge locations

Quick Reference - Status Codes

  • 1xx: Informational
  • 2xx: Success (200 OK, 201 Created, 204 No Content)
  • 3xx: Redirection (301 Moved, 302 Found, 304 Not Modified)
  • 4xx: Client Error (400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found)
  • 5xx: Server Error (500 Internal Server Error, 503 Service Unavailable)

Key Commands

# Create new project
dotnet new webapi -n MyApi
dotnet new mvc -n MyMvcApp

# Add packages
dotnet add package Microsoft.EntityFrameworkCore.SqlServer
dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer

# EF Core commands
dotnet ef migrations add InitialCreate
dotnet ef database update
dotnet ef database drop

# Run application
dotnet run
dotnet watch run  # With hot reload

Remember: This cheat sheet covers the essentials. Always refer to official documentation for the latest updates and detailed information.

Found this useful? Pass it on.
Pro · $10/mo

The sheet is free. Pro goes deeper.

Pro opens the full question library behind every sheet, every refresher and a monthly AI allowance. One subscription, all formats.

Full question library All refreshers Cancel anytime