Launch offer
Business website $150 USD Custom plugin $200 USD Ready in 5 days
Get a quote
C#

C# Complete Tutorial (121 Topics with .NET, EF Core, ASP.NET Core & Final Project)

Complete C# tutorial covering language fundamentals, OOP, LINQ, async, EF Core, ASP.NET Core Web APIs, security, testing, and a final ASP.NET Core application project.

This complete C# tutorial covers 121 topics — from language fundamentals and OOP to LINQ, async, EF Core, ASP.NET Core Web APIs, and a final full-stack style .NET application project.

Course roadmap

1. Introduction to C#

C# is a modern, strongly typed language on .NET used for web APIs, desktop apps, games, and cloud services. This series covers syntax, OOP, collections, LINQ, async, EF Core, ASP.NET Core, and a complete final project.

  1. Install .NET SDK and run Hello World.
  2. Learn OOP, LINQ, and async.
  3. Build the final ASP.NET Core application.

Learning path

Setup + first program
Types + OOP + collections
LINQ + async + files
EF Core + ASP.NET Core Web API
Auth, testing, security
Final ASP.NET Core app

2. What is C#?

C# combines strong typing, productive tooling, and a large BCL (Base Class Library) for building reliable applications.

C# at a glance

Strongly typed
OOP + modern features
Runs on .NET
Web, desktop, cloud, games

3. Features of C#

Modern C# includes records, pattern matching, nullable reference types, and top-level statements.

Feature highlights

Garbage collection
Properties / events
LINQ
async/await
Generics
Pattern matching
Nullable reference types

4. C# vs C++ vs Java

C# and Java are managed runtimes; C++ is typically unmanaged with manual/RAII memory control.

Quick compare

C++ → performance control, manual/RAII memory
Java → JVM ecosystem
C# → .NET ecosystem, modern language features
All → OOP capable

5. .NET and C# Relationship

.NET provides the runtime, BCL, and app models; C# is the primary language for many .NET apps.

.NET stack

C# source
→ Roslyn compiler
→ IL
→ .NET runtime (JIT/AOT)
→ BCL + packages

6. Installing .NET SDK

The SDK includes the runtime and CLI for creating/building/running projects.

  1. Download/install .NET SDK.
  2. Verify with dotnet –version.
  3. Create a sample console app.

Verify SDK

dotnet --version
dotnet --info

7. Setting Up Visual Studio / VS Code for C#

Use the IDE for IntelliSense, debugging, and test runners.

Setup tip

Visual Studio → workloads for .NET
VS Code → C# extension / Dev Kit
dotnet new / build / run in terminal

8. First C# Program

Confirm tooling works before learning language details.

  1. Run dotnet new console.
  2. Open Program.cs.
  3. dotnet run.

Hello World

Console.WriteLine("Hello, C#!");

9. C# Project Structure

SDK-style projects keep configuration concise in the .csproj file.

Project pieces

.csproj
Program.cs
Namespaces / folders
appsettings.json (web)
Properties/

10. Compilation and Execution in C#

`dotnet build` compiles; `dotnet run` builds and executes.

CLI

dotnet build
dotnet run
dotnet publish -c Release

11. C# Syntax

Prefer clear names and consistent formatting (dotnet format / IDE).

Syntax sample

var count = 10;
if (count > 0)
{
    Console.WriteLine("positive");
}

12. Comments in C#

Use /// for public API documentation.

Comments

// Single line
/* Multi-line */
/// <summary>Adds two numbers.</summary>

13. Variables and Constants in C#

Prefer meaningful names; use readonly for instance immutability after construction.

Variables

int count = 0;
const double Pi = 3.14159;
readonly string id;

14. Data Types in C#

Know aliases (int → System.Int32) and when to use decimal for money.

Common types

int, long, double, decimal, bool, char
string, object
DateTime, Guid
Custom classes/structs/records

15. Value Types vs Reference Types in C#

Structs/enums are value types; classes/interfaces/delegates are reference types (with nuances).

Mental model

Value → copy data
Reference → copy reference
string is reference but immutable
Careful with mutable structs

16. Type Casting in C#

Prefer pattern matching `is` checks over risky casts.

Casting

double d = 3.7;
int n = (int)d; // 3
if (obj is string s) Console.WriteLine(s);

17. Nullable Types in C#

Use HasValue/Value or null-coalescing carefully.

Nullable

int? age = null;
int years = age ?? 0;

18. Input and Output in C#

For apps, prefer structured logging over Console in production services.

Console I/O

Console.Write("Name: ");
var name = Console.ReadLine();
Console.WriteLine($"Hello, {name}");

19. Operators in C#

Null-conditional ?. and null-coalescing ?? are everyday tools.

Operator groups

Arithmetic
Comparison
Logical
Assignment
Bitwise
?? / ??= / ?.

20. Arithmetic Operators in C#

Prefer decimal for currency math.

Arithmetic

var q = 10 / 3;   // 3
var r = 10 % 3;   // 1
var f = 10.0 / 3; // ~3.33

21. Comparison Operators in C#

For strings, be aware of culture/ordinal comparison choices.

Comparison

if (score >= 50) { /* pass */ }
string.Equals(a, b, StringComparison.OrdinalIgnoreCase);

22. Logical Operators in C#

Useful for guard clauses.

Logical

if (user is not null && user.IsActive)
{
    /* ... */
}

23. Assignment Operators in C#

??= assigns only when null.

Assignment

var n = 5;
n += 2;
name ??= "Guest";

24. Bitwise Operators in C#

Common for flags enums.

Bitwise / flags tip

[Flags] enum Perms { None = 0, Read = 1, Write = 2 }
var p = Perms.Read | Perms.Write;

25. Null-Coalescing Operators in C#

Helps write concise null-tolerant code.

Null operators

var city = user?.Address?.City ?? "Unknown";
cache ??= new Dictionary<string, int>();

26. Conditional Operator in C#

Prefer clarity over clever nesting.

Ternary

var label = score >= 50 ? "Pass" : "Retry";

27. Conditional Statements in C#

Use early returns to keep methods flat.

Branching tools

if / else if / else
switch / switch expressions
pattern matching

28. if, else if and else in C#

Brace consistently for maintainability.

if/else

if (temp >= 30) Console.WriteLine("Hot");
else if (temp >= 20) Console.WriteLine("Warm");
else Console.WriteLine("Cool");

29. switch Statement in C#

Switch expressions are concise for mapping values.

Switch expression

var label = status switch
{
    "paid" => "Completed",
    "pending" => "Waiting",
    _ => "Other"
};

30. Pattern Matching in C#

Patterns reduce casting and nested conditionals.

Pattern

if (shape is Circle { Radius: > 0 } c)
{
    Console.WriteLine(c.Radius);
}

31. Loops in C#

foreach is preferred for collections when you don’t need indexes.

Loop choices

for → indexes
foreach → sequences
while / do-while → conditions
LINQ → declarative transforms

32. for Loop in C#

Be careful with bounds and off-by-one errors.

for

for (var i = 0; i < items.Length; i++)
{
    Console.WriteLine(items[i]);
}

33. while Loop in C#

Ensure termination conditions are reachable.

while

var n = 3;
while (n > 0)
{
    Console.WriteLine(n);
    n--;
}

34. do-while Loop in C#

Useful for menus and retry prompts.

do-while

int choice;
do {
    Console.WriteLine("1) Run  0) Quit");
    int.TryParse(Console.ReadLine(), out choice);
} while (choice != 0);

35. foreach Loop in C#

Don’t modify a collection while enumerating it (unless using safe patterns).

foreach

foreach (var item in items)
{
    Console.WriteLine(item);
}

36. break and continue in C#

Use sparingly for readability.

break/continue

foreach (var n in nums)
{
    if (n < 0) continue;
    if (n == 0) break;
    Console.WriteLine(n);
}

37. Methods in C#

Instance methods vs static methods; keep methods focused.

Method

static int Add(int a, int b) => a + b;

38. Method Parameters in C#

Prefer returning values over many out params.

Parameters

void Swap(ref int a, ref int b) => (a, b) = (b, a);
bool TryParseAge(string s, out int age) => int.TryParse(s, out age);

39. Return Values in C#

Expression-bodied members keep simple returns concise.

Return / tuple

(int min, int max) Range(int[] a) => (a.Min(), a.Max());

40. Method Overloading in C#

Return type alone cannot overload.

Overload

int Add(int a, int b) => a + b;
double Add(double a, double b) => a + b;

41. Optional Parameters in C#

Defaults must be compile-time constants (with some exceptions).

Optional

void Greet(string name = "Guest") => Console.WriteLine($"Hi {name}");

42. Named Arguments in C#

Especially helpful with multiple optional booleans.

Named args

CreateUser(name: "Asha", isAdmin: false);

43. Params Keyword in C#

params must be the last parameter.

params

int Sum(params int[] values) => values.Sum();
var total = Sum(1, 2, 3, 4);

44. Recursion in C#

Watch stack depth; prefer iterative/LINQ when simpler.

Recursion

long Factorial(int n) => n <= 1 ? 1 : n * Factorial(n - 1);

45. Arrays in C#

Prefer List<T> when size changes frequently.

Array

int[] scores = { 90, 85, 88 };
Console.WriteLine(scores.Length);

46. Multidimensional Arrays in C#

Jagged arrays are arrays of arrays — flexible but different memory layout.

2D array

int[,] grid = { { 1, 2 }, { 3, 4 } };

47. Strings in C#

Concatenation in loops should use StringBuilder.

String

string name = "Asha";
string hi = "Hello, " + name;

48. String Methods in C#

Prefer ordinal/invariant comparisons when appropriate.

String methods

var parts = "a,b,c".Split(',');
var ok = email.Contains('@', StringComparison.Ordinal);

49. String Interpolation in C#

Use raw string literals (modern C#) for multi-line text when helpful.

Interpolation

var msg = $"Order #{id} total={total:C}";

50. StringBuilder in C#

Ideal inside loops and serializers.

StringBuilder

var sb = new StringBuilder();
foreach (var w in words) sb.Append(w).Append(' ');
var text = sb.ToString();

51. Classes and Objects in C#

Prefer small classes with clear responsibilities.

Class

class User
{
    public string Name { get; set; } = "";
    public void Greet() => Console.WriteLine($"Hi {Name}");
}

52. Constructors in C#

Validate inputs; prefer required properties / init where suitable.

Constructor

class User
{
    public User(string name) => Name = name;
    public string Name { get; }
}

53. Destructors in C#

Don’t rely on destructors for timely resource cleanup — implement Dispose.

Cleanup tip

Prefer IDisposable / using
Finalizers are non-deterministic
SafeHandle for unmanaged resources

54. Properties in C#

Auto-properties keep code concise; add logic when validating.

Properties

public string Email { get; set; } = "";
public string Id { get; init; } = Guid.NewGuid().ToString("N");

55. Fields in C#

Prefer private fields with underscore naming if your style guide uses it.

Field

private readonly List<string> _items = new();

56. Access Modifiers in C#

Default for class members is private.

Modifiers

public
private
protected
internal
protected internal
private protected

57. Encapsulation in C#

Validate in setters/methods to protect invariants.

Encapsulation tip

Private fields
Public properties/methods
Validate inputs
Minimize mutable surface

58. Inheritance in C#

C# supports single class inheritance + multiple interfaces.

Inheritance

class Animal { public virtual void Speak() {} }
class Dog : Animal { public override void Speak() => Console.WriteLine("Woof"); }

59. Types of Inheritance in C#

Prefer composition when deep hierarchies get brittle.

Inheritance style

Single class inheritance
Interface implementation (many)
Composition over deep trees

60. Polymorphism in C#

Interfaces enable polymorphism without a shared class base.

Polymorphism

Animal a = new Dog();
a.Speak();

61. Method Overriding in C#

Use sealed override to stop further overriding.

override

public override void Speak() => Console.WriteLine("Woof");

62. Virtual and Override in C#

new hides members (different from override) — avoid accidental hiding.

virtual tip

virtual → can override
override → replace virtual/abstract
abstract → must override
new → hide (careful)

63. Abstract Classes in C#

Cannot instantiate abstract classes; derived types must implement abstracts.

Abstract

abstract class Shape
{
    public abstract double Area();
}

64. Interfaces in C#

Default interface methods exist but use carefully for API evolution.

Interface

interface ILogger { void Log(string message); }
class ConsoleLogger : ILogger
{
    public void Log(string message) => Console.WriteLine(message);
}

65. Sealed Classes in C#

Sealing can clarify design and enable some optimizations.

Sealed

sealed class PaymentService { /* ... */ }

66. Static Classes and Members in C#

Static classes cannot be instantiated; watch thread-safety for static mutable state.

Static

static class MathUtil
{
    public static int Square(int n) => n * n;
}

67. Structs in C#

Prefer readonly struct for immutable values; avoid large mutable structs.

Struct

readonly struct Point(int X, int Y);

68. Enums in C#

Use [Flags] for bit fields; don’t assume contiguous values in loops blindly.

Enum

enum Status { Pending, Paid, Cancelled }

69. Records in C#

Records give value-based equality and with-expressions.

Record

record User(string Id, string Email);
var u2 = u1 with { Email = "new@example.com" };

70. Generics in C#

Constraints (where T : …) communicate requirements.

Generic idea

T Max<T>(T a, T b) where T : IComparable<T>
    => a.CompareTo(b) >= 0 ? a : b;

71. Generic Classes in C#

Generics power List<T>, Dictionary<TKey,TValue>, and your domain containers.

Generic class

class Box<T>
{
    public Box(T value) => Value = value;
    public T Value { get; }
}

72. Generic Methods in C#

Type inference usually supplies T at the call site.

Generic method

void PrintAll<T>(IEnumerable<T> items)
{
    foreach (var i in items) Console.WriteLine(i);
}

73. Collections in C#

Choose List, Dictionary, HashSet, Queue, Stack by access pattern.

Collection map

List → sequence
Dictionary → key/value
HashSet → unique set
Queue/Stack → FIFO/LIFO

74. List<T> in C#

The most common collection for app code.

List

var items = new List<string> { "a", "b" };
items.Add("c");

75. Dictionary in C#

Use TryGetValue to avoid KeyNotFoundException.

Dictionary

var ages = new Dictionary<string, int> { ["Asha"] = 30 };
if (ages.TryGetValue("Asha", out var age)) Console.WriteLine(age);

76. HashSet in C#

Great for dedupe and membership tests.

HashSet

var set = new HashSet<int> { 1, 2, 2 };
Console.WriteLine(set.Count); // 2

77. Queue in C#

Enqueue/Dequeue/Peek are core operations.

Queue

var q = new Queue<string>();
q.Enqueue("job1");
var next = q.Dequeue();

78. Stack in C#

Useful for undo stacks and depth-first algorithms.

Stack

var st = new Stack<int>();
st.Push(1);
var top = st.Pop();

79. LINQ in C#

LINQ works over IEnumerable in-memory and IQueryable providers (EF).

LINQ method syntax

var adults = people.Where(p => p.Age >= 18).Select(p => p.Name).ToList();

80. LINQ Query Syntax in C#

Method syntax and query syntax compile to similar calls — pick readable style.

Query syntax

var q =
    from p in people
    where p.Age >= 18
    orderby p.Name
    select p.Name;

81. Lambda Expressions in C#

Captures close over variables — know closure lifetime implications.

Lambda

Func<int, int> square = x => x * x;
var evens = nums.Where(n => n % 2 == 0);

82. Delegates in C#

Delegates underpin events and callbacks.

Func/Action

Action<string> log = Console.WriteLine;
Func<int, int, int> add = (a, b) => a + b;

83. Events in C#

Always null-conditional invoke: Changed?.Invoke(…).

Event tip

public event EventHandler? Changed;
Changed?.Invoke(this, EventArgs.Empty);

84. Anonymous Methods in C#

Prefer lambda syntax in modern code.

Anonymous method tip

delegate(int x) { return x + 1; }
Today: x => x + 1

85. Extension Methods in C#

Keep extensions focused; don’t hide expensive operations.

Extension

static class StringExt
{
    public static bool IsEmpty(this string? s) => string.IsNullOrEmpty(s);
}

86. Nullable Reference Types in C#

Treat warnings seriously — they prevent NullReferenceExceptions.

NRT tip

#nullable enable
string name = "Asha"; // non-null
string? nickname = null;

87. Exception Handling in C#

Don’t swallow exceptions; catch specific types when possible.

Exceptions tip

catch specific exceptions
use finally/using for cleanup
throw informative exceptions
avoid empty catch

88. try, catch, finally in C#

Prefer using for IDisposable instead of manual finally when possible.

try/catch

try
{
    var text = File.ReadAllText(path);
}
catch (FileNotFoundException ex)
{
    Console.Error.WriteLine(ex.Message);
}

89. throw and Custom Exceptions in C#

Don’t over-create custom exceptions — use existing BCL types when they fit.

Custom exception tip

class OrderNotFoundException : Exception
{
    public OrderNotFoundException(string id) : base($"Order {id} not found") {}
}

90. File Handling in C#

Prefer async file APIs in web apps to avoid blocking threads.

File tip

File / FileInfo
StreamReader / StreamWriter
Path helpers
Async variants

91. Reading and Writing Files in C#

Handle IO exceptions and encoding explicitly when needed.

Read/Write

await File.WriteAllTextAsync("out.txt", content);
var text = await File.ReadAllTextAsync("out.txt");

92. JSON Handling in C#

Prefer System.Text.Json for new .NET apps unless you need Newtonsoft features.

System.Text.Json

var json = JsonSerializer.Serialize(user);
var copy = JsonSerializer.Deserialize<User>(json);

93. Serialization and Deserialization in C#

Validate deserialized data; don’t trust untrusted payloads.

Serialization tip

DTOs for boundaries
Ignore unexpected fields carefully
Version contracts
Never deserialize untrusted binary blindly

94. Date and Time in C#

Prefer DateTimeOffset / UTC for stored timestamps.

DateTime tip

var now = DateTimeOffset.UtcNow;
var local = now.ToLocalTime();

95. Regular Expressions in C#

Cache compiled regex for hot paths; prefer simple parsing when possible.

Regex

var ok = Regex.IsMatch(email, @"^[^@s]+@[^@s]+.[^@s]+$");

96. Async and Await in C#

Don’t block on async (.Result/Wait) in UI/ASP.NET — await instead.

async/await

async Task<string> LoadAsync(string url)
{
    using var client = new HttpClient();
    return await client.GetStringAsync(url);
}

97. Task and Task-Based Programming in C#

Pass CancellationToken through APIs for cooperative cancel.

Task tip

await Task.WhenAll(LoadAAsync(), LoadBAsync());

98. Multithreading in C#

Prefer Task Parallel Library / channels over manual threads when possible.

Concurrency tip

Tasks for async I/O
Parallel for CPU-bound
lock / concurrent collections
Avoid shared mutable state

99. Dependency Injection in C#

Depend on abstractions (interfaces) for testability.

DI tip

builder.Services.AddScoped<IUserService, UserService>();
// ctor: public HomeController(IUserService users) { }

100. Reflection in C#

Powerful but slower — use for frameworks/plugins, not hot loops.

Reflection tip

Type.GetType / GetMethods
Attributes discovery
Prefer source generators when possible

101. Attributes in C#

Examples: [HttpGet], [Required], [JsonPropertyName].

Attribute

public class CreateUserRequest
{
    [Required]
    public string Email { get; set; } = "";
}

102. Memory Management and Garbage Collection in C#

Managed memory is GC’d; unmanaged resources need Dispose/using.

GC tip

GC manages managed heap
Dispose unmanaged/native resources
using / await using
Avoid premature GC.Collect

103. C# with SQL Server

Always use parameterized queries — never concatenate untrusted SQL.

Parameterized tip

// Prefer EF Core or:
cmd.Parameters.AddWithValue("@id", id); // or better typed parameters

104. Entity Framework Core

Use migrations for schema changes and DbContext for unit-of-work style access.

DbContext idea

class AppDb : DbContext
{
    public DbSet<User> Users => Set<User>();
}

105. CRUD with Entity Framework Core

Call SaveChanges/SaveChangesAsync after tracked changes.

CRUD sketch

db.Users.Add(new User { Email = email });
await db.SaveChangesAsync();
var user = await db.Users.FirstAsync(u => u.Email == email);

106. ASP.NET Core Introduction

Minimal hosting model + middleware pipeline are foundational.

ASP.NET Core pieces

WebApplication builder
Middleware pipeline
DI container
MVC / Minimal APIs / Razor

107. MVC Architecture in ASP.NET Core

Controllers handle HTTP; models hold data; views render UI.

MVC flow

Request → Controller
→ Model/services
→ View / response

108. ASP.NET Core Web API

Return proper status codes and problem details for errors.

API controller sketch

[ApiController]
[Route("api/[controller]")]
public class ItemsController : ControllerBase
{
    [HttpGet]
    public ActionResult<IEnumerable<Item>> Get() => Ok(items);
}

109. REST API Development with C#

Version APIs thoughtfully; keep DTOs separate from entities.

REST tip

GET/POST/PUT/PATCH/DELETE
DTO mapping
Validation
Consistent error shape

110. Authentication and Authorization in ASP.NET Core

Use ASP.NET Core Identity / JWT / policies based on app needs.

AuthZ tip

Authentication → who are you?
Authorization → what can you do?
Policies/roles/claims

111. JWT Authentication in ASP.NET Core

Store secrets securely; use HTTPS; keep token lifetimes short + refresh strategy.

JWT tip

Issue token on login
Authorization: Bearer <token>
Validate issuer/audience/lifetime
HTTPS only

112. Entity Framework Core with Web API

Use async EF methods; avoid lazy-loading surprises in APIs.

EF + API tip

AddDbContext
Scoped lifetime
Project to DTOs
AsNoTracking for read-only

113. API Documentation with Swagger in ASP.NET Core

Add annotations and examples for better client experience.

Swagger tip

AddSwaggerGen
Map OpenAPI endpoints
Document auth schemes
Keep DTOs accurate

114. Unit Testing with xUnit

Test domain logic fast; use WebApplicationFactory for integration tests.

xUnit tip

[Fact]
public void Add_works()
{
    Assert.Equal(5, Add(2, 3));
}

115. Debugging C# Applications

Reproduce first; use conditional breakpoints for noisy loops.

Debug tip

Breakpoints / step
Call stack
Exception settings
Logs + correlation IDs

116. Logging in .NET

Log warnings/errors with context; avoid logging secrets.

ILogger tip

_logger.LogInformation("Created user {UserId}", user.Id);

117. Git and GitHub for C# Projects

Use branches/PRs; never commit secrets or user secrets store carelessly.

Git tip

dotnet new gitignore
Commit .csproj not bin/obj
PR reviews
Protect main branch

118. C# Security Best Practices

Enable nullable reference types; follow OWASP-minded API habits.

Security checklist

Parameterized queries / EF
HTTPS + secure cookies
AuthZ on every endpoint
Secrets in vault/user-secrets
Validate DTOs
Dependency updates

119. C# Interview Questions

Be ready for value vs reference, async/await, DI, LINQ, and boxing.

Sample Q&A

Q: Interface vs abstract class?
A: Interfaces = contracts (multi); abstract class = shared base + optional impl.

Q: async void?
A: Avoid except event handlers.

Q: IEnumerable vs IQueryable?
A: In-memory vs provider query translation (e.g. EF).

120. Real-World C# Project

Include README, .gitignore, and sample requests.

Project ideas

Task manager Web API
Inventory API + EF Core
Blog API with JWT
File processing worker service
Minimal API + Swagger demo

121. Final Project – Complete ASP.NET Core Application

Ship a production-shaped solution: domain models, EF Core + migrations, REST API, JWT (or Identity) auth, validation, Swagger, logging, unit tests, and README with run instructions.

  1. Design solution layers and domain.
  2. Implement EF Core + API CRUD.
  3. Add auth, Swagger, and tests.
  4. Document and demo the running app.

Final project scope

1. Solution structure (API + Domain + Data + Tests)
2. EF Core models + migrations
3. CRUD endpoints + DTOs
4. Validation + problem details
5. JWT/Identity auth on protected routes
6. Swagger docs
7. ILogger usage
8. xUnit tests for core logic/API
9. README + .env/user-secrets notes

Suggested features

Users/auth
Items/orders (or posts/comments)
Pagination/filtering
Seed data

Conclusion

You now have a full C# path: language mastery, .NET libraries, data access with EF Core, and ASP.NET Core APIs. Finish the final ASP.NET Core application project to turn the lessons into a portfolio-ready system.

Leave a reply

Your email address will not be published. Required fields are marked *