Grafikus C# – Windows Forms tanfolyam › 4.3 lecke

Windows Forms · 4.3 · önálló gyakorlás

Önálló feladat III.: Belépés és regisztráció SQLite-tal

A harmadik önálló feladatban az ablakos programot és az adatbázist összekapcsolod. Egy bejelentkező és regisztrációs alkalmazást építesz SQLite adatbázissal, biztonságos, paraméterezett lekérdezésekkel és hibakezeléssel. A leírást, a pontozást és támpontokat kapsz, kész megoldást nem.

  • 120 perc
  • önálló munka
  • 100 pontos feladat
Diák C# programozást gyakorol egy tanulósarokban

A feladat végére

  • önállóan összekötöd az ablakos programot és az SQLite adatbázist;
  • külön DB osztályba teszed az adatbázis-műveleteket;
  • paraméterezett lekérdezéssel építed fel a bejelentkezést és a regisztrációt;
  • kezeled a hibás bevitelt, az azonos nevű felhasználót, a hiányzó fájlt és táblát;
  • a listában nem mutatod meg a jelszót;
  • tesztlistával és önértékeléssel ellenőrzöd a munkádat.

Mielőtt elkezded

Ehhez a feladathoz a 3. fejezet leckéire támaszkodsz. A feladat közben használhatod a leckéket és a jegyzeteidet, de a programot önállóan állítsd össze.

3.4 Regisztráció és DataGridView →

3.3 Bejelentkezés SQLite-tal →

A feladat leírása

Készíts egy Felhasználókezelő nevű Windows Forms alkalmazást SQLite adatbázissal:

  • Az adatbázis neve belepes.db, a tábla neve belepesi_adatok, oszlopai: id (egész szám, elsődleges kulcs, automatikus), felhnev (szöveg, kötelező, egyedi) és jelszo (szöveg, kötelező).
  • Az ablak bal oldalán a bejelentkezés: felhasználónév és jelszó mező (a jelszó rejtve), Belépés gomb, hibajelzés.
  • Az ablak jobb oldalán a regisztráció: felhasználónév, jelszó és a jelszó megerősítése, Regisztráció gomb.
  • Alul egy DataGridView a regisztrált felhasználók nevét listázza (a jelszót nem).
  • Minden SQL parancs paraméterezett, és az adatbázis-hívások hibakezeltek.
📷 Képernyőkép helye

Mit tegyél ide: egy példa tervrajz vagy mintaablak: bal oldalt a Belépés csoport, jobb oldalt a Regisztráció csoport, alul a felhasználók táblázata és az üzenet-felirat.Javasolt fájlnév: winforms-4-3-minta.webp · Alt szöveg: A Felhasználókezelő alkalmazás mintaablaka belépéssel, regisztrációval és listával

Követelmények és pontozás

RészKövetelményPont
Belépés (40)A felhasználónév és a jelszó ellenőrzése paraméterezett SELECT COUNT(*) lekérdezéssel; sikeres és sikertelen belépésre eltérő üzenet.20
Üres mezők kezelése a lekérdezés előtt; a jelszó mező rejtett.10
A hibaüzenet nem árulja el, hogy a név vagy a jelszó hibás-e. Az adatbázis-hívás külön DB osztályban van.10
Regisztráció (40)Új felhasználó felvétele paraméterezett INSERT utasítással (ExecuteNonQuery).15
Azonos nevű felhasználó megakadályozása érthető üzenettel; a jelszó legalább 6 karakter, és a két jelszómező egyezik.15
A felhasználók listája a DataGridView-ban, jelszó nélkül; sikeres regisztráció után frissül.10
Hibakezelés (20)Hiányzó adatbázisfájl, nem létező tábla és zárolt adatbázis esetén látható, érthető hibaüzenet (try–catch), a program nem omlik össze.12
A .db fájl a program mellé másolódik (Copy if newer), és using blokkok zárják a kapcsolatot.8

Összesen: 100 pont. A belépés 40, a regisztráció 40, a hibakezelés 20 pontot ér.

Csak gyakorló adatot használj!

A feladat tesztadatbázisában kitalált neveket és jelszavakat tárolj. Soha ne írj bele igazi jelszót. A nyílt szövegű jelszótárolás a tanulás eszköze: valódi alkalmazásban a jelszót nem tárolják nyíltan.

Időbeosztás (120 perc)

PercMit csinálj?
0–15A DB Browserben hozd létre a belepes.db adatbázist és a táblát; vegyél fel két próbafelhasználót; írd ki a változtatásokat (Ctrl+S).
15–30Új Windows Forms projekt, a System.Data.SQLite NuGet csomag telepítése, a belepes.db bemásolása (Copy if newer).
30–45A DB osztály a kapcsolattal, és egy kapcsolat-teszt (a sorok számának lekérdezése).
45–65Az ablak felépítése; a felhasználónév és a jelszó beolvasása, a paraméterezett COUNT(*) lekérdezés a DB osztályban.
65–85A belépés sikeres és hibás ága; az üres mezők kezelése.
85–105Regisztráció: ellenőrzések, INSERT, azonos nevek, a lista frissítése.
105–120A tesztlista végigpróbálása, a hibás esetek (hiányzó fájl, hiányzó tábla, zárolt adatbázis) kipróbálása.

Támpontok (kész megoldás nélkül)

Mit hova tegyél?
FeladatHol és mivel?Lecke
Adatbázis és táblaDB Browser, CREATE TABLE, PRIMARY KEY, UNIQUE, Write Changes3.1
KapcsolatDB.UjKapcsolat(), using, File.Exists3.2
BelépésDB.BelepesJo(nev, jelszo), @nev, @jelszo, ExecuteScalar3.3
RegisztrációDB.Regisztral(nev, jelszo), ExecuteNonQuery3.4
ListaDataTable, SQLiteDataAdapter.Fill, DataSource3.4
A felület és az adatbázis szétválasztása

Az ablak kódja csak a bevitelt ellenőrzi, és a visszaadott értéket (bool, DataTable) használja fel. Az SQL szövegek és a kapcsolat a DB osztályban legyenek. Így egy helyen javítható minden adatbázis-hiba.

A jelszó megerősítése

A két jelszómező összehasonlításához használd a != operátort (nem egyenlő). Az ellenőrzést az adatbázis-hívás előtt végezd el.

Hibák, amelyeket külön ki kell próbálnod

Nevezd át ideiglenesen a bin\Debug mappában a .db fájlt (hiányzó fájl), írj át egy tábla nevet az SQL-ben (hiányzó tábla), és hagyd nyitva a DB Browserben ki nem írt változtatással az adatbázist (zárolt adatbázis). A programnak mindhárom esetben érthető hibaüzenetet kell mutatnia.

A lista frissítése

A DataGridView nem frissül magától. A listát egy külön Frissit() metódus tölti, amelyet az ablak betöltésekor és minden sikeres regisztráció után meghívsz.

Mintamegoldás

Előbb oldd meg önállóan!

A mintamegoldás csak az ellenőrzésre való, és nem az egyetlen helyes megoldás. Előbb próbálkozz saját kóddal, és csak elakadásnál vagy a végén nyisd meg. Ha egy rész nem megy, a hozzá tartozó lecke (3.1–3.4) részletesen elmagyarázza.

Megoldás: az adatbázis létrehozása (SQL)
DB Browser, Execute SQLSQLite
CREATE TABLE belepesi_adatok (
id INTEGER PRIMARY KEY AUTOINCREMENT,
felhnev TEXT NOT NULL UNIQUE,
jelszo TEXT NOT NULL
);

INSERT INTO belepesi_adatok (felhnev, jelszo) VALUES ('tanulo', 'teszt123');
INSERT INTO belepesi_adatok (felhnev, jelszo) VALUES ('kata', 'almafa');
Megoldás: DB.cs (teljes kód)
DB.csC#
using System;
using System.Data;
using System.Data.SQLite;
using System.IO;
using System.Windows.Forms;

internal static class DB
{
private static readonly string AdatbazisUt = Path.Combine(Application.StartupPath, "belepes.db");

public static SQLiteConnection UjKapcsolat()
{
if (!File.Exists(AdatbazisUt))
{
throw new FileNotFoundException("Nem található az adatbázis: " + AdatbazisUt);
}

return new SQLiteConnection("Data Source=" + AdatbazisUt + ";Version=3;");
}

public static bool BelepesJo(string nev, string jelszo)
{
using (SQLiteConnection kapcsolat = UjKapcsolat())
{
kapcsolat.Open();

string sql = "SELECT COUNT(*) FROM belepesi_adatok WHERE felhnev = @nev AND jelszo = @jelszo";

using (SQLiteCommand parancs = new SQLiteCommand(sql, kapcsolat))
{
parancs.Parameters.AddWithValue("@nev", nev);
parancs.Parameters.AddWithValue("@jelszo", jelszo);

return Convert.ToInt32(parancs.ExecuteScalar()) > 0;
}
}
}

public static bool Regisztral(string nev, string jelszo)
{
using (SQLiteConnection kapcsolat = UjKapcsolat())
{
kapcsolat.Open();

using (SQLiteCommand ellenor = new SQLiteCommand("SELECT COUNT(*) FROM belepesi_adatok WHERE felhnev = @nev", kapcsolat))
{
ellenor.Parameters.AddWithValue("@nev", nev);

if (Convert.ToInt32(ellenor.ExecuteScalar()) > 0)
{
return false;
}
}

using (SQLiteCommand beszur = new SQLiteCommand("INSERT INTO belepesi_adatok (felhnev, jelszo) VALUES (@nev, @jelszo)", kapcsolat))
{
beszur.Parameters.AddWithValue("@nev", nev);
beszur.Parameters.AddWithValue("@jelszo", jelszo);
beszur.ExecuteNonQuery();
}

return true;
}
}

public static DataTable Felhasznalok()
{
DataTable tabla = new DataTable();

using (SQLiteConnection kapcsolat = UjKapcsolat())
{
kapcsolat.Open();

using (SQLiteDataAdapter adapter = new SQLiteDataAdapter("SELECT id, felhnev FROM belepesi_adatok ORDER BY felhnev", kapcsolat))
{
adapter.Fill(tabla);
}
}

return tabla;
}
}
Megoldás: Form1.cs (teljes kód)

Az ablak vezérlői: txtFelhasznalo, txtJelszo, btnBelep (belépés); txtRegNev, txtRegJelszo, txtRegJelszo2, btnRegisztral (regisztráció); dgvFelhasznalok; lblUzenet. A jelszó mezők UseSystemPasswordChar értéke True.

Form1.csC#
using System;
using System.Drawing;
using System.Windows.Forms;

namespace Felhasznalokezelo
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void Uzenet(string szoveg, bool hiba)
{
lblUzenet.Text = szoveg;
lblUzenet.ForeColor = hiba ? Color.Firebrick : Color.SeaGreen;
}

private void Frissit()
{
try
{
dgvFelhasznalok.DataSource = DB.Felhasznalok();
dgvFelhasznalok.Columns["id"].HeaderText = "Azonosító";
dgvFelhasznalok.Columns["felhnev"].HeaderText = "Felhasználónév";
}
catch (Exception ex)
{
MessageBox.Show("Nem sikerült betölteni a listát: " + ex.Message);
}
}

private void Form1_Load(object sender, EventArgs e)
{
Frissit();
}

private void btnBelep_Click(object sender, EventArgs e)
{
string nev = txtFelhasznalo.Text.Trim();
string jelszo = txtJelszo.Text;

if (nev.Length == 0 || jelszo.Length == 0)
{
Uzenet("Mindkét mezőt töltsd ki!", true);
return;
}

try
{
if (DB.BelepesJo(nev, jelszo))
{
Uzenet($"Sikeres belépés, {nev}!", false);
}
else
{
Uzenet("Hibás felhasználónév vagy jelszó.", true);
}
}
catch (Exception ex)
{
MessageBox.Show("Adatbázis-hiba: " + ex.Message);
}
}

private void btnRegisztral_Click(object sender, EventArgs e)
{
string nev = txtRegNev.Text.Trim();
string jelszo = txtRegJelszo.Text;

if (nev.Length == 0)
{
Uzenet("Add meg a felhasználónevet!", true);
return;
}

if (jelszo.Length < 6)
{
Uzenet("A jelszó legalább 6 karakter legyen!", true);
return;
}

if (jelszo != txtRegJelszo2.Text)
{
Uzenet("A két jelszó nem egyezik!", true);
return;
}

try
{
if (DB.Regisztral(nev, jelszo))
{
Uzenet("Sikeres regisztráció.", false);
txtRegNev.Clear();
txtRegJelszo.Clear();
txtRegJelszo2.Clear();
Frissit();
}
else
{
Uzenet("Ez a felhasználónév már foglalt.", true);
}
}
catch (Exception ex)
{
MessageBox.Show("Adatbázis-hiba: " + ex.Message);
}
}
}
}
Megoldás: miért így épül fel?

Minden SQL parancs paraméterezett, ezért az aposztrófos nevek is biztonságosan működnek. Az adatbázis-hívások a DB osztályban vannak, az ablak csak a visszaadott értékekkel dolgozik. A Regisztral előbb ellenőrzi a nevet, a UNIQUE beállítás pedig védőháló. A listához csak az id és a felhnev oszlopot kérjük le. Az üres, rövid és eltérő jelszavakat az ablak a return utasítással még az adatbázis-hívás előtt kiszűri, a váratlan hibákat pedig a try–catch kapja el.

Tesztlista

#TesztVárt eredmény
1Belépés helyes adatokkalSikeres belépés üzenet.
2Belépés rossz jelszóvalHibás adat üzenet, amely nem árulja el, melyik rossz.
3Belépés ismeretlen névvelUgyanaz a hibaüzenet, mint a rossz jelszónál.
4Belépés üres mezőkkelFigyelmeztetés, nincs adatbázis-hívás.
5A jelszó mező tartalmaPontok látszanak, nem a valódi szöveg.
6Regisztráció új névvelSikeres regisztráció, az új név megjelenik a listában.
7Regisztráció ugyanazzal a névvelÉrthető üzenet, a névből egy sor marad.
8Regisztráció rövid jelszóvalFigyelmeztetés a hosszról.
9Regisztráció eltérő jelszavakkalFigyelmeztetés az egyezésről.
10Aposztrófos név (például O'Hara)Hiba nélkül működik.
11A lista oszlopaiNincs benne jelszó.
12Hiányzó .db fájlÉrthető hibaüzenet, nem omlik össze.
13Nem létező tábla az SQL-benÉrthető hibaüzenet.
14A program újraindításaA korábban regisztrált felhasználók megvannak.

Gyakori hibák és önértékelés

Ezeken szoktak elcsúszni

Gondold végig, nálad előfordul-e valamelyik.

1. Összefűzött SQL

string sql = "SELECT COUNT(*) FROM belepesi_adatok WHERE felhnev = '" + nev + "'";
Hiba és javítás

Biztonsági hiba (SQL-befecskendezés, 3.3 lecke), és az aposztrófos név hibát okoz. Használj paramétert: WHERE felhnev = @nev, és Parameters.AddWithValue.

2. Új üres adatbázis

A program no such table hibát jelez, pedig a DB Browserben megvan a tábla.

Ok és javítás

A program egy másik, üres .db fájlt nyitott meg. Ellenőrizd a Copy to Output Directory beállítást és a kapcsolati szöveg útvonalát (Application.StartupPath). A File.Exists ellenőrzés a hiányzó fájlt előre jelzi.

3. Kimaradt az Open()

using (SQLiteConnection kapcsolat = DB.UjKapcsolat())
{
// kapcsolat.Open(); hiányzik
int db = Convert.ToInt32(parancs.ExecuteScalar());
}
Hiba és javítás

Futás közbeni hiba (InvalidOperationException): a kapcsolat nincs megnyitva. A parancs végrehajtása előtt hívd a kapcsolat.Open(); metódust.

4. A jelszó is a listában

A táblázatban látszik a jelszó oszlop is.

Ok és javítás

A lekérdezés SELECT * alakú. A listához csak a szükséges oszlopokat kérd: SELECT id, felhnev FROM belepesi_adatok.

5. database is locked

A program zárolt adatbázis miatt hibát jelez.

Ok és javítás

A DB Browserben ki nem írt változtatás van, vagy a C# programban nincs lezárva egy kapcsolat. Írd ki a változtatásokat (Ctrl+S), és használd mindenhol a using blokkot.

6. A lista nem frissül

A regisztráció sikeres, de a táblázat a régi állapotot mutatja.

Ok és javítás

A sikeres regisztráció után nem hívod meg a Frissit() metódust, amely újra lekérdezi az adatokat.

Az értékeléshez ellenőrizd az alábbi szempontokat is:

MűködésA tesztlista mind a 14 pontja teljesül.
BiztonságMinden SQL paraméterezett, a jelszó rejtett, és nem szerepel a listában.
SzerkezetAz adatbázis-kód a DB osztályban van, az ablak csak a visszaadott értékeket használja.
HibakezelésHiányzó fájl, hiányzó tábla és zárolt adatbázis esetén érthető üzenet jelenik meg.

Bővítési ötletek, ha kész vagy

Ha maradt időd, fejleszd tovább a programot:

  • Próbálkozások korlátozása: három sikertelen belépés után tiltsd le a gombot (3.3 lecke feladata).
  • Keresés a listában: egy mezővel szűrd a felhasználókat névrészletre (3.4 lecke feladata).
  • Törlés: egy kijelölt felhasználó törlése a DELETE utasítással, megerősítő kérdéssel.
  • Jelszómódosítás: az UPDATE utasítással, a régi jelszó ellenőrzése után.
  • Jelszó hash-elése: tanulmányozd, hogyan tárolják a jelszavakat valódi programokban.

Mit tudsz már?

  • Önállóan összekötöd az ablakos programot és az SQLite adatbázist.
  • Paraméterezett lekérdezéssel építed fel a belépést és a regisztrációt.
  • Kezeled a hibás bevitelt és az adatbázis-hibákat.
  • A listában nem mutatod a jelszót.
  • Tesztlistával értékeled a saját munkádat.

Következő feladat: számológép

A három önálló feladaton túl vagy. A következő önálló feladatban számológépet építesz grafikus felülettel: közös eseménykezelők, állapotkezelés és hibakezelés.