ASP.NET CORE Web API - Topic-wise Practice

10 production incidents. Each one took down Zomato. Fix them.

Staff Rule: Don't just pick the answer. Explain WHY the other options crash prod. In interview they ask "what if we did X instead?"

Topic 1: Model Binding & Overposting

Incident: Hacker ordered $0.01 Zomato Gold by posting {isGold:true, price:0.01}

Code:

public class Order {
  public int Id {get;set;}
  public decimal Price {get;set;}
  public bool IsGold {get;set;}
  public int UserId {get;set;}
}

[HttpPost]
public IActionResult Create(Order order) { // BINDING TO ENTITY
  order.UserId = int.Parse(User.FindFirst("sub").Value); // Set server-side
  _db.Orders.Add(order);
  _db.SaveChanges();
  return Created();
}

Question: Why did hacker get $0.01 Gold? Pick the fix and explain why others fail.

Topic 2: JWT Audience Validation

Incident: Dev token used on prod API. All accounts hijacked.

Code:

services.AddAuthentication("Bearer").AddJwtBearer(o => {
  o.TokenValidationParameters = new() {
    ValidateIssuer = true,
    ValidIssuer = "https://auth.zomato.com",
    ValidateAudience = false, // BUG
    ValidateLifetime = true,
    IssuerSigningKey = key
  };
});

Question: Hacker has valid JWT from dev.zomato.com with aud: "dev". What happens on api.zomato.com and why?

Topic 3: CORS Credentials + Wildcard

Incident: evil.com stole user cookies and order history via fetch()

Code:

builder.Services.AddCors(o => o.AddPolicy("Open", p => {
  p.SetIsOriginAllowed(_ => true) // Reflect any origin
  .AllowAnyHeader()
  .AllowAnyMethod()
  .AllowCredentials(); // DANGER
}));

Question: User logged into Zomato visits evil.com. What JS runs and what data leaks?

Topic 4: Middleware Order - Yellow Screen

Incident: 500 in UseRouting showed YSOD to users with stack trace

Code:

app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(e => e.MapControllers());
app.UseExceptionHandler("/error"); // TOO LATE

Question: Exception thrown in UseRouting. Why didn't UseExceptionHandler catch it? What's the fix?

Topic 5: CancellationToken & DB Meltdown

Incident: 10k users closed app mid-search. DB pool exhausted. 503 for everyone.

Code:

[HttpGet("restaurants")]
public async Task<IActionResult> Search([FromQuery] string q) {
  return Ok(await _db.Restaurants
   .Where(r => r.Name.Contains(q))
   .ToListAsync()); // NO CANCELLATION TOKEN
}

Question: User closes app at 5s. Query takes 30s. What happens to DbConnection and why?

Topic 6: Captive Dependency in Singleton

Incident: User A saw User B's cart. Singleton cached DbContext.

Code:

builder.Services.AddSingleton<ICartService, CartService>();
builder.Services.AddScoped<AppDbContext, AppDbContext>();

public class CartService : ICartService {
  private readonly AppDbContext _db; // CAPTURED FROM FIRST REQUEST
  public CartService(AppDbContext db) => _db = db;

  public async Task<Cart> GetCart(int userId) {
    return await _db.Carts.FirstAsync(c => c.UserId == userId); // Returns wrong user
  }
}

Question: Request #1: User 123. Request #2: User 456. Why does #2 get User 123's cart?

Topic 7: API Versioning - 400 on Missing Version

Incident: Old mobile app calls /api/restaurants. Gets 400. 30% users can't order.

Code:

builder.Services.AddApiVersioning(opt => {
  opt.DefaultApiVersion = new ApiVersion(1, 0);
  opt.AssumeDefaultVersionWhenUnspecified = false; // BUG
});

[ApiVersion("1.0")]
[ApiVersion("2.0")]
[Route("api/v{version:apiVersion}/restaurants")]
public class RestaurantsController : ControllerBase { }

Question: Client calls /api/restaurants with no version. What status and why? How to fix without breaking v2?

Topic 8: Rate Limiting Burst

Incident: Bot sends 100 req at 00:59, 100 more at 00:01. FixedWindow allows 200. DB down.

Code:

opt.GlobalLimiter = PartitionedRateLimiter.Create<HttpContext, string>(httpContext => {
  var ip = httpContext.Connection.RemoteIpAddress?.ToString()?? "unknown";
  return RateLimitPartition.GetFixedWindowLimiter(ip, _ => new() {
    PermitLimit = 100,
    Window = TimeSpan.FromMinutes(1)
  });
});

Question: Why did FixedWindow allow 200 req in 2 seconds? Which limiter fixes this?

Topic 9: Output Caching Data Leak

Incident: User A saw User B's profile. OutputCache didn't vary by user.

Code:

[HttpGet("profile")]
[OutputCache(Duration = 60)] // BUG - NO VaryByHeader
public async Task<UserProfile> GetProfile() {
  var userId = User.FindFirst("sub").Value;
  return await _db.Users.FindAsync(int.Parse(userId));
}

Question: User 1 calls /profile, cached. User 2 calls /profile. What does User 2 see and why?

Topic 10: async void Crash

Incident: Startup hook threw exception. App crashed in K8s. No 500, no logs.

Code:

public void Configure(IApplicationBuilder app) {
  app.Use(async (ctx, next) => {
    await LogRequestAsync(ctx); // async void inside
    await next();
  });
}

private async void LogRequestAsync(HttpContext ctx) { // BUG
  await Task.Delay(100);
  throw new Exception("DB down"); // UNOBSERVED EXCEPTION
}

Question: Why did the app crash instead of returning 500? What happens to async void exceptions in ASP.NET Core?

Done. 10 incidents = 10 staff-level topics. Memorize the "Staff Answer" for each. If you can explain Q2, Q5, Q6, Q9 without looking, you'll pass FAANG.

Comments on ASP.NET CORE Web API - Topic-wise Practice (0)

No comments yet. Be the first to share your thoughts!