15 .NET API Interview Questions and Answers
Prepare for your next technical interview with this comprehensive guide on .NET API, featuring common questions and detailed answers.
Prepare for your next technical interview with this comprehensive guide on .NET API, featuring common questions and detailed answers.
.NET API is a robust framework developed by Microsoft, enabling developers to build secure, scalable, and high-performance applications. It supports multiple programming languages, including C#, F#, and VB.NET, making it a versatile choice for a wide range of development needs. With its extensive library and seamless integration with other Microsoft services, .NET API is a critical tool for modern software development.
This article offers a curated selection of interview questions designed to test your knowledge and proficiency with .NET API. By reviewing these questions and their detailed answers, you will be better prepared to demonstrate your expertise and problem-solving abilities in a technical interview setting.
The .NET API is a framework developed by Microsoft for building scalable, maintainable, and secure applications. It supports multiple programming languages, including C#, VB.NET, and F#. Its core components include:
Dependency injection in .NET Core allows for registering services and their implementations, promoting loose coupling and maintainability. Services are typically registered in the Startup
class and injected into classes that require them.
Example:
public interface IGreetingService { string Greet(string name); } public class GreetingService : IGreetingService { public string Greet(string name) { return $"Hello, {name}!"; } } public class Startup { public void ConfigureServices(IServiceCollection services) { services.AddTransient<IGreetingService, GreetingService>(); } } public class HomeController : Controller { private readonly IGreetingService _greetingService; public HomeController(IGreetingService greetingService) { _greetingService = greetingService; } public IActionResult Index() { var message = _greetingService.Greet("World"); return Content(message); } }
Middleware components in ASP.NET Core are software pieces that handle requests and responses in an application pipeline. They can perform tasks like authentication, logging, and error handling. Middleware is configured in the Startup
class, and the order of components affects their processing sequence.
Example:
public class Startup { public void Configure(IApplicationBuilder app) { app.Use(async (context, next) => { Console.WriteLine("Request Incoming"); await next.Invoke(); Console.WriteLine("Response Outgoing"); }); app.Use(async (context, next) => { if (context.Request.Path == "/hello") { await context.Response.WriteAsync("Hello, World!"); } else { await next.Invoke(); } }); app.Run(async (context) => { await context.Response.WriteAsync("Middleware Pipeline End"); }); } }
ASP.NET Core’s logging framework is extensible and can log information to various outputs. It integrates with the dependency injection system, making it easy to use throughout the application.
Example:
public class Program { public static void Main(string[] args) { CreateHostBuilder(args).Build().Run(); } public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureLogging(logging => { logging.ClearProviders(); logging.AddConsole(); logging.AddDebug(); }) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); }); } public class SomeService { private readonly ILogger<SomeService> _logger; public SomeService(ILogger<SomeService> logger) { _logger = logger; } public void DoWork() { _logger.LogInformation("Doing work..."); try { // Some work here } catch (Exception ex) { _logger.LogError(ex, "An error occurred while doing work."); } } }
The lifecycle of a request in an ASP.NET Core application involves several stages:
Configuration settings in an ASP.NET Core application can be managed using:
Example:
// appsettings.json { "MySettings": { "Setting1": "Value1", "Setting2": "Value2" } } public class MySettings { public string Setting1 { get; set; } public string Setting2 { get; set; } } public void ConfigureServices(IServiceCollection services) { services.Configure<MySettings>(Configuration.GetSection("MySettings")); } public class SomeService { private readonly MySettings _settings; public SomeService(IOptions<MySettings> settings) { _settings = settings.Value; } public void PrintSettings() { Console.WriteLine(_settings.Setting1); Console.WriteLine(_settings.Setting2); } }
Entity Framework Core (EF Core) is an open-source, lightweight ORM for .NET applications. It allows developers to work with databases using .NET objects, supporting various database engines and features like automatic change tracking and lazy loading.
Example:
public class BloggingContext : DbContext { public DbSet<Blog> Blogs { get; set; } public DbSet<Post> Posts { get; set; } } public class Blog { public int BlogId { get; set; } public string Url { get; set; } public List<Post> Posts { get; set; } } public class Post { public int PostId { get; set; } public string Title { get; set; } public string Content { get; set; } public int BlogId { get; set; } public Blog Blog { get; set; } } using (var db = new BloggingContext()) { var blog = new Blog { Url = "http://sample.com" }; db.Blogs.Add(blog); db.SaveChanges(); }
Synchronous programming in .NET executes tasks sequentially, while asynchronous programming allows tasks to run concurrently, improving responsiveness and performance.
Example:
public void SynchronousMethod() { var result = LongRunningOperation(); Console.WriteLine(result); } public async Task AsynchronousMethod() { var result = await LongRunningOperationAsync(); Console.WriteLine(result); } public string LongRunningOperation() { Thread.Sleep(5000); return "Operation Complete"; } public async Task<string> LongRunningOperationAsync() { await Task.Delay(5000); return "Operation Complete"; }
Securing an ASP.NET Core application involves:
Example:
public void ConfigureServices(IServiceCollection services) { services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))); services.AddIdentity<ApplicationUser, IdentityRole>() .AddEntityFrameworkStores<ApplicationDbContext>() .AddDefaultTokenProviders(); services.AddAuthentication() .AddGoogle(options => { options.ClientId = Configuration["Authentication:Google:ClientId"]; options.ClientSecret = Configuration["Authentication:Google:ClientSecret"]; }); services.AddAuthorization(options => { options.AddPolicy("AdminOnly", policy => policy.RequireRole("Admin")); }); services.AddDataProtection(); services.AddControllersWithViews(); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Home/Error"); app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); }); }
Versioning in a .NET API can be handled using URL path, query string, or header versioning. Each method has its own advantages and use cases.
Example of URL path versioning:
[ApiController] [Route("api/v{version:apiVersion}/[controller]")] public class ProductsController : ControllerBase { [HttpGet] public IActionResult Get() => Ok(new { Message = "This is version 1" }); } public void ConfigureServices(IServiceCollection services) { services.AddApiVersioning(config => { config.DefaultApiVersion = new ApiVersion(1, 0); config.AssumeDefaultVersionWhenUnspecified = true; config.ReportApiVersions = true; }); }
Event sourcing captures state changes as a sequence of events, allowing reconstruction of an entity’s state at any point in time. It is useful for applications requiring audit trails and debugging capabilities.
Example:
public class Event { public Guid Id { get; set; } public DateTime Timestamp { get; set; } public string EventType { get; set; } public string Data { get; set; } } public class EventStore { private readonly List<Event> _events = new List<Event>(); public void Save(Event evt) { _events.Add(evt); } public IEnumerable<Event> GetEvents() { return _events; } } public class Account { public Guid Id { get; private set; } public decimal Balance { get; private set; } public void Apply(Event evt) { if (evt.EventType == "Deposit") { Balance += decimal.Parse(evt.Data); } else if (evt.EventType == "Withdrawal") { Balance -= decimal.Parse(evt.Data); } } } var eventStore = new EventStore(); var account = new Account(); var depositEvent = new Event { Id = Guid.NewGuid(), Timestamp = DateTime.UtcNow, EventType = "Deposit", Data = "100.00" }; eventStore.Save(depositEvent); account.Apply(depositEvent);
ASP.NET Core Identity is a membership system for managing user authentication and authorization. It supports user registration, password recovery, role management, and external login providers.
Example:
public void ConfigureServices(IServiceCollection services) { services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))); services.AddIdentity<IdentityUser, IdentityRole>() .AddEntityFrameworkStores<ApplicationDbContext>() .AddDefaultTokenProviders(); services.AddControllersWithViews(); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Home/Error"); app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); }); }
.NET supports cross-platform development through:
JWT (JSON Web Token) authentication secures APIs by issuing a token upon successful authentication, which the client includes in subsequent requests. The server validates the token to ensure authentication.
Example:
public void ConfigureServices(IServiceCollection services) { services.AddAuthentication(options => { options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidateAudience = true, ValidateLifetime = true, ValidateIssuerSigningKey = true, ValidIssuer = "yourIssuer", ValidAudience = "yourAudience", IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("yourSecretKey")) }; }); services.AddControllers(); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); } public string GenerateJwtToken(string username) { var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("yourSecretKey")); var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256); var token = new JwtSecurityToken( issuer: "yourIssuer", audience: "yourAudience", expires: DateTime.Now.AddMinutes(120), signingCredentials: credentials); return new JwtSecurityTokenHandler().WriteToken(token); }
Rate limiting controls incoming requests to a server within a specified time window, preventing abuse and ensuring fair resource usage. It can be implemented using middleware.
Example:
public class RateLimitingMiddleware { private readonly RequestDelegate _next; private static Dictionary<string, (DateTime, int)> _clients = new Dictionary<string, (DateTime, int)>(); private readonly int _limit = 100; private readonly TimeSpan _timeWindow = TimeSpan.FromMinutes(1); public RateLimitingMiddleware(RequestDelegate next) { _next = next; } public async Task InvokeAsync(HttpContext context) { var clientIp = context.Connection.RemoteIpAddress.ToString(); if (_clients.ContainsKey(clientIp)) { var (lastRequestTime, requestCount) = _clients[clientIp]; if (DateTime.UtcNow - lastRequestTime < _timeWindow) { if (requestCount >= _limit) { context.Response.StatusCode = 429; return; } _clients[clientIp] = (lastRequestTime, requestCount + 1); } else { _clients[clientIp] = (DateTime.UtcNow, 1); } } else { _clients[clientIp] = (DateTime.UtcNow, 1); } await _next(context); } } public void Configure(IApplicationBuilder app, IHostingEnvironment env) { app.UseMiddleware<RateLimitingMiddleware>(); }