Menu

Εμφάνιση αναρτήσεων

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Εμφάνιση αναρτήσεων Menu

Μηνύματα - Vuyok

#1
Στο Kotlin, τα coroutines είναι μία από τις πιο εμβληματικές λειτουργίες της γλώσσας που κάνουν τον ασύγχρονο προγραμματισμό απλό, αναγνώσιμο και αποδοτικό. Σε σύγκριση με τα παραδοσιακά threads ή callbacks, τα coroutines δημιουργούν ελαφριές (lightweight) εργασίες – χιλιάδες coroutines μπορούν να εκτελούνται στο ίδιο thread, ενώ τα κλασικά threads καταναλώνουν γρήγορα πόρους συστήματος. Από το 2026, τα coroutines έχουν γίνει πρότυπο σε Android (ενσωμάτωση Jetpack Compose, Room, Retrofit), backend (Ktor server-side ασύγχρονο), Kotlin Multiplatform (κοινή δικτύωση) και ακόμη και εφαρμογές desktop. Σε συνδυασμό με structured concurrency, flows και διαχείριση εξαιρέσεων, γίνεται πολύ εύκολο να γράψετε robost ασύγχρονο κώδικα.

Στο Google, αναζητήσεις όπως "Kotlin coroutines", "Kotlin async await", "Kotlin flow", "Kotlin launch vs async" είναι μεταξύ των υψηλότερων σε όγκο θεμάτων Kotlin στην Τουρκία και παγκοσμίως. Η καλή κατανόηση των coroutines είναι απαραίτητη για κλήσεις δικτύου χωρίς μπλοκάρισμα UI, εκτέλεση παράλληλων εργασιών και reactive programming (Flow). Σε αυτόν τον οδηγό, θα καλύψουμε βήμα-βήμα από βασικούς coroutine builders μέχρι Flows, διαχείριση εξαιρέσεων και ρεαλιστικό παράδειγμα έργου.

Γιατί Πρέπει να Μάθετε Coroutines; (Προοπτική 2026)
  • Απόδοση: Χαμηλό overhead για χιλιάδες ταυτόχρονες εργασίες – δεν χρειάζονται thread pools.
  • Αναγνωσιμότητα: Ο κώδικας γράφεται σειριακά (όπως async/await) αλλά λειτουργεί non-blocking.
  • Structured concurrency: Scopes με αυτόματη ακύρωση και διάδοση σφαλμάτων – αποτρέπει memory leaks.
  • Multiplatform: Android, iOS, JS, Native και server-side (Ktor) ίδιο coroutine API.
  • Δημοφιλή χρήση: Κλήσεις Retrofit, ερωτήματα Room, διαχείριση κατάστασης Compose, handlers διαδρομών Ktor.
  • Ενημέρωση 2026: Με το Kotlin 2.0, καλύτερες βελτιστοποιήσεις μεταγλωττιστή και βελτιώσεις Flow.

Εγκατάσταση και Εξαρτήσεις
Για έργο Android:
Κώδικας [Επιογή]
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0") // ή implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.0") //
Για γενικό/multiplatform kotlinx-coroutines-core.

Βασικές Έννοιες
  • CoroutineScope: Διαχειρίζεται τον κύκλο ζωής των coroutines.
  • Dispatcher: Καθορίζει σε ποιο thread θα εκτελεστεί (Main, IO, Default).
  • Builders: launch (fire-and-forget), async (επιστρέφει τιμή, await).
Κώδικας [Επιογή]
import kotlinx.coroutines.*

fun main() = runBlocking { // Main scope - μπλοκάρει αλλά ιδανικό για τεστ
    launch { // Ξεκινά νέο coroutine (fire-and-forget)
        delay(1000L) // Non-blocking αναμονή (δεν κάνει thread sleep!)
        println("Γεια σου Coroutines! Thread: ${Thread.currentThread().name}")
    }
    println("Συνέχεια χωρίς αναμονή... Thread: ${Thread.currentThread().name}")
    val deferred = async { // Coroutine που επιστρέφει τιμή
        delay(500L)
        "Το αποτέλεσμα είναι έτοιμο"
    }
    println("Αποτέλεσμα async: ${deferred.await()}") // Περιμένει και παίρνει το αποτέλεσμα
}

Κώδικας [Επιογή]
launch(Dispatchers.IO) { // Για δικτύωση, αρχεία
    // Κλήση δικτύου...
}
launch(Dispatchers.Main) { // Για ενημέρωση UI Android
    // textView.text = "Ενημερώθηκε"
}
launch(Dispatchers.Default) { // Για CPU-intensive εργασίες
    // Υπολογισμός...
}

Structured Concurrency και Scopes

Κώδικας [Επιογή]
val scope = CoroutineScope(Dispatchers.Default)
val job = scope.launch {
    launch { // Παιδί coroutine
        delay(1000)
        println("Παιδί ολοκληρώθηκε")
    }
    delay(500)
    println("Γονέας συνεχίζει")
}
job.cancel() // Όλα τα παιδιά ακυρώνονται αυτόματα - structured!

Μην χρησιμοποιείτε GlobalScope – unstructured, κίνδυνος memory leak.
Στο Android, scope ViewModel:

Κώδικας [Επιογή]
viewModelScope.launch { ... } // Αυτόματη ακύρωση όταν καταστραφεί η Activity
lifecycleScope.launch { ... } // Συνειδητοποιημένο κύκλου ζωής

Διαχείριση Εξαιρέσεων

Κώδικας [Επιογή]
val handler = CoroutineExceptionHandler { _, exception ->
    println("Σφάλμα πιάστηκε: $exception")
}
scope.launch(handler) {
    throw Exception("Κάτι πήγε στραβά!")
} // Ή με SupervisorJob απομονώστε σφάλματα παιδιών

Flow: Reactive Streams
Cold stream – ξεκινά όταν συλλέγεται. Υπάρχουν επίσης StateFlow και SharedFlow.

Κώδικας [Επιογή]
import kotlinx.coroutines.flow.*

fun numberFlow(): Flow<Int> = flow {
    for (i in 1..5) {
        delay(500)
        emit(i) // Εκπέμπει
    }
}
fun main() = runBlocking {
    numberFlow()
        .map { it * it } // Μετασχηματίζει
        .filter { it % 2 == 0 } // Φιλτράρει
        .collect { println(it) } // 4, 16 (ζυγοί τετράγωνοι)
    // Σφάλμα και ολοκλήρωση
    numberFlow()
        .onEach { println(it) }
        .onCompletion { println("Η ροή τελείωσε") }
        .catch { println("Σφάλμα: $it") }
        .collect()
}

StateFlow (ιδανικό για Compose):

Κώδικας [Επιογή]
val state = MutableStateFlow("Αρχή")
state.value = "Ενημερώθηκε" // Το UI ανανεώνεται αυτόματα

Πραγματικό Παράδειγμα Έργου: Προσομοίωση Ασύγχρονης Κλήσης API
Απλή προσομοίωση εφαρμογής "Καιρός" – παράλληλες κλήσεις δικτύου.

Κώδικας [Επιογή]
import kotlinx.coroutines.*

data class City(val name: String, val temperature: Int)

suspend fun getTemperature(city: String): City = withContext(Dispatchers.IO) {
    delay((1000..3000).random().toLong()) // Προσομοίωση καθυστέρησης δικτύου
    City(city, (15..30).random())
}

fun main() = runBlocking {
    val cities = listOf("Κωνσταντινούπολη", "Άγκυρα", "Σμύρνη", "Προύσα")
    val jobs = cities.map { city ->
        async { getTemperature(city) } // Παράλληλη έναρξη
    }
    val results = jobs.awaitAll() // Περιμένει όλα
    results.forEach { println("${it.name}: ${it.temperature}°C") }
    // Σειριακά θα ήταν 10+ δευτερόλεπτα, παράλληλα ~3 δευτερόλεπτα!
}

Ενσωμάτωση Android/Compose (σύντομο παράδειγμα):

Προχωρημένα Θέματα και Συμβουλές
  • Timeout:withTimeout(5000) ... ή withTimeoutOrNull.
  • Channel: Επικοινωνία μεταξύ coroutines (producer-consumer).
  • Δοκιμές:runTest για δοκιμές coroutines.
  • Ktor client: Ενσωματωμένη υποστήριξη coroutines για ασύγχρονο HTTP.
  • Απόδοση:Dispatchers.IO.limitedParallelism(64) για προσαρμοσμένο pool.

Συμπέρασμα και Πρακτικές Συμβουλές
Τα coroutines είναι η υπερδύναμη του Kotlin στον ασύγχρονο κόσμο – απαλλαγείτε από callback hell, γράψτε καθαρό και γρήγορο κώδικα. Για πρακτική:
  • Γράψτε απλό client "Todo API": Retrofit + Coroutines με παράλληλες κλήσεις.
  • Δημιουργήστε εφαρμογή καιρού με loading spinner στο Android (Compose + ViewModelScope).
  • Δημιουργήστε κοινό επίπεδο δικτύωσης σε multiplatform έργο (Ktor client).
  • Πόροι: Kotlin docs (coroutines), "Kotlin Coroutines by Tutorials" (raywenderlich), επίσημα παραδείγματα GitHub.

Με αυτόν τον οδηγό, θα έχετε κατανοήσει πλήρως τα coroutines. Σε πραγματικά έργα (κλήσεις δικτύου, εργασίες φόντου) τα coroutines θα σας δώσουν μεγάλη απόδοση και αναγνωσιμότητα. Για λεπτομέρειες παραδείγματος έργου ή συγκεκριμένο τμήμα, αφήστε σχόλιο! Καλή επιτυχία στις εφαρμογές που θα αναπτύξετε με Kotlin το 2026.
#2
Στο Swift, τα closures ορίζονται ως ανώνυμες (χωρίς όνομα) συναρτήσεις και μπορείτε να τα εκχωρήσετε σε μια μεταβλητή, να τα περάσετε ως παραμέτρους ή να τα χρησιμοποιήσετε ως τιμή επιστροφής. Τα closures είναι ένα από τα πιο ισχυρά χαρακτηριστικά του Swift και χρησιμοποιούνται συχνά σε μεθόδους όπως map, filter, sorted του Array, σε completion handlers και σε ασύγχρονες λειτουργίες. Σε αυτό το άρθρο, θα εξετάσουμε τη βασική χρήση των closures, τη σύνταξή τους, τα trailing closures και τη συμπεριφορά capturing με λεπτομερή παραδείγματα.

Βασική Σύνταξη Closure

Ένα closure έχει την εξής δομή:

Απλό Παράδειγμα:
Χωρίς παραμέτρους και τύπο επιστροφής:
Πέρασμα Closure ως Παραμέτρου σε Συναρτήσεις
Τα closures χρησιμοποιούνται συχνότερα ως completion handlers.
Κώδικας [Επιογή]
func islemYap(sayi1: Int, sayi2: Int, operasyon: (Int, Int) -> Int) -> Int {
    return operasyon(sayi1, sayi2)
}
// Χρήση
let toplam = islemYap(sayi1: 5, sayi2: 3) { (a, b) in return a + b }
print(toplam) // 8
// Πιο σύντομο
let carpim = islemYap(sayi1: 4, sayi2: 5) { $0 * $1 }
print(carpim) // 20


Με shorthand syntax όπως $0, $1 μπορείτε να χρησιμοποιήσετε χωρίς να γράφετε ονόματα παραμέτρων.

Σύνταξη Trailing Closure
Αν η τελευταία παράμετρος μιας συνάρτησης είναι closure, μπορεί να γραφτεί έξω από τις παρενθέσεις.
Κώδικας [Επιογή]
// Κανονική χρήση
UIView.animate(withDuration: 1.0, animations: { view.alpha = 0 })
// Trailing closure (πιο καθαρό)
UIView.animate(withDuration: 1.0) { view.alpha = 0 }

Χρήση Closure σε Συνήθεις Μεθόδους Array
Κώδικας [Επιογή]
let sayilar = [3, 1, 4, 1, 5, 9, 2]

// map: Μετατροπή κάθε στοιχείου
let kareler = sayilar.map { $0 * $0 }
print(kareler) // [9, 1, 16, 1, 25, 81, 4]

// filter: Επιλογή αυτών που ταιριάζουν στην συνθήκη
let ciftler = sayilar.filter { $0 % 2 == 0 }
print(ciftler) // [4, 2]

// sorted: Ταξινόμηση
let sirali = sayilar.sorted { $0 < $1 }
print(sirali) // [1, 1, 2, 3, 4, 5, 9]

Capturing Values (Σύλληψη Τιμών)
Τα closures μπορούν να "συλλάβουν" (capture) τις μεταβλητές από το περιβάλλον τους. Αυτό είναι ένα χαρακτηριστικό που χρειάζεται προσοχή, ειδικά σε ασύγχρονες λειτουργίες.
Κώδικας [Επιογή]
func asenkronIslem(completion: @escaping () -> Void) {
    DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
        completion()
    }
}
var mesaj = "Başlangıç"
let closure = {
    print(mesaj) // Το closure συλλαμβάνει τη μεταβλητή mesaj
}
mesaj = "Değiştirildi"
closure() // Έξοδος: Değiştirildi


Διαχείριση weak/self με Capturing List (πρόληψη memory leak):
Κώδικας [Επιογή]
class Ornek {
    var deger = 0
    lazy var closure: () -> Void = { [weak self] in
        guard let self = self else { return }
        print(self.deger)
    }
}

Τα @escaping closures πρέπει να δηλώνονται αν εκτελούνται μετά την έξοδο από τη συνάρτηση.
Σύγκριση: Closure vs Κανονική Συνάρτηση
  • Χαρακτηριστικό: Όνομα Κανονική Συνάρτηση: Υπάρχει Closure: Συνήθως όχι (ανώνυμο)
  • Χαρακτηριστικό: Ορισμός Κανονική Συνάρτηση: Με def Closure: Με {} μπλοκ
  • Χαρακτηριστικό: Πέρασμα ως παραμέτρου Κανονική Συνάρτηση: Ναι Closure: Πολύ εύκολο και συχνά χρησιμοποιούμενο
  • Χαρακτηριστικό: Trailing syntax Κανονική Συνάρτηση: Όχι Closure: Ναι (πιο αναγνώσιμο)
  • Χαρακτηριστικό: Capturing Κανονική Συνάρτηση: Όχι Closure: Ναι (συλλαμβάνει τιμές από το περιβάλλον)
  • Χαρακτηριστικό: Πεδίο Χρήσης Κανονική Συνάρτηση: Γενικού σκοπού Closure: Completion handler, map/filter κλπ.

Καλύτερες Πρακτικές
• Σε σύντομα closures χρησιμοποιήστε shorthand $0, $1.
• Σε ασύγχρονα closures δηλώστε @escaping.
• Για πρόληψη memory leak χρησιμοποιήστε [weak self] ή [unowned self].
• Για αναγνωσιμότητα, βγάλτε πολύ μεγάλα closures σε ξεχωριστές συναρτήσεις.

Συμπέρασμα
Τα closures στο Swift κάνουν τον κώδικα σας πιο ευέλικτο και σύντομο. Ειδικά σε υψηλού επιπέδου μεθόδους (map, filter, reduce) και ασύγχρονο προγραμματισμό είναι απαραίτητα. Ξεκινήστε με απλά παραδείγματα για να εξοικειωθείτε, με τον καιρό θα τα χρησιμοποιείτε άνετα σε completion handlers και animations.
Για πρακτική, γράψτε μια εφαρμογή επεξεργασίας δεδομένων σε ένα array χρησιμοποιώντας συνδυασμό map, filter και reduce!
Περιμένω τις ερωτήσεις σας στα σχόλια.
#3
Το 2025 στην Τουρκία, τα μεγάλα συστήματα κλίμακας πλέον γράφονται με Go. Με ένα μόνο binary.

Γιατί Go; (Πραγματικότητες Τουρκίας 2025)
  • Ένα binary > Εικόνα Docker 15 MB
  • Σε 1 CPU 100.000+ αιτήματα/δευτερόλεπτο
  • Η Türk Telekom, Trendyol, Getir, Hepsiburada χρησιμοποιούν Go
  • Με το Go 1.23 generics + διαχείριση σφαλμάτων + δομημένη καταγραφή σταθερή

1. Εγκατάσταση Go και Έναρξη Έργου (2025)

Κώδικας [Επιογή]
# Κατεβάστε Go 1.23+: https://go.dev/dl/
go version  # πρέπει να είναι go1.23.4

mkdir go-api-2025 && cd go-api-2025
go mod init github.com/kullanicin/go-api-2025
go get github.com/gofiber/fiber/v2
go get github.com/golang-jwt/jwt/v5
go get gorm.io/gorm
go get gorm.io/driver/postgres
go get github.com/joho/godotenv

2. Δομή Φακέλων (Καθαρή Αρχιτεκτονική 2025)
Κώδικας [Επιογή]
go-api-2025/
|-- cmd/
|   |-- api/
|       |-- main.go
|-- internal/
|   |-- handlers/
|   |-- middleware/
|   |-- models/
|   |-- routes/
|-- database/
|-- pkg/
|   |-- go.mod
|-- Dockerfile
|-- .env


3. main.go (cmd/api/main.go)

Κώδικας [Επιογή]
// cmd/api/main.go
package main

import (
"log"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/cors"
"github.com/kullanicin/go-api-2025/internal/routes"
"github.com/joho/godotenv"
)

func main() {
godotenv.Load()

app := fiber.New(fiber.Config{
Prefork:       false, // στην παραγωγή κάντε true
CaseSensitive: true,
StrictRouting: true,
ServerHeader:  "GoAPI2025",
})

// CORS
app.Use(cors.New(cors.Config{
AllowOrigins: "*",
AllowHeaders: "Origin, Content-Type, Accept, Authorization",
AllowMethods: "GET,POST,PUT,DELETE",
}))

// Routes
routes.SetupRoutes(app)

log.Fatal(app.Listen(":3000"))
}


4. Μοντέλο Χρήστη (internal/models/user.go)

Κώδικας [Επιογή]
// internal/models/user.go
package models

import "gorm.io/gorm"

type User struct {
gorm.Model
Name     string `json:"name" gorm:"size:255"`
Email    string `json:"email" gorm:"unique;size:255"`
Password string `json:"-" gorm:"size:255"`
IsAdmin  bool   `json:"is_admin" gorm:"default:false"`
}



5. JWT Middleware (internal/middleware/auth.go)

Κώδικας [Επιογή]
// internal/middleware/auth.go
package middleware

import (
"strings"
"github.com/gofiber/fiber/v2"
"github.com/golang-jwt/jwt/v5"
)

func AuthRequired() fiber.Handler {
return func(c *fiber.Ctx) error {
authHeader := c.Get("Authorization")
if !strings.HasPrefix(authHeader, "Bearer ") {
return c.Status(401).JSON(fiber.Map{"error": "Μη εξουσιοδοτημένη πρόσβαση"})
}

tokenStr := strings.Split(authHeader, " ")[1]
token, err := jwt.Parse(tokenStr, func(token *jwt.Token) (interface{}, error) {
return []byte("super-secret-key-2025"), nil
})
if err != nil || !token.Valid {
return c.Status(401).JSON(fiber.Map{"error": "Άκυρο token"})
}

claims := token.Claims.(jwt.MapClaims)
c.Locals("userId", claims["id"])
c.Locals("isAdmin", claims["isAdmin"])

return c.Next()
}
}


6. Διαχειριστής Σύνδεσης (internal/handlers/auth.go)

Κώδικας [Επιογή]
// internal/handlers/auth.go
package handlers

import (
"time"
"github.com/gofiber/fiber/v2"
"golang.org/x/crypto/bcrypt"
"github.com/golang-jwt/jwt/v5"
"github.com/kullanicin/go-api-2025/internal/models"
"gorm.io/gorm"
)

var db *gorm.DB

func InitDB(database *gorm.DB) {
db = database
}

func Login(c *fiber.Ctx) error {
type LoginRequest struct {
Email    string `json:"email"`
Password string `json:"password"`
}

var req LoginRequest
if err := c.BodyParser(&req); err != nil {
return c.Status(400).JSON(fiber.Map{"error": "Άκυρα δεδομένα"})
}

var user models.User
if err := db.Where("email = ?", req.Email).First(&user).Error; err != nil {
return c.Status(401).JSON(fiber.Map{"error": "Ο χρήστης δεν βρέθηκε"})
}

if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(req.Password)); err != nil {
return c.Status(401).JSON(fiber.Map{"error": "Λάθος κωδικός"})
}

token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
"id":      user.ID,
"isAdmin": user.IsAdmin,
"exp":     time.Now().Add(time.Hour * 24 * 30).Unix(),
})

tokenString, _ := token.SignedString([]byte("super-secret-key-2025"))

return c.JSON(fiber.Map{
"message": "Επιτυχής είσοδος",
"token":   tokenString,
"user":    user,
})
}


7. Dockerfile (Εικόνα 15 MB!)

Κώδικας [Επιογή]
# Dockerfile
FROM golang:1.23-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o main ./cmd/api

FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /app/main .
EXPOSE 3000
CMD ["./main"]



8. Δωρεάν Ανάπτυξη στο Render.com
  • Δημιουργήστε αποθετήριο GitHub
  • render.com > New Web Service > Go seq
  • Build Command: go build -o main ./cmd/api
  • Start Command: ./main
  • Environment Variables:
    • DATABASE_URL=postgresql://...
    • PORT=3000
  • Deploy > Ζωντανό σε 15 δευτερόλεπτα!

Δοκιμή Απόδοσης (με k6)
Κώδικας [Επιογή]
k6 run script.js
# Αποτέλεσμα: 120.000+ req/s (1 CPU)


Πλήρης πηγαίος κώδικας (σε λειτουργία):
https://github.com/kullanicin/golang-api-2025
Ζωντανή demo:
https://golang-api-2025.onrender.com
#4
Η ASP[DOT]NET Core Identity είναι ένα ισχυρό και ευέλικτο σύστημα διαχείρισης ταυτοτήτων που χρησιμοποιείται για τη δημιουργία ασφαλών εφαρμογών με δυνατότητες εγγραφής, σύνδεσης και διαχείρισης χρηστών. Σε αυτό το άρθρο, θα σας καθοδηγήσουμε βήμα-βήμα στη διαδικασία εγκατάστασης της ASP[DOT]NET Core Identity σε ένα έργο, με πρακτικά παραδείγματα κώδικα. Αν είστε προγραμματιστής που θέλει να ενσωματώσει έλεγχο ταυτότητας στην εφαρμογή σας, αυτός ο οδηγός είναι ιδανικός για εσάς!

Τι είναι η ASP[DOT]NET Core Identity;
Η ASP[DOT]NET Core Identity είναι ένα πλαίσιο που παρέχει εργαλεία για τη διαχείριση χρηστών, κωδικών πρόσβασης, ρόλων και εξωτερικών παρόχων σύνδεσης (όπως Google ή Facebook). Υποστηρίζει τη βάση δεδομένων Entity Framework Core για την αποθήκευση δεδομένων και προσφέρει προσαρμοστικότητα για κάθε είδους εφαρμογή.

Βήματα Εγκατάστασης της ASP[DOT]NET Core Identity
Ακολουθήστε τα παρακάτω βήματα για να εγκαταστήσετε και να ρυθμίσετε την ASP[DOT]NET Core Identity:

1. Δημιουργία Νέου Έργου
Αρχικά, δημιουργήστε ένα νέο έργο ASP[DOT]NET Core μέσω του Visual Studio ή χρησιμοποιώντας την εντολή CLI:
Κώδικας [Επιογή]
dotnet new webapp -o MyIdentityApp
cd MyIdentityApp


2. Προσθήκη του Πακέτου ASP[DOT]NET Core Identity
Προσθέστε το πακέτο Microsoft.AspNetCore.Identity.EntityFrameworkCore μέσω του NuGet Package Manager ή με την εντολή:
Κώδικας [Επιογή]
dotnet add package Microsoft.AspNetCore.Identity.EntityFrameworkCore

3. Ρύθμιση του ApplicationDbContext
Δημιουργήστε μια κλάση που κληρονομεί από το IdentityDbContext για τη σύνδεση με τη βάση δεδομένων. Ανοίξτε το αρχείο Data/ApplicationDbContext.cs και προσθέστε:
Κώδικας [Επιογή]
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;

namespace MyIdentityApp.Data
{
    public class ApplicationDbContext : IdentityDbContext
    {
        public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
            : base(options)
        {
        }
    }
}


4. Ρύθμιση Υπηρεσιών στο Program.cs
Ανοίξτε το αρχείο Program.cs και προσθέστε τις υπηρεσίες Identity μαζί με τη σύνδεση στη βάση δεδομένων (π.χ. SQL Server):
Κώδικας [Επιογή]
var builder = WebApplication.CreateBuilder(args);

// Προσθήκη υπηρεσιών Identity
builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));

builder.Services.AddIdentity<IdentityUser, IdentityRole>()
    .AddEntityFrameworkStores<ApplicationDbContext>()
    .AddDefaultTokenProviders();

// Ρύθμιση Razor Pages
builder.Services.AddRazorPages();

var app = builder.Build();

// Middleware
app.UseAuthentication();
app.UseAuthorization();

app.MapRazorPages();
app.Run();


5. Ρύθμιση Connection String
Στο αρχείο appsettings.json, προσθέστε τη συμβολοσειρά σύνδεσης για τη βάση δεδομένων σας:
Κώδικας [Επιογή]
{
  "ConnectionStrings": {
    "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=MyIdentityDb;Trusted_Connection=True;MultipleActiveResultSets=true"
  }
}


6. Δημιουργία της Βάσης Δεδομένων
Εκτελέστε τις παρακάτω εντολές για να δημιουργήσετε τη βάση δεδομένων μέσω του Entity Framework:
Κώδικας [Επιογή]
dotnet add package Microsoft.EntityFrameworkCore.Design
dotnet ef migrations add CreateIdentitySchema
dotnet ef database update


7. Προσθήκη Σελίδων Εγγραφής και Σύνδεσης
Για να προσθέσετε τις βασικές σελίδες Identity (εγγραφή, σύνδεση, αποσύνδεση), χρησιμοποιήστε το scaffolding. Εκτελέστε:
Κώδικας [Επιογή]
dotnet aspnet-codegenerator identity -dc MyIdentityApp.Data.ApplicationDbContext

Αυτό θα δημιουργήσει τις απαραίτητες σελίδες Razor στο φάκελο Areas/Identity.

Παράδειγμα: Προσαρμογή του Μοντέλου Χρήστη
Αν θέλετε να προσθέσετε επιπλέον πεδία στο μοντέλο χρήστη, δημιουργήστε μια προσαρμοσμένη κλάση:
Κώδικας [Επιογή]
using Microsoft.AspNetCore.Identity;

namespace MyIdentityApp.Models
{
    public class ApplicationUser : IdentityUser
    {
        public string FullName { get; set; }
    }
}


Στη συνέχεια, ενημερώστε το ApplicationDbContext και το Program.cs:
Κώδικας [Επιογή]
// ApplicationDbContext.cs
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    // ...
}

// Program.cs
builder.Services.AddIdentity<ApplicationUser, IdentityRole>()
    .AddEntityFrameworkStores<ApplicationDbContext>()
    .AddDefaultTokenProviders();


Συμπέρασμα
Η εγκατάσταση της ASP[DOT]NET Core Identity είναι μια απλή διαδικασία που σας επιτρέπει να προσθέσετε ισχυρές δυνατότητες ελέγχου ταυτότητας και εξουσιοδότησης στις εφαρμογές σας. Με τα βήματα που περιγράψαμε και τα παραδείγματα κώδικα, μπορείτε να ξεκινήσετε άμεσα. Δοκιμάστε να προσαρμόσετε το σύστημα στις δικές σας ανάγκες και εξερευνήστε τις δυνατότητες που προσφέρει!
#5
Οι χώροι εκχώρησης στην PHP είναι βασικά εργαλεία που χρησιμοποιούνται για την ανάθεση τιμών σε μεταβλητές. Πέρα από την απλή εκχώρηση, η PHP προσφέρει μια σειρά από τελεστές που συνδυάζουν μαθηματικές, λογικές ή άλλες λειτουργίες, κάνοντας τον κώδικα πιο αποδοτικό και ευανάγνωστο. Σε αυτό το άρθρο, θα εξετάσουμε αναλυτικά τους χώρους εκχώρησης στην PHP, με πρακτικά παραδείγματα κώδικα για να κατανοήσετε τη χρήση τους. Αν είστε προγραμματιστής που επιθυμεί να εμβαθύνει στις δυνατότητες της PHP, αυτός ο οδηγός είναι ιδανικός για εσάς!

Τι είναι οι Χώροι Εκχώρησης στην PHP;
Οι χώροι εκχώρησης χρησιμοποιούνται για να "εκχωρούν" μια τιμή σε μια μεταβλητή. Ο πιο συνηθισμένος τελεστής είναι το σύμβολο =, το οποίο αναθέτει την τιμή από τα δεξιά στα αριστερά. Ωστόσο, η PHP περιλαμβάνει και συνδυαστικούς τελεστές που επιτρέπουν την εκτέλεση πράξεων ταυτόχρονα με την εκχώρηση.

Βασικοί Χώροι Εκχώρησης στην PHP
Ας δούμε τους πιο δημοφιλείς χώρους εκχώρησης στην PHP:
  • Απλή Εκχώρηση (=)
     Αναθέτει μια τιμή σε μια μεταβλητή.

    Κώδικας [Επιογή]
    <?php
    $αριθμός
    = 10;
    echo
    $αριθμός; // Εμφανίζει: 10
    ?>

  • Πρόσθεση και Εκχώρηση (+=)
     Προσθέτει την τιμή στα δεξιά στη μεταβλητή και αποθηκεύει το αποτέλεσμα.

    Κώδικας [Επιογή]
    <?php
    $αριθμός
    = 5;
    $αριθμός += 3; // $αριθμός γίνεται 8
    echo $αριθμός; // Εμφανίζει: 8
    ?>

  • Αφαίρεση και Εκχώρηση (-=)
     Αφαιρεί την τιμή στα δεξιά από τη μεταβλητή.

    Κώδικας [Επιογή]
    <?php
    $αριθμός
    = 10;
    $αριθμός -= 4; // $αριθμός γίνεται 6
    echo $αριθμός; // Εμφανίζει: 6
    ?>

  • Πολλαπλασιασμός και Εκχώρηση (*=)
     Πολλαπλασιάζει τη μεταβλητή με την τιμή στα δεξιά.

    Κώδικας [Επιογή]
    <?php
    $αριθμός
    = 3;
    $αριθμός *= 2; // $αριθμός γίνεται 6
    echo $αριθμός; // Εμφανίζει: 6
    ?>

  • Διαίρεση και Εκχώρηση (/=)
     Διαιρεί τη μεταβλητή με την τιμή στα δεξιά.

    Κώδικας [Επιογή]
    <?php
    $αριθμός
    = 20;
    $αριθμός /= 5; // $αριθμός γίνεται 4
    echo $αριθμός; // Εμφανίζει: 4
    ?>

  • Υπόλοιπο και Εκχώρηση (%=)
     Υπολογίζει το υπόλοιπο της διαίρεσης και το αναθέτει στη μεταβλητή.

    Κώδικας [Επιογή]
    <?php
    $αριθμός
    = 17;
    $αριθμός %= 5; // $αριθμός γίνεται 2
    echo $αριθμός; // Εμφανίζει: 2
    ?>

  • Συνένωση και Εκχώρηση (.=)
     Συνενώνει συμβολοσειρές και αποθηκεύει το αποτέλεσμα.

    Κώδικας [Επιογή]
    <?php
    $κείμενο
    = "Γειά ";
    $κείμενο .= "σου!"; // $κείμενο γίνεται "Γειά σου!"
    echo $κείμενο; // Εμφανίζει: Γειά σου!
    ?>


Γιατί να Χρησιμοποιήσετε τους Χώρους Εκχώρησης;
Οι χώροι εκχώρησης στην PHP δεν είναι απλώς συντομογραφίες. Βελτιώνουν την αναγνωσιμότητα του κώδικα και μειώνουν τον χρόνο συγγραφής του. Για παράδειγμα, αντί να γράψετε $αριθμός = $αριθμός + 5, μπορείτε απλά να χρησιμοποιήσετε $αριθμός += 5. Αυτό είναι ιδιαίτερα χρήσιμο σε μεγαλύτερα προγράμματα ή επαναληπτικές διαδικασίες.

Πρακτικό Παράδειγμα: Υπολογισμός Συνόλου
Ας δούμε ένα παράδειγμα όπου χρησιμοποιούμε πολλούς χώρους εκχώρησης:
Κώδικας [Επιογή]
<?php
$σύνολο
= 100; // Αρχική τιμή
$σύνολο += 20; // Προσθέτουμε 20
$σύνολο -= 10; // Αφαιρούμε 10
$σύνολο *= 2; // Διπλασιάζουμε το αποτέλεσμα

echo "Το τελικό σύνολο είναι: " . $σύνολο; // Εμφανίζει: Το τελικό σύνολο είναι: 220
?>


Συμπέρασμα
Οι χώροι εκχώρησης στην PHP είναι απαραίτητοι για κάθε προγραμματιστή που θέλει να γράφει αποδοτικό και καθαρό κώδικα. Από την απλή εκχώρηση με το = μέχρι τη συνένωση συμβολοσειρών με το .=, οι δυνατότητες είναι πολλές. Δοκιμάστε τα παραδείγματα που δώσαμε και πειραματιστείτε στον δικό σας κώδικα για να εξοικειωθείτε πλήρως!