25 Pertanyaan Interview ASP.NET Core: Middleware, DI, dan Minimal APIs

Kuasai pertanyaan interview ASP.NET Core tentang middleware pipeline, dependency injection, minimal APIs, dan konsep advanced untuk persiapan wawancara teknis.

Pertanyaan Interview ASP.NET Core tentang Middleware, Dependency Injection, dan Minimal APIs

ASP.NET Core telah menjadi framework pilihan untuk membangun aplikasi web modern yang scalable dan performant. Dalam proses interview untuk posisi .NET developer, pemahaman mendalam tentang middleware pipeline, dependency injection container, dan minimal APIs menjadi indikator kuat dari keahlian teknis kandidat. Framework ini terus berkembang melalui .NET 10, menghadirkan arsitektur modular yang memungkinkan developer membangun aplikasi dengan separation of concerns yang jelas, testability yang tinggi, dan performa yang optimal.

Fokus utama interviewer

Urutan middleware pipeline, kesalahan lifetime pada DI (masalah captive dependency), dan kemampuan menjelaskan trade-off antara minimal APIs dan controllers merupakan tiga area yang paling sering diuji dalam interview ASP.NET Core di level mid-to-senior.

Pertanyaan Middleware Pipeline ASP.NET Core

1. Apa yang dimaksud dengan middleware dalam ASP.NET Core?

Middleware adalah komponen yang disusun dalam pipeline aplikasi untuk menangani request dan response. Setiap middleware memilih untuk meneruskan request ke komponen berikutnya atau melakukan short-circuit pada pipeline. Middleware dieksekusi sesuai urutan registrasi di Program.cs, dan response berjalan kembali melalui komponen yang sama dalam urutan terbalik.

2. Bagaimana urutan eksekusi middleware bekerja?

Urutan pemanggilan app.Use*() di Program.cs menentukan sekuens eksekusi secara pasti. Request mengalir dari atas ke bawah melalui setiap middleware, dan response mengalir dari bawah ke atas. Inilah mengapa UseAuthentication() harus muncul sebelum UseAuthorization(), dan UseRouting() sebelum UseEndpoints().

Program.cs — Middleware order matterscsharp
var app = builder.Build();

app.UseExceptionHandler("/error");   // 1. Outermost: catches all exceptions
app.UseHsts();                        // 2. HTTP Strict Transport Security
app.UseHttpsRedirection();            // 3. Redirect HTTP to HTTPS
app.UseStaticFiles();                 // 4. Serve static files (short-circuits if found)
app.UseRouting();                     // 5. Match request to endpoint
app.UseAuthentication();              // 6. Identify the user
app.UseAuthorization();               // 7. Check permissions
app.MapControllers();                 // 8. Execute the matched endpoint

app.Run();

Menempatkan UseStaticFiles() sebelum authentication menghindari pengecekan auth yang tidak perlu pada file CSS, JS, dan gambar. Ini sering menjadi pertanyaan lanjutan dalam interview.

3. Bagaimana cara membuat custom middleware?

Custom middleware dapat diimplementasikan sebagai class dengan method InvokeAsync atau secara inline menggunakan app.Use(). Pendekatan berbasis class lebih disarankan untuk kode production karena mendukung dependency injection melalui parameter constructor.

RequestTimingMiddleware.cscsharp
public class RequestTimingMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger<RequestTimingMiddleware> _logger;

    public RequestTimingMiddleware(RequestDelegate next, ILogger<RequestTimingMiddleware> logger)
    {
        _next = next;
        _logger = logger;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        var stopwatch = Stopwatch.StartNew();
        
        await _next(context);  // Call the next middleware
        
        stopwatch.Stop();
        _logger.LogInformation(
            "Request {Method} {Path} completed in {Elapsed}ms",
            context.Request.Method,
            context.Request.Path,
            stopwatch.ElapsedMilliseconds);
    }
}

// Registration in Program.cs
app.UseMiddleware<RequestTimingMiddleware>();

Perlu diperhatikan bahwa class middleware diinstansiasi sekali (singleton lifetime) sementara InvokeAsync dipanggil per request. Perbedaan ini penting untuk thread safety.

4. Apa perbedaan antara app.Use(), app.Run(), dan app.Map()?

app.Use() menambahkan middleware yang memanggil delegate berikutnya. app.Run() adalah terminal middleware yang tidak memanggil next, mengakhiri pipeline. app.Map() membuat cabang pipeline berdasarkan path request. Kesalahan umum adalah menempatkan app.Run() terlalu awal, yang akan melakukan short-circuit pada seluruh middleware di bawahnya.

5. Bagaimana mekanisme short-circuiting middleware bekerja?

Middleware mana pun dapat melakukan short-circuit pada pipeline dengan tidak memanggil next(). Ini adalah cara kerja UseStaticFiles(): jika file statis cocok dengan path request, file tersebut langsung dikembalikan tanpa memanggil middleware authentication, authorization, atau routing. Middleware rate-limiting juga menggunakan short-circuiting untuk mengembalikan response 429 sebelum mencapai endpoint.

6. Apa yang berubah pada middleware di .NET 9?

.NET 9 memperluas dukungan keyed dependency injection ke middleware. Atribut [FromKeyedServices] kini dapat digunakan baik di constructor middleware (untuk service singleton/transient) maupun di method InvokeAsync (untuk semua lifetime termasuk scoped). Ini menghilangkan kebutuhan workaround service locator ketika middleware membutuhkan implementasi berbeda dari interface yang sama.

Pertanyaan Dependency Injection

7. Apa tiga service lifetime pada DI?

ASP.NET Core menyediakan tiga lifetime: Transient (instance baru setiap kali), Scoped (satu instance per HTTP request), dan Singleton (satu instance untuk seluruh lifetime aplikasi). Pilihan lifetime secara langsung mempengaruhi penggunaan memori, thread safety, dan berbagi state antar komponen.

Masalah captive dependency

Menginjeksi scoped service ke dalam singleton menciptakan captive dependency: scoped service hidup selama singleton, berbagi state antar request. Aktifkan ValidateScopes di development untuk mendeteksi ini saat startup.

8. Jelaskan masalah captive dependency dengan contoh

Ketika singleton service menerima scoped dependency melalui constructor-nya, instance scoped tersebut tidak pernah di-dispose antar request. Instance tersebut menjadi "captive" dalam lifetime singleton. Ini menyebabkan state dibagikan antar HTTP request, yang dapat mengakibatkan kebocoran data dan race condition.

Program.cs — Captive dependency detectioncsharp
builder.Services.AddScoped<IUserRepository, UserRepository>();
builder.Services.AddSingleton<ICacheService, CacheService>(); // CacheService takes IUserRepository

// This throws at startup in Development when ValidateScopes is enabled:
builder.Host.UseDefaultServiceProvider(options =>
{
    options.ValidateScopes = true;    // Catches captive dependencies
    options.ValidateOnBuild = true;   // Validates all registrations at startup
});

Solusinya: injeksi IServiceScopeFactory ke dalam singleton dan buat scope secara manual ketika scoped service dibutuhkan.

9. Apa itu keyed services dan kapan menggunakannya?

Keyed services, diperkenalkan di .NET 8, memungkinkan registrasi beberapa implementasi dari interface yang sama dengan key berbeda. Fitur ini menghilangkan pattern factory kustom dan logika resolusi kondisional yang kompleks.

Program.cs — Registering keyed servicescsharp
builder.Services.AddKeyedSingleton<INotificationService, EmailNotification>("email");
builder.Services.AddKeyedSingleton<INotificationService, SmsNotification>("sms");
builder.Services.AddKeyedSingleton<INotificationService, PushNotification>("push");

// Resolving in a controller or service
public class OrderService
{
    public OrderService(
        [FromKeyedServices("email")] INotificationService emailService,
        [FromKeyedServices("sms")] INotificationService smsService)
    {
        // Each parameter gets its specific implementation
    }
}

Sebelum keyed services, hal ini memerlukan class factory, named registration dengan third-party container, atau resolusi manual dari IServiceProvider.

10. Apakah third-party DI container masih diperlukan dengan ASP.NET Core?

Built-in container mencakup sebagian besar skenario pada .NET 9/10: constructor injection, keyed services, open generics, dan decorator pattern (melalui registrasi manual). Third-party container seperti Autofac atau Lamar tetap berguna untuk skenario advanced seperti property injection, interception/AOP, registrasi berbasis modul, atau scanning konvensi di seluruh assembly besar. Untuk sebagian besar aplikasi, built-in container sudah memadai.

11. Bagaimana DI bekerja di minimal APIs vs controllers?

Controllers menerima dependency melalui constructor injection. Endpoint minimal API menerimanya sebagai parameter method, yang di-resolve secara otomatis dari DI container. Tipe khusus seperti HttpContext, CancellationToken, dan ClaimsPrincipal juga di-bind otomatis tanpa registrasi eksplisit.

12. Apa itu Options pattern?

Options pattern mengikat bagian konfigurasi ke class strongly-typed. Pattern ini memisahkan konfigurasi dari logika service dan mendukung validasi, named options, dan reload runtime melalui IOptionsMonitor<T>. Menginjeksi raw IConfiguration ke dalam service merupakan anti-pattern karena mengikat service secara erat ke struktur konfigurasi.

Siap menguasai wawancara .NET Anda?

Berlatih dengan simulator interaktif, flashcards, dan tes teknis kami.

Pertanyaan Minimal APIs

13. Apa itu minimal APIs dan bagaimana perbedaannya dengan controllers?

Minimal APIs, diperkenalkan di .NET 6, mendefinisikan HTTP endpoint langsung di Program.cs menggunakan app.MapGet(), app.MapPost(), dan method serupa. Mereka menghilangkan kebutuhan class controller, atribut model binding, dan action filter. Controllers menawarkan dukungan bawaan untuk filter, validasi model, dan content negotiation. Minimal APIs lebih ringan tetapi memerlukan setup manual untuk cross-cutting concern.

14. Kapan memilih minimal APIs daripada controllers?

Minimal APIs cocok untuk microservice, API ringan, dan skenario di mana performa startup penting. Controllers cocok untuk aplikasi besar dengan pipeline filtering kompleks, model binding ekstensif, atau tim yang terbiasa dengan konvensi MVC. Keduanya dapat berdampingan dalam aplikasi yang sama.

15. Bagaimana menyusun minimal APIs dalam proyek nyata?

Hindari menempatkan semua endpoint di Program.cs. Gunakan extension method untuk mengorganisir endpoint berdasarkan fitur atau domain, menjaga route handler tetap tipis dan mendelegasikan logika bisnis ke service.

Features/Products/ProductEndpoints.cscsharp
public static class ProductEndpoints
{
    public static void MapProductEndpoints(this WebApplication app)
    {
        var group = app.MapGroup("/api/products")
            .WithTags("Products")
            .RequireAuthorization();

        group.MapGet("/", GetAll);
        group.MapGet("/{id:int}", GetById);
        group.MapPost("/", Create);
    }

    private static async Task<IResult> GetAll(
        IProductService productService,    // Auto-resolved from DI
        CancellationToken cancellationToken)
    {
        var products = await productService.GetAllAsync(cancellationToken);
        return TypedResults.Ok(products);
    }

    private static async Task<IResult> GetById(
        int id,
        IProductService productService)
    {
        var product = await productService.GetByIdAsync(id);
        return product is null
            ? TypedResults.NotFound()
            : TypedResults.Ok(product);
    }

    private static async Task<IResult> Create(
        CreateProductRequest request,
        IProductService productService)
    {
        var product = await productService.CreateAsync(request);
        return TypedResults.Created($"/api/products/{product.Id}", product);
    }
}

// Program.cs — Clean registration
app.MapProductEndpoints();

Pola ini dapat di-scale dengan baik: setiap folder fitur berisi endpoint, DTO, dan interface service-nya.

16. Bagaimana validasi bekerja di minimal APIs?

.NET 10 memperkenalkan validasi bawaan untuk minimal APIs. Sebelum .NET 10, validasi memerlukan implementasi manual atau library pihak ketiga seperti FluentValidation. Dengan .NET 10, data annotations pada tipe parameter divalidasi secara otomatis, dan request yang tidak valid mengembalikan response 400 dengan problem details.

17. Apa itu TypedResults dan mengapa menggunakannya?

TypedResults (diperkenalkan di .NET 7) menyediakan type safety pada waktu kompilasi untuk response API dan memungkinkan dokumentasi OpenAPI otomatis. Berbeda dengan Results yang mengembalikan IResult, method TypedResults mengembalikan tipe spesifik seperti Ok<T> atau NotFound, memungkinkan framework menghasilkan skema response yang akurat.

18. Bagaimana menangani Server-Sent Events di minimal APIs?

.NET 10 menambahkan TypedResults.ServerSentEvents() untuk streaming response. Fitur ini menghilangkan penulisan manual Response.Body dan menangani serialisasi JSON, header content-type, dan manajemen koneksi secara otomatis.

Pertanyaan Advanced

19. Bagaimana request pipeline berinteraksi dengan endpoint routing?

UseRouting() mencocokkan request yang masuk ke endpoint tetapi tidak mengeksekusinya. Middleware antara UseRouting() dan MapControllers()/MapEndpoints() dapat menginspeksi metadata endpoint yang cocok (misalnya atribut authorization) sebelum eksekusi. Ini adalah cara UseAuthorization() membaca atribut [Authorize] yang diatur pada controller atau endpoint minimal API.

20. Apa perbedaan antara AddTransient, AddScoped, dan AddSingleton untuk IHttpClientFactory?

Jangan pernah mendaftarkan HttpClient sebagai singleton: ia mengabaikan perubahan DNS dan menghabiskan koneksi socket. IHttpClientFactory (melalui AddHttpClient()) mengelola lifetime HttpClient dengan benar: instance HttpClient bersifat transient, tetapi pool HttpMessageHandler yang mendasarinya dikelola dengan lifetime yang dapat dikonfigurasi (default 2 menit). Ini mencegah kelelahan socket sambil menghormati TTL DNS.

21. Bagaimana mengimplementasikan decorator pattern dengan built-in DI?

Built-in container tidak memiliki dukungan decorator asli, tetapi dapat dicapai secara manual menggunakan factory delegate.

csharp
// Decorating IProductService with caching
builder.Services.AddScoped<ProductService>();
builder.Services.AddScoped<IProductService>(sp =>
{
    var inner = sp.GetRequiredService<ProductService>();
    var cache = sp.GetRequiredService<IMemoryCache>();
    return new CachedProductService(inner, cache);
});

Untuk aplikasi yang memerlukan banyak decorator, third-party container seperti Scrutor menyediakan API Decorate<TInterface, TDecorator>() yang lebih bersih.

22. Bagaimana middleware berbeda dari endpoint filter di minimal APIs?

Middleware berjalan untuk setiap request dalam pipeline, terlepas dari endpoint. Endpoint filter (diperkenalkan di .NET 7) hanya berjalan untuk endpoint yang cocok, mirip dengan action filter di MVC. Filter memiliki akses ke context spesifik endpoint dan didaftarkan per-route atau per-group. Gunakan middleware untuk cross-cutting concern seperti logging dan CORS; gunakan filter untuk logika spesifik endpoint seperti validasi atau transformasi.

23. Apa itu HybridCache di .NET 9?

HybridCache menggabungkan caching in-memory (L1) dan distributed (L2) di balik satu API. Fitur ini menangani perlindungan cache stampede secara otomatis: ketika beberapa request bersamaan melewatkan cache untuk key yang sama, hanya satu yang mengeksekusi factory method sementara yang lain menunggu. Ini menggantikan koordinasi manual IMemoryCache + IDistributedCache yang sebelumnya rawan error.

24. Bagaimana cara menguji middleware secara terpisah?

Middleware dapat diuji menggunakan DefaultHttpContext dan RequestDelegate kustom. Buat instance middleware, berikan mock context, dan assert pada properti response.

RequestTimingMiddlewareTests.cscsharp
[Fact]
public async Task Middleware_LogsElapsedTime()
{
    var logger = new FakeLogger<RequestTimingMiddleware>();
    var middleware = new RequestTimingMiddleware(
        next: (ctx) => Task.CompletedTask,  // Terminal delegate
        logger: logger);

    var context = new DefaultHttpContext();
    context.Request.Method = "GET";
    context.Request.Path = "/api/products";

    await middleware.InvokeAsync(context);

    Assert.Single(logger.LogEntries);
    Assert.Contains("completed in", logger.LogEntries[0].Message);
}

Untuk integration test, WebApplicationFactory<T> menyediakan pengujian pipeline lengkap termasuk urutan middleware.

25. Apa perubahan OpenAPI di .NET 9 dan .NET 10?

.NET 9 menggantikan Swagger/Swashbuckle dengan pembuatan dokumen OpenAPI bawaan melalui Microsoft.AspNetCore.OpenApi. .NET 10 mengupgrade ke library OpenAPI v2.0 dengan dukungan YAML, skema tipe nullable yang lebih baik (menggunakan oneOf alih-alih properti nullable), dan integrasi komentar dokumentasi XML yang lebih baik. Dokumen yang dihasilkan dilayani di /openapi/v1.json secara default.

Tips persiapan

Berlatihlah menjelaskan middleware pipeline di whiteboard: gambar request yang mengalir turun melalui setiap middleware dan response yang mengalir kembali ke atas. Interviewer di perusahaan seperti Microsoft, Accenture, dan konsultan sering menggunakan latihan ini untuk menilai kedalaman pemahaman.

Kesimpulan

  • Urutan eksekusi middleware bersifat deterministik dan kritis untuk keamanan: exception handling terlebih dahulu, static files sebelum auth, routing sebelum authorization
  • Masalah captive dependency (scoped di dalam singleton) adalah bug DI paling umum; aktifkan ValidateScopes dan ValidateOnBuild di development
  • Keyed services di .NET 8/9 menghilangkan sebagian besar kebutuhan untuk third-party DI container atau pattern factory kustom
  • Minimal APIs dan controllers dapat berdampingan; pilih berdasarkan kompleksitas proyek, konvensi tim, dan kebutuhan filtering
  • Susun minimal APIs menggunakan extension method dan route group untuk menjaga Program.cs tetap bersih
  • .NET 10 menambahkan validasi bawaan minimal API, dukungan SSE melalui TypedResults, dan pembuatan OpenAPI yang lebih baik
  • Uji middleware secara terpisah dengan DefaultHttpContext; gunakan WebApplicationFactory untuk integration test

Latih pertanyaan-pertanyaan ini dengan kode nyata di simulator interview .NET SharpSkill yang mencakup modul minimal APIs, pengembangan Web API, dan clean architecture.

Mulai berlatih!

Uji pengetahuan Anda dengan simulator wawancara dan tes teknis kami.

Tag

#asp.net core
#interview
#middleware
#dependency injection
#minimal apis
#dotnet

Bagikan

Artikel terkait