.NET Core
Interview Preparation Notes
- Cross-platform, open-source, high-performance framework for building modern apps.
- Unified platform (.NET 5+) for web, desktop, mobile, cloud, and microservices.
- CLR manages memory via GC, just-in-time compilation, and type safety.
SDK vs Runtime
- SDK: includes compilers, tools, and runtime to build apps.
- Runtime: to run apps only; no compilers/dev tools.
-
Program.cswith top-level statements (minimal hosting) in .NET 6+. -
appsettings.jsonfor configuration per environment. -
Use
dotnetCLI for creating, building, running, and publishing.
dotnet new webapi -n SampleApi
dotnet build
dotnet run
dotnet publish -c Release
IoC (Inversion of Control) Overview
- IoC is a principle where control of object creation and dependency resolution is delegated to an external component (a container) instead of being handled by the objects themselves.
- Promotes loose coupling, testability, and separation of concerns.
DI (Dependency Injection)
- DI is a specific way to implement IoC by supplying dependencies to a class (usually via constructor, sometimes via properties or methods) rather than creating them internally.
- ASP.NET Core includes a built-in IoC container to register and resolve services.
IoC vs DI
- IoC is the broader principle (who controls object creation and flow).
- DI is a concrete technique to achieve IoC by injecting dependencies.
Dependency Injection is the most common way to implement IoC, but other approaches include the Service Locator pattern, Factory pattern, Template Method pattern, and event-driven mechanisms. All of these shift control of object creation or execution flow away from the class itself.
Benefits
- Loose coupling and cleaner architecture.
- Easier unit testing and mocking (swap implementations).
- Centralized configuration of lifetimes and implementations.
Registration & Lifetimes
- Singleton — one instance for app lifetime.
- Scoped — one instance per request scope.
- Transient — new instance every resolution.
var builder = WebApplication.CreateBuilder(args);
// Register interfaces to implementations with lifetimes
builder.Services.AddSingleton<ICache, MemoryCacheImpl>();
builder.Services.AddScoped<IRepository, EfRepository>();
builder.Services.AddTransient<INotifier, EmailNotifier>();
var app = builder.Build();
app.Run();
Constructor Injection Example
public interface IGreeter { string Greet(string name); }
public class Greeter : IGreeter { public string Greet(string name) => $"Hello {name}"; }
// Registration
// builder.Services.AddScoped<IGreeter, Greeter>();
[ApiController]
[Route("api/[controller]")]
public class HelloController : ControllerBase
{
private readonly IGreeter _greeter;
public HelloController(IGreeter greeter) => _greeter = greeter;
[HttpGet("{name}")]
public string Get(string name) => _greeter.Greet(name);
}
Avoid Service Locator
- Prefer constructor injection over resolving services imperatively from
IServiceProviderwithin classes (service locator anti-pattern), which hides dependencies and complicates testing.
Examples of Dependency Injection
public interface IMessageService
{
void SendMessage(string message);
}
public class EmailService : IMessageService
{
public void SendMessage(string message)
{
Console.WriteLine("Email sent: " + message);
}
}
public class Notification
{
private readonly IMessageService _messageService;
// Dependency injected through constructor
public Notification(IMessageService messageService)
{
_messageService = messageService;
}
public void Notify(string message)
{
_messageService.SendMessage(message);
}
}
public class Notification
{
// Dependency injected through property
public IMessageService MessageService { get; set; }
public void Notify(string message)
{
MessageService.SendMessage(message);
}
}
public class Notification
{
// Dependency injected through method
public void Notify(IMessageService messageService, string message)
{
messageService.SendMessage(message);
}
}
-
Bind strongly-typed settings via
IOptions<T>/IOptionsMonitor<T>. - Support multiple configuration providers: JSON, env vars, user secrets, Azure Key Vault.
{
"Smtp": {
"Host": "smtp.example.com",
"Port": 587
}
}
builder.Services.Configure<SmtpOptions>(builder.Configuration.GetSection("Smtp"));
public class SmtpOptions { public string Host { get; set; } = ""; public int Port { get; set; } }
- Pipeline built from middleware: authentication, routing, endpoints, static files, etc.
-
Order matters: place
UseRouting()beforeUseEndpoints(), etc.
var app = builder.Build();
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
-
Attribute routing with tokens like
[Route("api/[controller]")]. -
Use
ApiControllerfor automatic 400 responses and binding behaviors.
[ApiController]
[Route("api/[controller]")]
public class UsersController : ControllerBase
{
[HttpGet("{id:int}")]
public ActionResult<UserDto> Get(int id) => Ok(new UserDto(id, "John"));
}
- Automatic binding from route, query, headers, and body to action parameters.
-
Use DataAnnotations like
[Required],[EmailAddress],[Range].
public record RegisterDto(
[property: Required, EmailAddress] string Email,
[property: Required, MinLength(6)] string Password);
Access Modifiers (Visibility/Accessibility)
- public — Accessible from anywhere.
- private — Accessible only within the containing type.
- protected — Accessible within the containing type and derived types.
- internal — Accessible within the same assembly.
- protected internal — Accessible from the same assembly OR from derived types in any assembly.
- private protected — Accessible from the containing type or its derived types in the same assembly.
public class A
{
private int x;
protected int y;
internal int z;
protected internal int p;
private protected int q;
}
public class B : A
{
void Test() {
// x not accessible (private)
y = 1; // protected OK
z = 2; // internal OK if same assembly
p = 3; // protected internal OK
q = 4; // private protected OK if same assembly
}
}
Non-Access Modifiers (Behavior/Semantics)
- static — Member/type belongs to the type itself; one shared instance.
- readonly — Field can be assigned only at declaration or in constructor.
- const — Compile-time constant; implicitly static; must be assigned at declaration.
- sealed — Class cannot be inherited; method cannot be overridden further.
- abstract — Incomplete class/member; must be implemented by derived classes.
- virtual — Member can be overridden in derived classes.
- override — Provides a new implementation of a virtual/abstract member.
- partial — Type/Method split across files; combined at compile time.
- ref/out/in — Parameter passing modifiers: by reference, output-only, by-ref readonly.
- async — Marks a method that contains await; returns Task/Task<T>/ValueTask.
public static class MathUtil
{
public const double Pi = 3.14159;
public static int Square(int x) => x * x;
}
public abstract class Animal
{
public abstract void Speak();
public virtual void Move() => Console.WriteLine("Moving...");
}
public sealed class Dog : Animal
{
public override void Speak() => Console.WriteLine("Woof");
public override void Move() => Console.WriteLine("Running...");
}
public class Sample
{
public readonly Guid Id = Guid.NewGuid();
public void Update(ref int a, out int b, in int c)
{
a += c;
b = a * 2; // out must be assigned
// c is readonly by-ref
}
public async Task<string> FetchAsync() => await Task.FromResult("ok");
}
ref, out, and in Parameters (Details)
These modifiers change how arguments are passed to methods in C#.
ref (Pass by reference)
- Caller must initialize the variable before passing.
- Callee can read and modify the caller’s variable.
- Useful when you need to return multiple values or mutate inputs.
void DoubleValue(ref int x) { x *= 2; }
int a = 10;
DoubleValue(ref a);
Console.WriteLine(a); // 20
out (Output parameter)
- Caller does not need to initialize the variable.
- Callee must assign the variable before the method returns.
- Ideal for try-style APIs returning multiple outputs.
bool TryParsePositive(string s, out int value)
{
if (int.TryParse(s, out var v) && v >= 0) { value = v; return true; }
value = 0; // must assign on all paths
return false;
}
if (TryParsePositive("42", out int n))
Console.WriteLine(n); // 42
in (Read-only reference)
- Passes the argument by reference but as read-only inside the method.
- Avoids copying large structs while preventing modification.
- Compiler may copy if needed to maintain readonly semantics.
readonly struct Point { public readonly int X, Y; public Point(int x, int y) { X = x; Y = y; } }
int DistanceSquared(in Point p) { return p.X * p.X + p.Y * p.Y; }
var p = new Point(3, 4);
Console.WriteLine(DistanceSquared(in p)); // 25
Choosing between ref vs out vs in
- ref: caller initializes; callee may read/write.
- out: caller need not initialize; callee must write.
- in: caller initializes; callee reads only (no writes).
1) Field in .NET
What is a Field? A field is a variable declared inside a class; it stores the internal state of an object.
private string name;
- Usually declared private
- Direct data storage (no validation)
- Used internally
Best Practice: Keep fields private and expose via properties.
2) Property in .NET
What is a Property? A property provides controlled access to a field.
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
- Looks like a variable but compiles to methods
- Supports validation, encapsulation, and controlled access
3) Auto-Property
public string Name { get; set; }
Internally the compiler generates:
private string <Name>k__BackingField;
public string get_Name() => <Name>k__BackingField;
public void set_Name(string value) => <Name>k__BackingField = value;
Auto-properties are syntactic sugar for a hidden backing field and getter/setter methods.
4) Property vs Field
- Field — Stores data directly; usually private; no validation.
- Property — Controls access to data; can add validation; usually public.
5) Property vs Method
Properties conceptually represent state; methods represent actions/behavior.
- Properties compile to methods, but are not conceptually “methods.”
- Use a property for fast access to state; use a method for heavier logic or actions.
emp.Name // Property (state)
emp.CalculatePay() // Method (behavior)
6) Avoid Infinite Recursion in Setters
// Wrong: causes recursion
public string Name
{
get => _name;
set => Name = value; // ❌ calls setter again, StackOverflowException
}
// Correct:
public string Name
{
get => _name;
set => _name = value; // use the field
}
7) Use of this Keyword
this is optional unless there’s a naming conflict.
public Employee(string name)
{
this.name = name; // disambiguates parameter vs field
}
// Equivalent without conflict:
_name = value; // or this._name = value;
8) What Happens Internally on Access
emp.Name = "Harmeet"; // compiles to: emp.set_Name("Harmeet");
var name = emp.Name; // compiles to: var name = emp.get_Name();
In IL you will see calls similar to callvirt set_Name and callvirt get_Name. Property access is a method call at runtime.
9) Why Properties Are Powerful
You can evolve logic without changing callers (encapsulation + maintainability).
// Initially
public string Name { get; set; }
// Later with validation
private string _name = "";
public string Name
{
get => _name;
set
{
if (value == null || value.Length < 3) throw new ArgumentException("Too short");
_name = value;
}
}
Core OOP Principles Practiced
- Encapsulation and abstraction
- Backing field concept
- CLR method generation for getters/setters
- Avoiding infinite recursion
Interview-Level Summary
In C#, fields store data, properties provide controlled access to fields, and methods define behavior. Although properties look like variables, they compile to getter and setter methods, so property access is a method call at runtime.
Generics enable type-safe classes, methods, interfaces, and delegates using type parameters. They improve reusability, performance (avoid boxing/casting), and compile-time safety.
Generic Class
public class Box<T>
{
public T Value { get; }
public Box(T value) => Value = value;
}
var intBox = new Box<int>(42);
var strBox = new Box<string>("hello");
Generic Method
public static T Max<T>(T a, T b) where T : IComparable<T>
{
return a.CompareTo(b) >= 0 ? a : b;
}
var m1 = Max(3, 7);
var m2 = Max("a", "b");
Constraints
where T : class(reference type),struct(value type)new()(public parameterless constructor)- Interfaces/types:
where T : IDisposable,where T : BaseType - Multiple constraints:
where T : class, new()
Common Generic Collections
List<T>,Dictionary<TKey, TValue>,HashSet<T>,Queue<T>,Stack<T>
var dict = new Dictionary<string, int> { ["a"] = 1, ["b"] = 2 };
if (dict.TryGetValue("a", out var val)) Console.WriteLine(val);
Generic Interfaces and Variance
out(covariant) for output positions;in(contravariant) for input positions.- Examples:
IEnumerable<out T>(covariant),IComparer<in T>(contravariant).
IEnumerable<string> strings = new List<string> { "a", "b" };
IEnumerable<object> objs = strings; // covariance works
Repository Pattern with Generics
public interface IRepository<T> where T : class
{
Task<T?> GetByIdAsync(Guid id);
Task AddAsync(T entity);
}
public class EfRepository<T> : IRepository<T> where T : class
{
private readonly DbContext _ctx;
public EfRepository(DbContext ctx) => _ctx = ctx;
public Task<T?> GetByIdAsync(Guid id) => _ctx.Set<T>().FindAsync(id).AsTask();
public async Task AddAsync(T entity) { await _ctx.Set<T>().AddAsync(entity); }
}
Interview Tip: Use constraints to express requirements on type parameters, and prefer generic collections to avoid boxing/casting and improve performance.
What are Attributes?
Attributes are metadata annotations applied to code elements (assemblies, types, members, parameters, return values) to influence behavior at compile time or runtime via frameworks and reflection.
Applying Attributes
[Serializable]
public class Person
{
[Required, StringLength(50)]
public string Name { get; set; } = string.Empty;
[Range(0, 120)]
public int Age { get; set; }
}
Common Built-in Attributes
- DataAnnotations:
[Required],[StringLength],[Range],[EmailAddress]. - ASP.NET Core MVC:
[ApiController],[HttpGet],[FromBody],[FromQuery],[Authorize]. - Serialization:
[JsonPropertyName](System.Text.Json),[JsonIgnore]. - Interoperability:
[DllImport],[MarshalAs]. - Diagnostics:
[Conditional],[Obsolete].
Create a Custom Attribute
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = false, AllowMultiple = true)]
public sealed class AuditAttribute : Attribute
{
public string Action { get; }
public AuditAttribute(string action) => Action = action;
}
[Audit("CreateUser")]
public class UserService
{
[Audit("ResetPassword")]
public void Reset(string userId) { /* ... */ }
}
Read Attributes via Reflection
var method = typeof(UserService).GetMethod("Reset");
var audits = method?.GetCustomAttributes(typeof(AuditAttribute), inherit: false)
.Cast<AuditAttribute>();
foreach (var a in audits!) Console.WriteLine(a.Action);
Conditional and Obsolete
[Conditional("DEBUG")]
static void DebugLog(string msg) => Console.WriteLine(msg); // removed from release builds
[Obsolete("Use NewMethod instead.", error: false)]
public void OldMethod() { /* ... */ }
Interview Tip: Attributes provide declarative metadata that frameworks (e.g., ASP.NET Core, EF Core, serializers) use to alter behavior without changing imperative code; custom attributes plus reflection enable cross-cutting concerns like auditing and validation.
Typecasting converts a value from one type to another. In C#, casts can be implicit (safe, no data loss) or explicit (may lose data or fail at runtime for references).
Implicit vs Explicit (Numeric Examples)
int i = 42;
long l = i; // implicit widening
double d = l; // implicit
double dx = 3.14;
int ix = (int)dx; // explicit narrowing (3, truncates)
Reference Types: Upcasting vs Downcasting
- Upcasting: Cast from derived to base. Always safe; often implicit.
- Downcasting: Cast from base to derived. Requires runtime check; can throw InvalidCastException if incompatible.
class Animal { public virtual void Speak() => Console.WriteLine("Animal"); }
class Dog : Animal { public override void Speak() => Console.WriteLine("Dog"); }
Dog dog = new Dog();
Animal a = dog; // upcasting (implicit)
a.Speak(); // "Dog" due to virtual dispatch
// Downcasting
Dog d2 = (Dog)a; // explicit; OK because 'a' actually refers to Dog
// Dog d3 = (Dog)new Animal(); // throws InvalidCastException
Safe Downcasting: as and is
Animal a2 = GetAnimal();
Dog? maybeDog = a2 as Dog; // returns Dog reference or null
if (maybeDog != null) maybeDog.Speak();
// C# pattern matching with 'is'
if (a2 is Dog d4) d4.Speak();
Boxing/Unboxing
- Boxing: Value type → object heap allocation.
- Unboxing: object → value type; requires explicit cast and correct type.
int v = 10;
object o = v; // boxing
int v2 = (int)o; // unboxing (must match original value type)
Convert Class vs Cast Operators
(T)expruses language/runtime casting rules; for numeric, truncates/overflows unless checked; for references, runtime type check.Convert.ToInt32,Convert.ToDouble, etc., support conversions from strings and other types with culture/format handling.
string s = "123";
int n = Convert.ToInt32(s); // parses string
try {
int bad = (int)(object)3.5; // InvalidCastException: cannot unbox double to int
} catch (InvalidCastException) { /* handle */ }
User-defined Conversions
Types can define implicit and explicit operators to customize casting behavior.
struct Celsius
{
public double Value;
public Celsius(double v) => Value = v;
public static implicit operator Celsius(double v) => new Celsius(v);
public static explicit operator double(Celsius c) => c.Value;
}
Celsius c = 25.0; // implicit from double
double temp = (double)c; // explicit to double
Interview Tip: Prefer is/as (or pattern matching) for safe reference casts; be mindful of boxing with generics/collections; use user-defined conversions sparingly with clear semantics.
- ORM for data access with LINQ; supports migrations and change tracking.
- DbContext configured via DI; providers: SQL Server, SQLite, PostgreSQL, etc.
builder.Services.AddDbContext<AppDbContext>(o =>
o.UseSqlServer(builder.Configuration.GetConnectionString("Default")));
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions options) : base(options) {}
public DbSet<User> Users => Set<User>();
}
3. How do you perform migrations in EF?
For EF Core, you can use either the Package Manager Console (PMC) or the .NET CLI to manage migrations.
- PMC:
Add-Migration InitialCreate,Update-Database - CLI:
dotnet ef migrations add InitialCreate,dotnet ef database update
For EF6 (the classic Entity Framework for .NET Framework), migrations are handled via the Package Manager Console only.
-
Use async/await to free threads; avoid blocking with
.Result/.Wait(). -
Use
CancellationTokenfor cooperative cancellation.
[HttpGet]
public async Task<IEnumerable<UserDto>> GetAll(CancellationToken ct) =>
await _svc.GetUsersAsync(ct);
- Built-in logging abstractions with providers (Console, Debug, Seq, Application Insights).
- Use scopes and structured logging for richer context.
public class UsersController(ILogger<UsersController> logger) : ControllerBase
{
[HttpGet]
public IActionResult Get() {
using (logger.BeginScope("RequestId:{RequestId}", Guid.NewGuid())) {
logger.LogInformation("Fetching users");
return Ok(Array.Empty<string>());
}
}
}
What is a Delegate?
A delegate is a type-safe function pointer. It encapsulates a reference to a method with a particular signature, enabling callbacks, event handling, and functional composition.
Delegate is a representative to communicate between two parties.
How Delegates Work Internally
- A delegate is a sealed class derived from
System.MulticastDelegate. - It stores a target (object for instance methods or null for static) and a method pointer.
- Multicast delegates maintain an invocation list (array) of method references; invoking the delegate iterates through this list in order.
- For non-void return types in a multicast delegate, the return value of the last method is observed; prior results are ignored.
- Delegates support covariance (return type can be more derived) and contravariance (parameter types can be less derived).
// Custom delegate type
public delegate int MathOp(int a, int b);
// Methods matching the signature
static int Add(int x, int y) => x + y;
static int Sub(int x, int y) => x - y;
// Create and invoke
MathOp op = Add;
Console.WriteLine(op(2, 3)); // 5
// Reassign
op = Sub;
Console.WriteLine(op(5, 2)); // 3
Multicast Delegates
Action pipeline = () => Console.WriteLine("Step 1");
pipeline += () => Console.WriteLine("Step 2");
pipeline += () => Console.WriteLine("Step 3");
pipeline(); // Invokes all three steps in order
Generic Delegates
- Action<T...> — encapsulates a method that returns void.
- Func<T..., TResult> — encapsulates a method that returns a value.
- Predicate<T> — shorthand for
Func<T, bool>.
Func<int, int, int> mul = (a, b) => a * b;
Action<string> log = msg => Console.WriteLine(msg);
Predicate<string> hasAt = s => s != null && s.Contains('@');
Console.WriteLine(mul(3, 4)); // 12
log("Hello");
Console.WriteLine(hasAt("user@example.com")); // True
Delegates and Events
Events provide publish/subscribe built on delegates; only the declaring type can raise the event, while consumers subscribe via +=.
public class Button
{
public event EventHandler? Click;
public void RaiseClick() => Click?.Invoke(this, EventArgs.Empty);
}
var btn = new Button();
btn.Click += (s, e) => Console.WriteLine("Clicked!");
btn.RaiseClick();
Behind the Scenes (Conceptual)
// Delegate instance conceptually holds:
// - object? _target
// - IntPtr _methodPtr
// - Delegate[]? _invocationList (for multicast)
// Invocation effectively loops through the invocation list:
// foreach (var d in invocationList) d.Invoke(args);
Interview Tip: Prefer built-in generic delegates (Action/Func/Predicate) and lambdas for clarity; use custom delegates when naming conveys strong intent.
- Use xUnit/NUnit/MSTest for unit tests; Moq/NSubstitute for mocking.
- WebApplicationFactory enables integration testing of minimal APIs and MVC.
public class ApiTests : IClassFixture<WebApplicationFactory<Program>>
{
private readonly HttpClient _client;
public ApiTests(WebApplicationFactory<Program> factory) => _client = factory.CreateClient();
[Fact]
public async Task Get_ReturnsOk() {
var res = await _client.GetAsync("/weatherforecast");
res.EnsureSuccessStatusCode();
}
}
- Use ASP.NET Core Identity or external providers (JWT/OAuth/OpenID Connect).
- Protect APIs with authentication/authorization policies and role-based access.
builder.Services
.AddAuthentication("Bearer")
.AddJwtBearer("Bearer", o => {
o.Authority = "https://auth.example.com";
o.Audience = "api";
});
app.UseAuthentication();
app.UseAuthorization();
https://www.youtube.com/watch?v=rUtWgEs07eI
Scaffolding in .NET (especially ASP.NET Core) automatically generates code for common CRUD operations, controllers, views, and UI pages based on your models. It speeds up development by providing a ready-to-use skeleton you can customize.
Scaffolding automates creation of:
- Controllers – Handle HTTP requests and responses.
- Views – Razor Pages or MVC Views for listing, editing, creating, and deleting records.
- Data Access Code – Can include DbContext and model binding if needed.
- CRUD Methods – Pre-built methods for Create, Read, Update, Delete operations.
Essentially, it creates a template structure based on your models. By providing Models as input, you can generate controller and views code.
In ASP.NET Core, scaffolding can generate:
- MVC scaffolding → Multiple views + centralized controller → Better for complex applications.
- Razor Pages scaffolding → Each page has its own code-behind → Simpler for page-focused applications.
- RESTful API scaffolding → Generates API controllers with CRUD endpoints.
Razor Pages
MVC and Razor Pages are two different approaches (they can be used together). MVC is an architectural pattern, whereas Razor Pages is a framework feature/programming model.
Razor Pages is a page-based programming model in ASP.NET Core that simplifies building web apps compared to traditional MVC.
Razor Pages are .cshtml files (views) with an associated
Page Model (.cshtml.cs) that contains the C# code. They
combine UI and logic for a single page in a self-contained structure,
ideal for simple CRUD or page-focused applications.
Each Razor Page has two parts:
.cshtml→ HTML and Razor markup (the view).cshtml.cs→ Page Model (code-behind)
DbContext (EF Core)
In ASP.NET Core with Entity Framework (EF) Core, a
DbContext manages your database connection and
operations—the bridge between your app code and the database.
-
Definition — Represents a session with the
database, enables querying/saving, and tracks changes for
persistence. Implement by creating a class inheriting from
DbContext. -
Key Components
-
DbSet<T>— Represents a table; each DbSet corresponds to an entity/model. -
OnModelCreating(optional) — Configure relationships/constraints via Fluent API.
-
.NET Authentication (Built-in)
.NET provides built-in support for three common authentication mechanisms:
-
Individual User Accounts
- Classic form-based authentication using ASP.NET Core Identity.
- Features: registration, login, password hashing, email confirmation, password reset, roles.
- Use case: Consumer apps where users create accounts (blogs, e-commerce, portals).
- How it works: Credentials verified by Identity → cookie issued for session; user data stored in DB.
-
Microsoft Identity Platform (Azure AD)
- Users log in with Microsoft work/school accounts.
- Features: SSO, MFA, Microsoft Graph integration, OAuth 2.0/OpenID Connect tokens.
- Use case: Enterprise/internal applications.
- How it works: App redirects to Microsoft login → token returned → app calls APIs securely.
-
Windows Authentication
- Uses existing Windows credentials (Active Directory); no login form.
- Features: Kerberos/NTLM; suitable for intranet apps.
- Use case: Internal tools within the same domain/network.
- How it works: Browser sends Windows credentials → verified against AD → user logged in.
ADO.NET vs Code-First vs Database-First
ADO.NET requires manual SQL and data handling—fine-grained control but more boilerplate.
Entity Framework Code-First defines the database with C# classes, automates CRUD and migrations, and improves maintainability.
Entity Framework Database-First starts from an
existing DB—EF generates models and DbContext from
schema. Relationships/keys are scaffolded; DB changes require
regenerating/updating models. CRUD via EF similar to Code-First.
Visual Studio provides an in-built database designer to create a DB and generate entity models.
How to use Visual Studio Database Designer (SQL Server)
- Create a database using “SQL Server Database Project” or use an existing one.
- To create a new DB: File → New → Project → SQL Server Database Project.
| .NET Core vs .NET Framework | ||
|---|---|---|
| Feature | .NET Framework | .NET Core |
| Platform support | Windows only | Cross-platform (Windows, Linux, macOS) |
| Type of apps | Web Forms, WPF, WinForms, ASP.NET MVC | ASP.NET Core, Console apps, Microservices, Cloud apps |
| Open Source | Partially | Fully open source (on GitHub) |
| Performance | Slower (IIS dependent) | Faster, modular, lightweight |
| Deployment | Installed system-wide | Self-contained, per-app deployment possible |
| CLI support | Limited | Full CLI (dotnet) support |
| Versioning | System-wide | Per-application, avoids version conflicts |
| Web Server | IIS only | Kestrel (built-in), can run behind IIS/Nginx/Apache |
| Modern Development | Not evolving (last 4.8) | .NET (.NET 6/7/8): Actively evolving |
1) Which .NET version are you using?
Ans — .NET 6 (LTS). .NET 6 released Nov 9, 2021; .NET 8 (LTS) released Nov 14, 2023.
2) What is Dependency Injection (DI) and how does it work?
Explain DI as providing dependencies to classes via constructors or properties, managed by the built-in IoC container registered in Program.cs using service lifetimes.
3) Explain Transient vs Scoped vs Singleton DI
-
AddTransient — An instance is created every time the service is requested.
The instance is not stored; each request/consumer gets a fresh instance,
even within the same HTTP request.
When to use (Lifecycle Examples):- Lightweight, stateless services.
- Business logic calculators.
- Email/SMS sender services.
- Mapping/Transformation services (e.g., DTO mappers).
// Registration services.AddTransient(); // Every injection gets a new instance public class OrderService { private readonly IEmailService _email; public OrderService(IEmailService email) { _email = email; } } -
AddScoped — A single instance is created per request scope.
The same instance is reused for the duration of a single HTTP request.
When to use (Lifecycle Examples):- Database contexts (e.g., DbContext).
- Unit of Work pattern.
- Services that maintain request-specific state.
- Repository layer services.
// Registration services.AddScoped(); // Same instance used throughout one HTTP request public class OrderController : ControllerBase { private readonly IOrderRepository _repo; public OrderController(IOrderRepository repo) { _repo = repo; } } -
AddSingleton — A single instance is utilized for the lifetime of the application.
This instance is reused across all requests.
When to use (Lifecycle Examples):- Configuration services.
- Logging services.
- In-memory caching services.
- Application-wide shared state.
// Registration services.AddSingleton(); // Same instance shared across entire app lifetime public class ProductService { private readonly ICacheService _cache; public ProductService(ICacheService cache) { _cache = cache; } }
The mentioned three lifetimes control how long service instances exist in ASP.NET Core DI. Choosing the correct lifetime is critical to avoid memory leaks, threading issues, or unintended shared state.
4) How do you change object values in DI when required?
Use options pattern (IOptionsMonitor<T>) for config reloads, or inject a factory (IServiceProvider or custom Func<T>) to resolve fresh instances; for scoped state, use scoped services or IMemoryCache.
5) How do you handle exceptions in .NET Core APIs?
- Try–Catch — Local handling within actions or services to return meaningful errors.
- Custom Middleware — Centralized global handler to standardize error responses and logging.
- UseExceptionHandler() — Built-in global handler routing errors to a specific endpoint.
6) What is middleware and its uses?
Requests pass through a sequence of middleware; each can process the request, call the next middleware, or short-circuit. Responses flow back in reverse order.
- Common uses: Authentication/Authorization, Logging, Exception handling, CORS, Static files, Localization.
7) How do you classify exceptions and create custom exceptions?
Exceptions are runtime errors derived from System.Exception. System exceptions are predefined (e.g., NullReferenceException, FileNotFoundException). Custom exceptions derive from Exception for domain-specific errors.
8) Which Entity Framework approach do you use? (Database First / Code First)
Answer based on project: Code-First for greenfield with migrations; Database-First for existing schemas.
9) How do you write queries – LINQ, raw SQL, or other approaches?
LINQ describes the data shape (filters, sorts, joins) while the ORM (EF) translates LINQ into SQL and executes it. Use raw SQL for complex or performance-critical cases.
we can write with LINQ , LINQ provides the language for writing queries, ORM (like Entity Framework) provides the engine that runs those queries on the database. LINQ --- Describes what data you want in a query (e.g., filtering, sorting, joining). ORM (EF) -- Executes that query against the database by converting LINQ expressions into SQL.- Is
abstractkeyword there? - Difference between value type and reference type in C#?
- Difference between
IEnumerable,IQueryableandList? - How are encapsulation, inheritance etc. implemented?
readonlykeyword kya kaam karta hai?- Class me jab koi property, method, field kya hoti hai? Aur class me agar aap koi field banate ho to uska access specifier kya hota hai?
- Pipeline sequence, API integration.
- https://www.youtube.com/watch?v=8xcIy9cV-6g
- Add about
statickeyword. - Scenario-based questions in .NET.
- .net questions
- abstract vs interface delegate vs events stored procedure vs functions primary key vs unique key static vs singleton ref vs out clustered vs nonClustered string vs stringBuffer Boxing vs unBoxing Ienumerable vs iqueryable delete vs truncate tread vs task == vs equal overloading vs overriding var vs dynamic union vs union all lazy vs eager loading array vs arrayList encapsulation vs abstract concurent parallel temp tables vs CTE normal collection vs generics struct vs class filters vs middlewear property vs variable throw vs throw ex
- https://www.linkedin.com/posts/praveen-r-820a921b6_what-dot-net-interviews-actually-focus-share-7441405795436666880--Seh?utm_source=share&utm_medium=member_android&rcm=ACoAACv5yREBv9N0r8wAMG8gFLfkAuo8i3ewF6g