ASP.NET Core 6/Web Servisleri/Örnek Projemiz
Bu kısımda kitabın Web Servisleri bölümü için kullanılacak örnek proje oluşturulacaktır. Şimdi ASP.NET Core Empty şablonuyla WebApp isimli bir proje oluşturalım. Projenin launchSetting.json dosyasında profiles:WebApp:applicationUrl girdisinde değişiklik yaparak sunucunun 5000 portunda dinlemesini sağlayalım. Ayrıca profiles:WebApp:launchBrowser girdisini false yapalım ki sunucuyu başlattığımızda tarayıcı otomatik olarak açılmasın.
Model sınıflarının eklenmesi
[değiştir]Projemiz veritabanına okuyup yazacak. Öncelikle NuGet Paket Yöneticisinden Microsoft.EntityFrameworkCore.Design ve Microsoft.EntityFrameworkCore.SqlServer paketlerinin 6.0.0 versiyonlarını kuralım. Şimdi model sınıflarımızı oluşturalım. Projenizin ana klasöründe Models isimli bir klasör oluşturun ve içinde ismi Category.cs olan aşağıdaki sınıfı oluşturun:
namespace WebApp.Models
{
public class Category
{
public long CategoryId { get; set; }
public string Name { get; set; }
public IEnumerable<Product> Products { get; set; }
}
}
Şimdi Models klasöründe Supplier.cs isimli bir sınıf oluşturun ve içeriği şöyle olsun:
namespace WebApp.Models
{
public class Supplier
{
public long SupplierId { get; set; }
public string Name { get; set; } = string.Empty;
public string City { get; set; } = string.Empty;
public IEnumerable<Product>? Products { get; set; }
}
}
Şimdi Models klasörüne Product.cs isimli bir sınıf ekleyelim ve içeriği şöyle olsun:
using System.ComponentModel.DataAnnotations.Schema;
namespace WebApp.Models
{
public class Product
{
public long ProductId { get; set; }
public string Name { get; set; }
[Column(TypeName = "decimal(8, 2)")]
public decimal Price { get; set; }
public long CategoryId { get; set; }
public Category Category { get; set; }
public long SupplierId { get; set; }
public Supplier Supplier { get; set; }
}
}
Burada Price özelliği için veritabanında seçilecek tipi decimal(8, 2) olduğunu belirttik. Yani ilgili sayı 8 haneden oluşacak ve ondalık kısmı 2 haneli olacak diyoruz. Her .NET tipinin veritabanı kısmında tam bir karşılığı olmayabilir. Bu tür durumlarda ilgili özelliğin veritabanı tipini elle belirtiriz. Her bir sınıfta Id değerleri vardır. Bunlar elle girilmeyecektir. Veriler veritabanına gönderildikten sonra veritabanı tarafından otomatik atanacaktır. Her bir sınıfta navigasyon özellikleri vardır. Bunlar iki karmaşık tip arasında bağlantı kurmaktadır. Örneğin Category sınıfındaki Products özelliği ilgili kategorideki ürünleri verecektir.
Bağlam sınıfının oluşturulması
[değiştir]Şimdi .NET nesneleriyle veritabanı arasında köprü görevi görecek olan bağlam sınıfını şöyle oluşturalım (Models klasöründe ve ismi DataContext.cs olsun):
using Microsoft.EntityFrameworkCore;
namespace WebApp.Models
{
public class DataContext : DbContext
{
public DataContext(DbContextOptions<DataContext> opts) : base(opts) { }
public DbSet<Product> Products => Set<Product>();
public DbSet<Category> Categories => Set<Category>();
public DbSet<Supplier> Suppliers => Set<Supplier>();
}
}
Veritabanını seed'leyen sınıfın oluşturulması
[değiştir]Şimdi Models klsörüne ismi SeedData.cs olan ve içeriği aşağıdaki gibi olan sınıfı ekleyin:
using Microsoft.EntityFrameworkCore;
namespace WebApp.Models
{
public static class SeedData
{
public static void SeedDatabase(DataContext context)
{
context.Database.Migrate();
if (context.Products.Count() == 0 && context.Suppliers.Count() == 0 && context.Categories.Count() == 0)
{
Supplier s1 = new Supplier { Name = "Splash Dudes", City = "San Jose" };
Supplier s2 = new Supplier { Name = "Soccer Town", City = "Chicago" };
Supplier s3 = new Supplier { Name = "Chess Co", City = "New York" };
Category c1 = new Category { Name = "Watersports" };
Category c2 = new Category { Name = "Soccer" };
Category c3 = new Category { Name = "Chess" };
context.Products.AddRange(
new Product { Name = "Kayak", Price = 275, Category = c1, Supplier = s1 },
new Product { Name = "Lifejacket", Price = 48.95m, Category = c1, Supplier = s1 },
new Product { Name = "Soccer Ball", Price = 19.50m, Category = c2, Supplier = s2 },
new Product { Name = "Corner Flags", Price = 34.95m, Category = c2, Supplier = s2 },
new Product { Name = "Stadium", Price = 79500, Category = c2, Supplier = s2 },
new Product { Name = "Thinking Cap", Price = 16, Category = c3, Supplier = s3 },
new Product { Name = "Unsteady Chair", Price = 29.95m, Category = c3, Supplier = s3 },
new Product { Name = "Human Chess Board", Price = 75, Category = c3, Supplier = s3 },
new Product { Name = "Bling-Bling King", Price = 1200, Category = c3, Supplier = s3 }
);
context.SaveChanges();
}
}
}
}
Bu kod her zamankş gibi bekleyen bir migration varsa migrate yapmakta ve sonra veritabanında ürün, kategori ve tedarikçi yoksa verileri oluşturup veritabanına yazmaktadır.
Entity Framework Core'un etkinleştirilmesi
[değiştir]Model sınıflarımız, bağlam sınıfımız ve veri beslemesi yapacak sınıfımız hazır olduğuna göre şimdi Entity Framework'u etkileştirerek yapılandırmaya sıra geldi. Şimdi Program.cs dosyasını şöyle değiştirelim:
using Microsoft.EntityFrameworkCore;
using WebApp.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<DataContext>(opts => {
opts.UseSqlServer(builder.Configuration["ConnectionStrings:ProductConnection"]);
opts.EnableSensitiveDataLogging(true);
});
var app = builder.Build();
app.MapGet("/", () => "Hello World!");
var context = app.Services.CreateScope().ServiceProvider.GetRequiredService<DataContext>();
SeedData.SeedDatabase(context);
app.Run();
Burada SeedData sınıfının SeedDatabase() metodunun ihtiyaç duyduğu context nesnesini oluşturup SeedDatabase() metoduna verdik. Şimdi appsettings.json dosyasını şöyle güncelleyelim:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning",
"Microsoft.EntityFrameworkCore": "Information"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"ProductConnection": "Server=DESKTOP-J5SDIAM;Database=Products;Trusted_Connection=True;MultipleActiveResultSets=true;"
}
}
Burada veritabanına bağlantı için connection string'i belirtme yanında Microsoft.EntityFrameworkCore için loglama seviyesini Information yaptık. Bu sayede Entity Framework Core tarafından oluşturulan SQL sorgularını görebileceğiz.
Migration'ın oluşturulup uygulanması
[değiştir]Şimdi "Geliştirici PowerShell" pencereciğinde aşağıdaki iki komutu sırayla verin:
dotnet ef migrations add Initial dotnet ef database update
İlk komut migration'ı yapacak olan sınıfı oluşturmakta, ikinci komut ise migration'ı uygulamaktadır.
Programımızın çalışıp çalışmadığını test etme
[değiştir]Aslında programımız şu anda hazır. Ama programımızın çalışıp çalışmadığını test etmemiz gerekiyor. Bunun için bir test middleware'i yazacağız. İsmi TestMiddleware.cs olan ve içeriği aşağıdaki gibi olan dosyayı projenizin ana klasöründe oluşturun:
using WebApp.Models;
namespace WebApp
{
public class TestMiddleware
{
private RequestDelegate nextDelegate;
public TestMiddleware(RequestDelegate next)
{
nextDelegate = next;
}
public async Task Invoke(HttpContext context, DataContext dataContext)
{
if (context.Request.Path == "/test")
{
await context.Response.WriteAsync($"There are {dataContext.Products.Count()} products\n");
await context.Response.WriteAsync($"There are {dataContext.Categories.Count()} categories\n");
await context.Response.WriteAsync($"There are {dataContext.Suppliers.Count()} suppliers\n");
}
else
{
await nextDelegate(context);
}
}
}
}
Bu middleware "/test" path'ına karşılık vermekte ve veritabanındaki ürün, kategori ve tedarikçi sayılarını ekrana yazmakatdır. Şimdi bu middleware'i request pipeline'a ekleyelim (Program.cs dosyası):
using Microsoft.EntityFrameworkCore;
using WebApp.Models;
using WebApp;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<DataContext>(opts => {
opts.UseSqlServer(builder.Configuration["ConnectionStrings:ProductConnection"]);
opts.EnableSensitiveDataLogging(true);
});
var app = builder.Build();
app.UseMiddleware<TestMiddleware>();
app.MapGet("/", () => "Hello World!");
var context = app.Services.CreateScope().ServiceProvider.GetRequiredService<DataContext>();
SeedData.SeedDatabase(context);
app.Run();
Programı çalıştırıp /test path'ına talepte bulunduğunuzda aşağıdaki gibi bir çıktı görmeniz lazım:
There are 9 products There are 3 categories There are 3 suppliers