.csproj Dosyasına Elveda mı? .NET 10 ile Yepyeni Kodlama Deneyimi konusunu anlatan renkli 3D teknik illüstrasyon

Projesiz C#, .NET 10 SDK ile tek bir .cs dosyasını ayrı bir .csproj oluşturmadan derleyip çalıştırmayı sağlar. Microsoft bu yaklaşımı file-based apps olarak adlandırıyor. Küçük CLI araçlarında ve prototiplerde başlangıcı sadeleştirir; büyüyen uygulamalarda ise klasik proje yapısının sağladığı organizasyon hâlâ değerlidir.

projesiz_akisi

Akış şemasındaki #package ve #sdk etiketlerinin C# dosyasında geçerli karşılığı #:package ve #:sdk biçimindedir. SDK kaynak kodu derler; ilk çalıştırmada restore ve build maliyetini hesaba katın.

1. Projesiz C# ve klasik proje akışı

1.1 Eskiden Nasıldı?

  • Klasik .NET CLI akışında dotnet new console ile proje oluşturur, bağımlılık ve derleme ayarlarını .csproj üzerinden yönetirsiniz. C# Interactive gibi başka deneme araçları da vardır; file-based app bu proje akışına ek bir seçenektir.
  • Tüm bağımlılıklar, paketler ve derleme ayarları .csproj dosyasında tutulurdu.
  • File-based app bir yorumlanan script değildir. SDK arka planda proje yapılandırmasını oluşturup normal C# programını derler; sizin ayrı bir .csproj yazmanız gerekmez.

1.2 .NET 10 ile Neler Değişti?

  • Artık tek bir .cs dosyasıyla, projesiz doğrudan geliştirme mümkün.
  • Dosyanın başındaki #:package ve #:sdk direktifleri, paket referanslarını ve MSBuild SDK türünü belirtir. #:sdk, kurulu .NET SDK sürümünü seçmez; bu seçim için global.json ve SDK kurulumunu kullanırsınız.
  • Terminalde dotnet run –file dosya.cs ile çalıştırın. Aynı klasörde .csproj varsa –file kullanmadan dotnet run dosya.cs yazmak mevcut projeyi çalıştırıp dosya adını argüman olarak iletebilir.

csproj-giris

2. #:package ve #:sdk Direktifleriyle Bağımlılık Yönetimi

2.1 #:package Kullanımı

File-based app dosyasının başında paket referanslarını şöyle tanımlayabilirsiniz:

#:package Newtonsoft.Json@13.0.4
#:package Dapper@2.0.123
#:property PublishAot=false
using Newtonsoft.Json;
using Dapper;

Console.WriteLine(JsonConvert.SerializeObject(new { Message = "Merhaba" }));
  • Çoklu paket desteği: Dilediğin kadar farklı paketi başa ekleyebilirsin.
  • Sürüm belirtme: Paket adı ile sürüm arasına @ koyun; örneğin #:package Newtonsoft.Json@13.0.4. Merkezi paket yönetimi yoksa sürümü belirtin. @* kullanmak sürümü sabitlemez; örneklerin tekrar üretilebilirliğini azaltır.

2.2 #:sdk Direktifi

Web SDK türünü seçip küçük bir endpoint oluşturmak için:

#:sdk Microsoft.NET.Sdk.Web
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/", () => "Merhaba");
app.Run();
  • Varsayılan SDK Microsoft.NET.Sdk’dir; web uygulaması için Microsoft.NET.Sdk.Web seçebilirsiniz. TargetFramework gibi MSBuild ayarlarını #:property ile belirtin. .NET SDK sürümünü bununla karıştırmayın.

3. Projesiz C# kod örnekleri

3.1 Hızlı Komut Satırı Araçları

Tek dosyada, mevcut klasördeki PNG dosyalarını bir ZIP arşivine eklemek:

using System.IO.Compression;

var output = "tum_resimler.zip";
if (File.Exists(output))
{
    Console.Error.WriteLine(
        "Arşiv zaten var; farklı ad seçin veya mevcut dosyayı inceleyin."
    );
    return 1;
}

var pngs = Directory.GetFiles(Directory.GetCurrentDirectory(), "*.png");
using var archive = ZipFile.Open(output, ZipArchiveMode.Create);
foreach (var file in pngs)
    archive.CreateEntryFromFile(file, Path.GetFileName(file));
Console.WriteLine("PNG dosyaları arşive eklendi.");
return 0;

3.2 Hızlı JSON İşleme ve API Tüketimi

#:package Newtonsoft.Json@13.0.4
#:property PublishAot=false
using Newtonsoft.Json.Linq;

using var client = new HttpClient { Timeout = TimeSpan.FromSeconds(15) };
try
{
    var data = await client.GetStringAsync("https://randomuser.me/api/");
    var user = JObject.Parse(data)["results"]?.FirstOrDefault()?["name"];
    if (user?["first"] is null || user["last"] is null)
    {
        Console.Error.WriteLine("API yanıtında beklenen isim alanları yok.");
        return 1;
    }
    Console.WriteLine($"İsim: {user["first"]} {user["last"]}");
    return 0;
}
catch (Exception ex) when (ex is HttpRequestException or TaskCanceledException or Newtonsoft.Json.JsonException)
{
    Console.Error.WriteLine($"API verisi alınamadı veya ayrıştırılamadı: {ex.Message}");
    return 1;
}

3.3 CLI ile Mini Oyun veya Eğitim Scripti

Console.WriteLine("Bir sayı tahmin et (1-10):");
int dogru = Random.Shared.Next(1, 11);
if (
    !int.TryParse(Console.ReadLine(), out int tahmin)
    || tahmin is < 1 or > 10
)
{
    Console.Error.WriteLine("1 ile 10 arasında bir tam sayı girin.");
    return 1;
}
Console.WriteLine(
    tahmin == dogru ? "Doğru tahmin!" : $"Doğru cevap: {dogru}"
);
return 0;

3.4 Veritabanı Bağlantısı ve Kayıt İşlemleri

#:package System.Data.SQLite.Core@1.0.119
#:property PublishAot=false
using System.Data.SQLite;

using var conn = new SQLiteConnection("Data Source=demo.db");
conn.Open();
using (var create = new SQLiteCommand("CREATE TABLE IF NOT EXISTS notes (id INTEGER PRIMARY KEY, text TEXT)", conn))
    create.ExecuteNonQuery();
using var insert = new SQLiteCommand("INSERT INTO notes (text) VALUES (@text)", conn);
insert.Parameters.AddWithValue("@text", "Merhaba, dünya!");
insert.ExecuteNonQuery();
Console.WriteLine("Not eklendi!");

4. Gerçek Dünya Kullanım Senaryoları

4.1 Data Science & Hızlı Veri Analizi

  • Excel veya CSV verisi okuyup istatistik çıkarmak için tek dosya script
  • Örneğin: CSV dosyalarının fiziksel satır sayısını bulmak. Aşağıdaki örnek sütunları veya CSV kayıtlarını ayrıştırmaz; tırnak içindeki çok satırlı alanlar nedeniyle satır sayısı kayıt sayısından farklı olabilir.
using System.IO;

var files = Directory.GetFiles(
    Directory.GetCurrentDirectory(),
    "*.csv"
);
foreach (var file in files)
{
    var count = File.ReadLines(file).LongCount();
    Console.WriteLine(
        $"{Path.GetFileName(file)}: {count} fiziksel satır"
    );
}

4.2 Otomasyon ve Batch İşlemler

  • Klasördeki resimleri yeniden adlandırmak veya boyutlandırmak için küçük script’ler
  • Sunucuya otomatik yedekleme için gece çalışan mini kodlar

4.3 Eğitim, Demo ve Topluluk Paylaşımı

  • StackOverflow, blog, Github gibi ortamlarda paylaşılacak örnek kodlar
  • Kaynak kodu tek dosya olarak paylaşabilirsiniz; çalıştıracak kişinin uyumlu .NET SDK’ya, paket kaynaklarına ve gerekiyorsa native bağımlılıklara erişimi olmalıdır.

5. Projesiz ve Klasik C# Proje Akışının Karşılaştırılması

Özellik Projesiz C# (.NET 10+) Klasik Proje (.csproj)
Başlangıç Tek dosya ile Proje gerekir; solution isteğe bağlı
Paket yönetimi #:package ile baştan eklenir NuGet & .csproj ile
SDK ayarı #:sdk ile .csproj’a eklenir
Derleme/Çalıştırma dotnet run dosya.cs dotnet run
Hedef Script, CLI, hızlı deneme Büyük uygulama, prod kod
Sürüm Yönetimi Paket sürümleri dosyada; .NET SDK seçimi global.json ile Paketler .csproj/merkezi yönetimde; .NET SDK seçimi global.json ile
Dosya Sayısı Tek giriş dosyası; #:include desteği SDK sürümüne bağlı Çoklu dosya
IDE Desteği Editör ve C# araçlarının sürümüne bağlı Gelişmiş (Visual Studio)

6. Projesiz C# hangi işleri kolaylaştırır?

  • Zamandan Tasarruf: Proje oluştur, ayar yap, NuGet config ile uğraş derdi yok.
  • Taşınabilirlik: Kaynak dosyayı paylaşmak kolaydır; ancak kullanılan paketlerin ve native bileşenlerin platform desteğini ayrıca kontrol edin.
  • Karmaşıklıktan Kurtuluş: Küçük işler için proje şişkinliği yok.
  • Bağımlılık yönetimi: #:package ile NuGet paketlerini dosyada tanımlayabilirsiniz. Restore, ağ ve NuGet yapılandırması gereksinimlerini ortadan kaldırmaz.
  • Eğitimde Kolaylık: Öğrencilere, geliştiricilere “projesiz” hızlı deneme imkanı.
  • Geliştirici Deneyimi: Hızlı prototip ve hata ayıklama için birebir.

7. Sınırlar ve bakım maliyeti

  • Büyük Proje Yönetimi Zor: Script büyüdükçe takip ve bakım güçleşir.
  • Dosya organizasyonu: .NET SDK 10.0.300 ve sonrasında #:include ile ek C# dosyalarını dahil edebilirsiniz. Bu dosyalar ek top-level statements içeremez; büyük çözümde proje sınırlarını açık tutmak yine önemlidir.
  • IDE desteği: Editör ve C# araçlarının sürümüne bağlıdır. Güncel araçları kontrol edin; refactoring veya IntelliSense için her durumda .csproj zorunlu olduğu iddiası doğru değildir.
  • CI/CD: dotnet build dosya.cs ve dotnet publish dosya.cs ile pipeline kurabilirsiniz. SDK, paket sürümleri, secret yönetimi ve test adımlarını açıkça tanımlayın.
  • Yayınlama/dağıtım: File-based app publish destekler. Native AOT varsayılan olabilir; dynamic/reflection kullanan paketlerde uyumluluğu doğrulayın veya #:property PublishAot=false ile JIT dağıtımı seçin.

8. Sık Yapılan Hatalar & İpuçları

  • #:package satırında paket adı/sürümünü yanlış yazmak → derleme hatası alırsın.
  • Çoklu paket eklerken, sürüm çakışmasına dikkat et.
  • Script dosyasını gereğinden fazla büyütüp, bir “spaghetti code”a dönüştürmekten kaçın.
  • Üretim için seçimde kaynak dosyası sayısından önce test, gözlemlenebilirlik, bağımlılık ve deployment gereksinimlerini değerlendirin. Kritik ve büyüyen uygulamalarda klasik proje yapısı bakım açısından daha uygun olabilir.
  • Script dosyanı, platform bağımsız çalışacak şekilde (örn. yol ayrımları) yazmaya dikkat et.

9. İleri Seviye Kod Örnekleri

9.1 Dış Servis ile Entegrasyon (Mail Gönderme)

#:package MailKit@4.17.0
using MailKit.Net.Smtp;
using MailKit.Security;
using MimeKit;

string Required(string name) => Environment.GetEnvironmentVariable(name)
    ?? throw new InvalidOperationException($"{name} ortam değişkeni gerekli.");

var mesaj = new MimeMessage();
mesaj.From.Add(MailboxAddress.Parse(Required("SMTP_FROM")));
mesaj.To.Add(MailboxAddress.Parse(Required("SMTP_TO")));
mesaj.Subject = "Test Mail";
mesaj.Body = new TextPart("plain") { Text = "Selamlar!" };

using var smtp = new SmtpClient { Timeout = 15000 };
await smtp.ConnectAsync(Required("SMTP_HOST"), 587, SecureSocketOptions.StartTls);
await smtp.AuthenticateAsync(Required("SMTP_USER"), Required("SMTP_PASSWORD"));
await smtp.SendAsync(mesaj);
await smtp.DisconnectAsync(true);
Console.WriteLine("E-posta gönderildi!");

9.2 Web Scraping (HTML’den Veri Çekme)

#:package HtmlAgilityPack@1.12.4
using HtmlAgilityPack;

using var client = new HttpClient { Timeout = TimeSpan.FromSeconds(15) };
var source = await client.GetStringAsync("https://news.ycombinator.com/");
var doc = new HtmlDocument();
doc.LoadHtml(source);
var basliklar = doc.DocumentNode.SelectNodes("//span[contains(concat(' ', normalize-space(@class), ' '), ' titleline ')]/a[1]");
if (basliklar is null)
{
    Console.Error.WriteLine("Başlık bulunamadı; sayfa yapısını kontrol edin.");
    return 1;
}
foreach (var b in basliklar)
    Console.WriteLine(HtmlEntity.DeEntitize(b.InnerText));
return 0;

9.3 CSV’den JSON’a Dönüştürme

#:package CsvHelper@33.1.0
#:package Newtonsoft.Json@13.0.4
#:property PublishAot=false
using System.IO;
using CsvHelper;
using Newtonsoft.Json;
using System.Globalization;

using var reader = new StreamReader("veri.csv");
using var csv = new CsvReader(reader, CultureInfo.InvariantCulture);
var kayitlar = csv.GetRecords<dynamic>().ToList();
var json = JsonConvert.SerializeObject(kayitlar, Formatting.Indented);
File.WriteAllText("veri.json", json);
Console.WriteLine("Dönüşüm tamamlandı!");

10. Sıkça sorulan sorular

.csproj tamamen bitiyor mu?
Hayır. Projesiz C# küçük araçların başlangıcını sadeleştirir. Büyüyen uygulamalarda proje ve solution yapısı, test ve dependency sınırlarını yönetmeyi kolaylaştırır.

Her platformda çalışır mı?
Uyumlu .NET 10 SDK gerekir; yalnız runtime yeterli değildir. Paket, native bağımlılık ve API’lerin platform desteğini ayrıca kontrol edin.

Birden fazla C# dosyası kullanabilir miyim?
.NET SDK 10.0.300 ve sonrasında #:include desteği vardır. Dahil edilen dosyalar tip ve metot tanımlayabilir, ek top-level statements içeremez. Daha eski SDK’da bu desteği varsaymayın.

Paket çakışması olursa ne olur?
Restore veya build çıktısını inceleyin; paket sürümlerini ve transitive dependency uyumunu kontrol edin.

Yayımlayabilir miyim?
Evet, dotnet publish dosya.cs desteklenir. Native AOT için platform toolchain’i ve paket uyumluluğunu doğrulayın. Örneklerdeki dynamic/reflection kullanımları için PublishAot=false belirtilmiştir.

JSON ve CSV örnekleri küçük veri içindir; tüm sonuçları belleğe alma maliyetini büyük dosyalarda ayrıca değerlendirin. SQLite örneğini yeniden çalıştırmak yeni bir not ekler. Mail örneği gerçek SMTP bilgileri ve gönderim yetkisi gerektirir; credential’ları kaynak koduna yazmayın. Scraping selector’ı hedef sitenin HTML’i değiştiğinde yeniden kontrol edin.

Temel komut ve direktifler için Microsoft’un file-based apps referansını inceleyin. Uygulama büyüdüğünde test sınırlarını kurmak için Dependency Injection rehberi de yardımcı olabilir.

11. Kaynaklar

By tanju.bozok

Senior .NET Engineer | Backend architecture, distributed systems & real-time communication