Asp.NET Core 2 MVC İle Neler Değişti? Genel Bakış
Merhaba,
Uzun zamandır Asp.NET Core 2 MVC’de klasik Asp.NET MVC’ye nazaran hangi noktalarda değişiklik gerçekleştirildiğine dair genel bakış maksatlı makale yazmayı planlıyordum. Bu planım doğrultusunda şimdi gelin Asp.NET Core 2 MVC’de gelen yenilikleri ve değişiklikleri parsel parsel özetleyelim.
Asp.NET Core 2 MVC Projesinin Ayağa Kaldırılması
İlk olarak bir Asp.NET Core 2 MVC projesinin nasıl ayağa kaldırıldığına dair tüm yapıya değinmemiz gerekmektedir. Asp.NET Core 2 MVC projesi oluşturabilmek için Visual Studio editöründe klasik “File” -> “New” -> “Project” kombinasyonu üzerinden “ASP.NET Core Web Appllication” projesini seçiyoruz.
Ardından gelen pencereden “Empty”i seçerek boş bir proje oluşturuyoruz.
Açılan projenin Solution Explorer penceresinden dosyalarına göz atarsak eğer;
Görüldüğü üzere “Dependencies” ve “Properties” alanlarıyla birlikte “wwwroot” klasörü ve “Program.cs” ve “Startup.cs” dosyaları mevcuttur. Bu klasör ve dosyaları izah etmemiz gerekirse eğer;
- Dependencies Alanı
Projede kullanılan Nuget vs. modüllerinin tutulduğu alandır. Klasik Asp.NET MVC’de ki ‘References’ klasörüne denk düşmektedir. - Properties Alanı
Projeyle ilgili temel başlangıç ayarlarının tutulduğu alan. - wwwroot Klasörü
Projede kullanılacak CSS, JavaScript, Image vs. dosyalarının tutulacağı klasör. - Program.cs
Asp.NET Core uygulamalarında host yapısı klasik Asp.NET mimarisine nazaran köklü değişikliklere tabi tutulmuştur. Bizler “Program.cs” dosyasını Console Application projelerinden tanıyoruz. Asp.NET Core mimarisinde “Program.cs” dosyasının bulunması Asp.NET Core uygulamalarının aslında bir Console Application uygulaması olduğu anlamına geliyor. Bu da ilgili mimarinin executable(çalıştırılabilir) bir alt yapıda olduğunu ve entry pointe(başlangıç noktası) sahip olduğunu ifade etmektedir. İşte bu başlangıç noktası “Program.cs” de ki static Main metodudur.Şimdi “Program.cs” sınıfında neler yapılıyor bakalım;public class Program { public static void Main(string[] args) { CreateWebHostBuilder(args).Build().Run(); } public static IWebHostBuilder CreateWebHostBuilder(string[] args) => WebHost.CreateDefaultBuilder(args) .UseStartup<Startup>(); }
Dikkat ederseniz Main metodunda “CreateWebHostBuilder” isimli metodu çağırararak bir host inşa etmekte ve bunu çalıştırmaktadır. İlgili metot içerisine göz atarsak eğer başlangıç sınıfı olarak “Startup” sınıfını belirtmektedir.
- Startup.cs
Projemizde herbir kullanıcı ile yapılan etkileşim neticesinde bir sürece girilmektedir. İşte o süreci “Startup” sınıfında kontrol edebilmekteyiz. “Startup” sınıfı aslında bir Middleware özelliği görmektedir. Yapısal olarak;public class Startup { public void ConfigureServices(IServiceCollection services) { //Uygulamada kullanılacak servisleri burada belirterek projeye dahil ediyoruz. } public void Configure(IApplicationBuilder app, IHostingEnvironment env) { //Çalışma zamanında tetiklenen ayar fonksiyonudur. if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.Run(async (context) => { await context.Response.WriteAsync("Hello World!"); }); } }
şeklinde bir yapıya sahiptir.
Projemizi ayağa kaldırırken “Startup” sınıfında aşağıdaki ayarları yapabiliriz.public class Startup { public void ConfigureServices(IServiceCollection services) { //MVC modülünü projemizde yapılandıralım. services.AddMvc(); } public void Configure(IApplicationBuilder app, IHostingEnvironment env) { //Varsayılan route yapılanmasıyla MVC'yi kullanabiliriz. //app.UseMvcWithDefaultRoute(); //Ya da route yapılanmasını manuel oluşturmak kaydıyla MVC'yi kullanabiliriz. app.UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}" ); routes.MapRoute( name: "About", template: "about", defaults: new { controller = "Home", action = "About" } ); }); //Uygulamadaki wwwroot klasörünün içerisindeki tüm dosyalara proje genelinden static bir şekilde erişim izni vermek için UseStaticFiles fonksiyonu ile ilgili dosyayı erişime açıyoruz. app.UseStaticFiles(); //Projede alınan hataların kullanıcıya gösterilmesini isteyebiliriz. //app.UseDeveloperExceptionPage(); //Ya da sadece development esnasındaysak kullanıcılara hata sayfasını gösterebiliriz. if (env.IsDevelopment()) app.UseDeveloperExceptionPage(); //Aranılan kaynak bulunamadığı durumlarda 404 hatasının kullanıcıya göterilmesini istiyorsak UseStatusCodePages fonksiyonu çağırmamız yeterlidir. app.UseStatusCodePages(); } }
Genel olarak kod üzerine kullanılan fonksiyonların açıklamalarını yapmış bulunmaktayım.
Evet… Proje dosyalarımızın ne olduğunu gördük, alt yapı olarak MVC olacak şekilde gerekli ayarlamaları gerçekleştirdik. Şimdi projemizin ana dizinine “Models”, “Views” ve “Controllers” isimlerinde üç adet klasör oluşturuyoruz ve Asp.NET Core 2 MVC projemizi bu şekilde ayağa kaldırmış oluyoruz…
_ViewImports Dosyası İle Global Yapılanma
Klasik Asp.NET MVC’de .cshtml dosyalarına model tanımlarken ya modelin bulunduğu namespaceleri tam olarak belirtmemiz gerekmekteydi ya da web.config’den modellerin bulunduğu namespace’i tüm viewlere global bir şekilde bir kere tanımlayıp sunmamız yeterliydi. Asp.NET Core 2 MVC’de artık web.config dosyası bulunmadığından dolayı bu işlevi “_ViewImports.cshtml” dosyası üstlenmektedir.
@model CoreExample.Web.Models.Employee <h2>Employee</h2>
Yukarıdaki örnek .cshtml sayfasında olduğu gibi model tanımlanırken modelin bulunduğu tüm namespaceleri belirtmemiz gerekmektedir. Şimdi bu namespace’i tüm viewlere global olarak tanımlamak istiyorsak ilgili klasöre Razor View Imports dosyasını “_ViewImports.cshtml” isminde eklemeniz gerekmektedir.
İlgili dosyanın içeriğini aşağıdaki gibi şekillendirirsek;
@using CoreExample.Web.Models
Artık bu namespace global olarak tutulacağı için view dosyalarında direkt olarak ilgili modeli namespace’i belirtmeksizin çağırabilmekteyiz.
@model Employee <h2>Employee</h2>
Tag Helper Yapılanması
Klasik Asp.NET MVC’de ki Html.Helper altındaki tüm helper metotları gitti yerine tag helperlar geldi.
Tag helperları kullanabilmek için kullanılacağı sayfanın en üst satırına aşağıdaki kodu eklemeniz gerekmektedir.
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
ya da tek tek view dosyalarına eklemekle uğraşmaktansa “_ViewImports.cshtml” dosyasına da ekleyebilirsiniz.
@using CoreExample.Web.Models @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
Bu işlemden sonra tag helperları aşağıdaki gibi kullanabilirsiniz.
@model Employee <h2>Employee</h2> <p> <label asp-for="Name">Name</label> <input asp-for="Name" /> </p> <p> <label asp-for="SurName">Surname</label> <input asp-for="SurName" /> </p> <p> <label asp-for="Age">Age</label> <input asp-for="Age" /> </p>
Görüldüğü üzere tag helperlar üretecekleri html elemanları kullanıldığı sayfanın modeline uygun bir şekilde bind etmekte ve hatta eşleştirilen propertynin tipine göre oluşturulacak inputun değeri otomatik belirlenmektedir.(string ise text, int ise number vs.)
Hatta tag helperlar yazım esnasında sayfa modelinin memberlarını IntelliSense aracılığıyla karşımıza getirmektedir.
İşte bu özellik harika 🙂
Ayrıca klasik Asp.NET MVC’de ki Action ya da ActionLink helper metotlarının yerine aşağıdaki gibi “asp-action” ve “asp-controller” tag helperları gelmiştir.
@* Aynı Controller'da ise; /Home/Page*@ <a asp-action="Page">Page1</a> @*/Home/Page*@ <a asp-action="Page" asp-controller="Home">Page2</a> @* /Home/Page/5?name=gencay *@ <a asp-action="Page" asp-controller="Home" asp-route-id="5" asp-route-name="gencay">Page3</a> @* /Home/Page/5?name=gencay *@ <a asp-action="Page" asp-controller="Home" asp-all-route-data='new Dictionary<string, string> { { "name","gencay"}, { "id","5"} }'>Page4</a>
Form Yapılanması
Form yapıları artık html olarak aşağıdaki gibi tasarlanmaktadır.
@model Employee <form method="post" asp-action="Save" asp-controller="Employee"> <p> <label asp-for="Name">Name</label> <input asp-for="Name" /> </p> <p> <label asp-for="SurName">Surname</label> <input asp-for="SurName" /> </p> <p> <label asp-for="Age">Age</label> <input asp-for="Age" /> </p> <p> <button type="submit">Save</button> </p> </form>
Form Validations
public class Employee { public int Id { get; set; } [Required(ErrorMessage = "Enter the name field")] public string Name { get; set; } [Required(ErrorMessage = "Enter the surname field")] public string SurName { get; set; } public int Age { get; set; } }
public class EmployeeController : Controller { public IActionResult Save() => View(); [HttpPost] public IActionResult Save(Employee employee) { if (ModelState.IsValid) Content("Kayıt gerçekleştirildi."); return View(employee); } }
@model Employee <form method="post" asp-action="Save" asp-controller="Employee"> <p> <div asp-validation-summary="All"></div> </p> <p> <label asp-for="Name">Name</label> <input asp-for="Name" /> </p> <p> <label asp-for="SurName">Surname</label> <input asp-for="SurName" /> </p> <p> <label asp-for="Age">Age</label> <input asp-for="Age" /> </p> <p> <button type="submit">Save</button> </p> </form>
Yukarıda div elemanında gördüğünüz “asp-validation-summary” tag helperı ile validasyon mesajları hızlıca verilebilmektedir.
View Components
Asp.NET Core ile hayatımıza giriş yapmış olan yepyeni bir terimdir. Kullanım olarak Partial View yapılarına benzemektedirler lakin işleyiş olarak başlı başına bir cevherdirler.
Peki ne işe yaramaktadır View Componentler?
Olayı ilk olarak Partial View yapılarıyla ele alalım. MVC mimarisinde veri kümesi kullanan bir Partial View’i her tetiklediğimizde ilgili partial view controller ile bağlantısını kuracak ve kullanacağı modeli bu bağlantı üzerinden talep edecektir.
Örneğin;
@model IEnumerable<CoreExample.Web.Models.Employee> <ul> @foreach (var employee in Model) { <li> @employee.Name @employee.SurName - @employee.Age </li> } </ul>
@model Employee @Html.Partial("~/Views/Home/Partials/_EmployeeList.cshtml", ViewBag.Models as IEnumerable<Employee>)
Burada gördüğünüz üzere partial view’a modeli controllerdan ViewBag.Models değişkenine atayarak getirmekteyiz. İşte View Componentler, partial viewlerin bu controller’a olan bağımlılığını ortadan kaldırmakta ve talep geldiği zaman direkt olarak modele gidip gereken veritabanı işlemlerini hallettikten sonra view’e yansıtmaktadır. Dolayısıyla controller ile bir ilişiği olmayacağından dolayı daha hızlı ve performanslı çalışacaktır.
View Componentleri kullanabilmek için projenin ana dizininde “ViewComponents” isminde bir klasör eklenerek ardından içerisine yapılacak işlemi ifade eden bir isimde class oluşturulur. Örneğin; EmployeeViewComponent
İçerisinde gerekli işlemler yapılır;
public class EmployeeViewComponent : ViewComponent { public IViewComponentResult Invoke() { List<Employee> employeeList = new List<Employee> { new Employee{ Id = 1, Age = 26, Name = "Gençay", SurName = "Yıldız" }, new Employee{ Id = 2, Age = 34, Name = "Mehmet", SurName = "İlhan" } }; return View(employeeList); } }
Burada dikkat etmeniz gereken hususlardan biri ilgili sınıfın isminin sonuna “..ViewComponent” ekinin eklenmesidir. Bir diğeri ilgili sınıfı “ViewComponent” sınıfından türetilmesi gerekmektedir. Ve son dikkat edilmesi gereken husus ise bu View Componentin yapacağı işi geriye “IViewComponentResult” interface tipinde değer dönen “Invoke” isimli metot içerisinde yapılmasıdır.
Şimdi oluşturulan bu View Componenti kullanalım.
Asp.NET Core View Componentleri çalışma zamanında aşağıdaki yollarda aramaktadır;
- Views/<ControllerName>/Components/<ViewComponentName>/<ViewName>
- Views/Shared/Components/<ViewComponentName>/<ViewName>
Biz makalemizde ikinci yolu baz alacağız.
İlgili view componenti çağırırken aşağıdaki gibi Invoke edilmesi yeterlidir.
@model Employee @await Component.InvokeAsync("Employee")
NuGet – Harici Kütüphanelerin Yönetimi
Harici paketleri yönetebilmek için projeye sağ tıklayıp “Edit -ProjeAdi-.csproj” sekmesine tıklayınız.
Bu işlemden sonra açılan pencerede projede kullanılan tüm harici modülleri görebilirsiniz. “Dependencies” -> “NuGet” kombinasyonu altında birden fazla kütüphane olabilir lakin proje publish edildiğinde projeye ait edit dosyasında bulunan modüller haricindekiler silinecektir.
npm Configuration File İle Modül Yönetimi
Projeye “package.json” isminde bir “npm Configuration File” dosyası eklediğinizde bu dosya üzerinden tüm modül install ya da uninstall yönetimini sağlayabilirsiniz.
{ "version": "1.0.0", "name": "asp.net", "private": true, "devDependencies": { "bootstrap": "4.1.3", "jquery": "3.3.1" } }
Projeye entegre etmek istediğimiz tüm modülleri “devDependencies” alanına belirttikten sonra tek yapmamız gereken dosyayı kaydetmemiz. Gerisini Visual Studio bizim için halledecek ve modülleri projeye entegre edecektir. Entegre edilen harici modülleri “Dependencies” -> “npm” dizini altında görebilirsiniz.
Evet.. Bu içeriğimizde Asp.NET Core 2 MVC mimarisinde mühim olan ve ilgimi çeken yeniliklere ve farklılıklara özet mahiyetinde değinmiş bulunmaktayım. Elbetteki sonraki yazılarımda burada değindiğim ya da değinmediğim birçok konuyu hususi olarak değerlendirecek ve detaylı içerikler oluşturacağız.
İlgilenenlerin faydalanması dileğiyle…
Sonraki yazılarımda görüşmek üzere…
İyi çalışmalar…