KODLABBET: DITT NÄSTA STEG I IT-KARRIÄREN.
Lär dig programmering från grunden med interaktiva övningar och expertstöd.
Riktiga studenter. Riktiga resultat.
Mer än 2 400 kodare har redan börjat sin resa med KodLabbet.
Välj ditt nästa projekt
Bygg riktiga grejer. Anpassa varje projekt till ditt språk, ramverk och terminal.
Laddar projekt...
📚 Kunskapsbanken
Kodreferenser, AI-verktyg, kravställning och de senaste nyheterna inom tech — allt på ett ställe.
Laddar kunskapsbanken...
Hej! Jag är KodBot!
Fråga om kod, klistra in kod med fel,
eller välj ett ämne nedan.
Generera träningsuppgifter
Klistra in din kursplan så genererar KodBot anpassade övningar efter din nivå — eller skriv bara ett ämne, begrepp eller enstaka ord för att få riktade övningsuppgifter direkt.
Enkel prissättning
Börja gratis. Uppgradera när du är redo.
- ✅6 projekt (nybörjare)
- ✅Alla tips & tricks
- ✅5 AI-frågor per dag
- ✅JavaScript + Python
- 🔒C# & TypeScript-projekt
- 🔒SQL / MongoDB-projekt
- 🔒Avancerade filter
- 🔒Obegränsad AI-chatt
- ✅Alla 25 projekt
- ✅C#, SQL, MongoDB-projekt
- ✅Obegränsad AI-chatt
- ✅Alla avancerade filter
- ✅AI anpassad till ditt ramverk
- ✅Sparad chatthistorik
- ✅Algoritmer & designmönster
- ✅XP-leaderboard
- ✅Allt i Pro
- ✅Upp till 20 användare
- ✅Team-dashboard & statistik
- ✅Anpassade projekt för ert stack
- ✅SSO-integration
- ✅Faktura-betalning
Detaljerad jämförelse
| Funktion | Gratis | Pro | Enterprise |
|---|---|---|---|
| Antal projekt | 6 | 25+ | Obegränsad |
| AI-frågor/dag | 5 | ∞ | ∞ |
| C#-projekt | ✗ | ✓ | ✓ |
| SQL & MongoDB | ✗ | ✓ | ✓ |
| Avancerade filter | ✗ | ✓ | ✓ |
| AI anpassad till ramverk | ✗ | ✓ | ✓ |
| Sparad chatthistorik | ✗ | ✓ | ✓ |
| Team-funktioner | ✗ | ✗ | ✓ |
❓ Vanliga frågor
⚔️ Kodarenas
Utmana vänner och okända kodare i realtid. Lös problem snabbast och vinn XP.
Redo att koda mot varandra? ⚔️
Skapa en privat utmaning och bjud in en vän, eller hoppa in i en öppen arena och möt slumpmässiga motståndare.
Programmeringskoncept
Interaktiva diagram som förklarar hur moderna system fungerar — från containrar och API:er till databaser, Git och molnet.
Varför använda containrar?
En container är som en låda som packar ihop din app med allt den behöver. Problemet den löser: Det funkar på min dator men inte på servern. Med Docker ser appen exakt likadan ut oavsett var den körs.
Vad är ett API?
API (Application Programming Interface) är ett sätt för program att prata med varandra. Du (appen) beställer något, kyparen (API:et) tar din order, köket (servern) levererar. Du behöver inte veta hur köket fungerar — bara vad du kan beställa.
HTML, CSS och JavaScript — vad gör vad?
HTML är skelettet, CSS är kläderna och JavaScript är musklerna. I .NET genererar du HTML via Razor Pages eller Blazor på servern och skickar det till webbläsaren.
SQL eller NoSQL — vad ska jag välja?
I .NET-världen är SQL Server + Entity Framework Core det vanligaste. SQL passar när du har tydliga relationer (kund har många ordrar). NoSQL passar när datan ser olika ut per post eller behöver skalas enormt.
Autentisering i .NET — vad ska du använda?
I ASP.NET Core används JWT Bearer tokens för API:er och Cookie-autentisering för webbsidor. För Google/Microsoft-inloggning finns OAuth 2.0. ASP.NET Identity är ett färdigt system för användare, roller och lösenord.
Molnet för .NET-utvecklare
Azure är Microsofts moln och det naturliga valet för .NET-appar. Med Azure App Service driftsätter du appen med ett klick. GitHub Actions eller Azure DevOps automatiserar hela pipeline från kodpush till produktion.
Git — det viktigaste att komma ihåg
Git spårar ändringar så att du kan gå tillbaka i historiken, arbeta parallellt med kollegor via branches och slå ihop med merge. GitHub lagrar koden. Flöde: branch → koda → commit → push → Pull Request → merge.
public class Bil
{
public string Marke { get; set; }
public int Hastighet { get; set; }
public Bil(string marke, int hastighet)
{
Marke = marke;
Hastighet = hastighet;
}
public void Kora() => Console.WriteLine($"{Marke} kör!");
}
// Skapa objekt
var b1 = new Bil("Volvo", 120);
var b2 = new Bil("Tesla", 250);
b1.Kora(); // "Volvo kör!"
Klass och objekt — grunden i OOP
En klass är som en husbeskrivning — den berättar hur ett hus ska se ut. Objekt är de faktiska husen byggda från beskrivningen. Du kan skapa hur många objekt du vill från samma klass, och varje objekt har sina egna värden.
public class BankKonto
{
private decimal _saldo; // ingen utanför klassen ser detta
public decimal Saldo // property – kontrollerad åtkomst
{
get => _saldo;
private set => _saldo = value >= 0 ? value : 0;
}
public void SattIn(decimal belopp)
{
if (belopp > 0) Saldo += belopp;
}
public bool TaUt(decimal belopp)
{
if (belopp > Saldo) return false;
Saldo -= belopp;
return true;
}
}
var konto = new BankKonto();
konto.SattIn(1000);
konto.TaUt(200);
// konto._saldo = -999; ← KOMPILERINGSFEL! private
Inkapsling — varför gömma data?
Utan inkapsling kan vem som helst sätta konto.Saldo = -99999. Med private tvingar du all kod att gå genom dina metoder, där du kan validera och kontrollera. Det gör koden tryggare och lättare att ändra internt utan att påverka resten av systemet.
public class Djur
{
public string Namn { get; set; }
public int Alder { get; set; }
public void At() => Console.WriteLine($"{Namn} äter.");
public virtual void LaterLjud() => Console.WriteLine("...");
}
public class Hund : Djur // Hund ärver Djur
{
public string Ras { get; set; }
public override void LaterLjud() => Console.WriteLine("Vov!");
}
public class Katt : Djur
{
public override void LaterLjud() => Console.WriteLine("Mjau!");
}
var h = new Hund { Namn = "Fido", Ras = "Labrador" };
h.At(); // "Fido äter." ← ärvd från Djur
h.LaterLjud(); // "Vov!" ← overridad i Hund
Arv — skriv kod en gång, använd överallt
Med arv slipper du kopiera kod. Allt som är gemensamt (namn, ålder, äta, sova) skrivs en gång i basklassen. Varje barn-klass lägger bara till det som är unikt för den. virtual + override låter barn-klassen byta ut en metods beteende. Obs: C# stöder bara ett arv — en klass kan bara ärva från en basklass.
// Polymorfism — en lista med blandade djur
List<Djur> djur = new()
{
new Hund { Namn = "Fido" },
new Katt { Namn = "Misse" },
new Fagel { Namn = "Tweety" }
};
foreach (var d in djur)
{
d.LaterLjud(); // C# väljer rätt metod automatiskt!
}
// Vov!
// Mjau!
// Tweet!
// Overloading — samma namn, olika parametrar
public void Skriv(int tal) => Console.WriteLine(tal);
public void Skriv(string text) => Console.WriteLine(text);
public void Skriv(int x, int y) => Console.WriteLine($"{x},{y}");
Polymorfism — magin i OOP
Polymorfism låter dig skriva generell kod som fungerar med alla typer som ärver från basklassen. Du kan lägga till en Orm-klass i framtiden och loop-koden ovan fungerar fortfarande utan ändringar — den vet inte och behöver inte veta vilken typ det är.
public interface INotifierare
{
void SkickaNotis(string meddelande);
bool ArTillganglig();
}
public class EpostNotifierare : INotifierare
{
public void SkickaNotis(string med) => SendEmail(med);
public bool ArTillganglig() => true;
}
public class SmsNotifierare : INotifierare
{
public void SkickaNotis(string med) => SendSms(med);
public bool ArTillganglig() => CheckSmsGateway();
}
// Din service beror bara på interfacet — lätt att byta!
public class OrderService
{
private readonly INotifierare _notis;
public OrderService(INotifierare notis) => _notis = notis; // DI
public void PlaceraOrder() => _notis.SkickaNotis("Order klar!");
}
Interface — varför inte bara arv?
Till skillnad från arv kan en klass implementera hur många interface som helst. Interface är perfekta för Dependency Injection — din kod beror på INotifierare, inte på en specifik klass. Det gör det trivialt att byta implementation eller mocka i tester. Namnge alltid interface med stort I: IRepository, ILogger.
public abstract class Rapport
{
public string Titel { get; set; }
// Klar metod – används av ALLA subklasser
public void SkrivUt()
{
Console.WriteLine($"=== {Titel} ===");
Console.WriteLine(GenereraInnehall()); // anropar subklassens version
}
// Abstrakt – MÅSTE overridas av subklassen
public abstract string GenereraInnehall();
}
public class PdfRapport : Rapport
{
public override string GenereraInnehall() => "PDF-formaterat innehall...";
}
public class ExcelRapport : Rapport
{
public override string GenereraInnehall() => "Excel-formaterat innehall...";
}
var r = new PdfRapport { Titel = "Arsredovisning" };
r.SkrivUt();
// === Arsredovisning ===
// PDF-formaterat innehall...
Abstrakt klass vs interface — när vilket?
Abstrakt klass: när subklasserna delar gemensam kod + har egna implementationer. Interface: när du bara vill definiera ett kontrakt utan delad kod, eller när en klass behöver "vara" flera saker. Tumregel: föredra interface i moderna C#-projekt — de är mer flexibla och testbara.
Kan ha fält och kod
En per klass (arv)
Har konstruktor
Bra: Template Method
Bara kontrakt (C# 8+: default)
Obegränsat per klass
Ingen konstruktor
Bra: DI, testning
Microservices — när ska du använda dem?
Microservices passar stora system med många team. Varje tjänst kan driftsättas, skalas och uppdateras oberoende. Nackdelen är ökad komplexitet: nätverkskommunikation, distribuerade transaktioner och övervakning kräver mer arbete än en monolit.
Caching i .NET
ASP.NET Core har inbyggt stöd för IMemoryCache (in-process) och IDistributedCache (t.ex. Redis). Redis är det vanligaste valet när du har flera instanser av din app. Cacha data som läses ofta men sällan ändras — t.ex. produktlistor, konfiguration, sökresultat.
Testning i .NET — verktyg och mönster
I .NET-ekosystemet är xUnit det vanligaste ramverket för unit tests. Moq används för att "mocka" beroenden (t.ex. en databas) så att du kan testa en klass isolerat. Integrationstester i ASP.NET Core görs med WebApplicationFactory som startar hela appen i minnet. Sträva efter många snabba unit tests och färre långsamma integrationstester.
Design patterns — varför lära sig dem?
Design patterns är beprövade lösningar på vanliga problem. Du behöver inte memorera dem alla — men Repository och Dependency Injection möter du i nästan varje .NET-projekt. DI är inbyggt i ASP.NET Core och är grunden till hur hela ramverket fungerar. Lär dig dessa två först, resten kommer naturligt.
Regel: om en metod gör I/O (DB, HTTP, fil) – gör den async. Annars blockerar du tråden i onödan.
// SYNKRONT – blockerar tråden
public string HämtaData()
{
var result = db.Users.ToList(); // tråden väntar här
return result;
}
// ASYNKRONT – frigörs tråden under väntan
public async Task<List<User>> HämtaDataAsync(CancellationToken ct)
{
var result = await db.Users.ToListAsync(ct); // tråden är fri!
return result;
}
// Parallellt – flera saker samtidigt
public async Task ParallellAsync()
{
var t1 = HämtaAnvändareAsync();
var t2 = HämtaProdukterAsync();
await Task.WhenAll(t1, t2); // båda kör samtidigt!
}
// Vanligt misstag – .Result blockerar och kan deadlocka!
var data = HämtaDataAsync().Result; // GÖR INTE SÅ
var data = await HämtaDataAsync(); // GÖR SÅ ISTÄLLET
Async/await – varför är det viktigt?
En webbserver har ett begränsat antal trådar. Om varje request blockerar sin tråd medan den väntar på databasen kan servern bara hantera några tiotal requests samtidigt. Med async/await frigörs tråden och kan hantera hundratals requests parallellt – utan extra trådar.
// SQL Injection – GÖR INTE SÅ
var sql = $"SELECT * FROM Users WHERE Name = '{input}'";
// Om input = "'; DROP TABLE Users;--" → katastrof!
// GÖR SÅ – parametriserad query (EF Core)
var user = await db.Users
.Where(u => u.Name == input) // EF skyddar automatiskt
.FirstOrDefaultAsync();
// XSS – Razor HTML-encodar automatiskt
<p>@Model.AnvändarInput</p> // SÄKER – encodas
<p>@Html.Raw(Model.AnvändarInput)</p> // FARLIG – kör rå HTML
// CORS i ASP.NET Core
builder.Services.AddCors(opt => opt.AddPolicy("MittAPI", p =>
p.WithOrigins("https://minapp.se")
.AllowAnyMethod()
.AllowAnyHeader()));
// HTTPS-omdirigering
app.UseHttpsRedirection();
app.UseHsts();
Säkerhet – den viktigaste regeln
Lita aldrig på indata från användaren. Validera, sanitera och encoda alltid. EF Core och Razor skyddar dig mot de vanligaste attackerna automatiskt – men du måste förstå varför, så att du inte kringgår skyddet av misstag med Html.Raw eller råa SQL-strängar.
// DNS-uppslag i C#
var addresses = await Dns.GetHostAddressesAsync("google.se");
// HTTP-request i C# med HttpClient
var client = new HttpClient();
var response = await client.GetAsync("https://api.example.com/data");
var json = await response.Content.ReadAsStringAsync();
// Kontrollera statuskod
if (response.IsSuccessStatusCode)
Console.WriteLine("OK!");
else
Console.WriteLine($"Fel: {response.StatusCode}");
// TCP-socket (lågnivå – sällan behövs direkt)
using var socket = new TcpClient("example.com", 80);
// HttpClient hanterar allt detta åt dig automatiskt
Nätverk – vad en .NET-utvecklare behöver veta
Du behöver inte kunna bygga en router – men att förstå DNS (namn → IP), TCP (tillförlitlig koppling), HTTP (protokollet ovanpå) och portar hjälper enormt när saker inte fungerar. HttpClient i .NET sköter allt detta åt dig, men det är guld värt att förstå vad som händer under huven.
// Värdetyper (struct) – bor på stack
int x = 42;
bool aktiv = true;
DateTime now = DateTime.Now;
// Referenstyper (class) – bor på heap
var bil = new Bil("Volvo"); // "bil"-variabeln på stack pekar på heap
var lista = new List<int>();
// IDisposable – frigör ej-hanterade resurser (filer, DB, HTTP)
// using-satsen anropar Dispose() automatiskt när blocket avslutas
using var fil = File.OpenRead("data.txt");
using var conn = new SqlConnection(connStr);
// Dispose() anropas automatiskt här – även vid exception
// Många kopior vs delad referens
int a = 5;
int b = a; // kopia – b = 5, ändrar a påverkar inte b
var bil1 = new Bil("Volvo");
var bil2 = bil1; // SAMMA objekt! ändrar bil2 → ändrar bil1 också
Minneshantering – vad du behöver tänka på
.NET sköter minneshantering automatiskt via Garbage Collector – du behöver sällan tänka på det. Men du måste använda using för resurser som databasanslutningar, filer och HTTP-klienter, annars läcker de. Förstå skillnaden mellan värdetyper (kopieras) och referenstyper (delas) – det förklarar många konstiga buggar.
// Dictionary – O(1)-uppslag
var priser = new Dictionary<string, decimal>
{
["Mjölk"] = 15.90m,
["Bröd"] = 29.50m
};
decimal pris = priser["Mjölk"]; // O(1) – blixtsnabbt
// HashSet – kontrollera unikhet O(1)
var besökta = new HashSet<int>();
besökta.Add(42);
bool finnsDen = besökta.Contains(42); // O(1)
// List – O(n) sökning – använd bara när ordning spelar roll
var lista = new List<string> { "A", "B", "C" };
bool finns = lista.Contains("B"); // O(n) – går igenom alla
// Binär sökning på sorterad lista
var sorterad = new List<int> { 1, 3, 5, 7, 9, 11 };
int index = sorterad.BinarySearch(7); // O(log n)
// LINQ använder rätt algoritm internt
var snabb = dict.ContainsKey("Mjölk"); // O(1)
var långsammare = lista.Any(x => x == "B"); // O(n)
Algoritmer – den praktiska kunskapen
Du behöver inte implementera quicksort från grunden, men du måste veta att Dictionary.ContainsKey är O(1) medan List.Contains är O(n) – det är skillnaden mellan en app som svarar på millisekunder och en som hänger sig under last. Välj rätt datastruktur för rätt problem.
// Try/catch/finally
public async Task<User> HämtaAnvändareAsync(int id)
{
try
{
return await db.Users.FindAsync(id)
?? throw new NotFoundException($"Användare {id} hittades inte");
}
catch (NotFoundException)
{
throw; // Skicka vidare – låt anroparen hantera
}
catch (Exception ex)
{
logger.LogError(ex, "Oväntat fel vid hämtning av användare {Id}", id);
throw;
}
finally
{
// Körs ALLTID – bra för cleanup
}
}
// Eget exception
public class NotFoundException : Exception
{
public NotFoundException(string msg) : base(msg) { }
}
// Result-mönstret – inga exceptions för kända fel
public record Result<T>(T? Value, string? Error, bool IsSuccess);
public Result<User> LoggaIn(string epost, string lösenord)
{
var user = db.Users.FirstOrDefault(u => u.Epost == epost);
if (user == null) return new(null, "Användare finns ej", false);
if (!VerifyPassword(lösenord, user.Hash))
return new(null, "Fel lösenord", false);
return new(user, null, true);
}
// Anroparen kollar resultatet – inga try/catch behövs
var result = LoggaIn("test@test.se", "abc");
if (result.IsSuccess)
Console.WriteLine($"Välkommen {result.Value!.Namn}!");
else
Console.WriteLine($"Fel: {result.Error}");
Felhantering – exceptions vs Result
Kasta exceptions för oväntade fel (nätverkskrasch, null-referens, saknad fil). Använd Result-mönstret för väntade affärslogik-fel (fel lösenord, validering, resurs hittades inte). Fånga aldrig Exception och svälj felet tyst – logga alltid. finally garanterar städning oavsett vad som händer.
Alla delar ihop
I ett modernt system: Användaren ser en HTML-sida, som pratar med ett API, som kör C#-kod, som hämtar data från en databas — allt packat i containrar för att köras var som helst.
🔥 Dagens utmaning
En ny koduppgift varje dag. Bygg din streak och tjäna bonus-XP!