Derinlemesine yazılım eğitimleri için kanalımı takip edebilirsiniz...

Asp.NET Core 2 MVC’de View Component Yapısı

Merhaba,

Klasik Asp.NET MVC mimarisinde kullandığımız partial view yapılarına alternatif olarak Asp.NET Core 2 MVC mimarisinde View Component yapıları geliştirilmiştir. Alternatif olarak nitelendiriyoruz çünkü partial view yapıları halen Asp.NET Core MVC mimarisinde de işlevsel olarak mevcudiyetini korumaktadır. Dolayısıyla bu içeriğimizde View Component yapılarını inceleyecek ve partial view yapılarının işlevsel açıdan hangi durumlarının, View Component yapılarının geliştirilmesine neden olduğunu açığa çıkarmaya çalışacağız.

İlk olarak partial view yapısını ne amaçla, nasıl kullanıyorduk bunun üzerine duralım. Web sitemiz üzerinde hemen hemen her modülde yahut sayfada birebir benzer işlemleri gerçekleştireceksek yahut aynı kodları çalıştırmamız gerekecekse bunun için her sayfa üzerinde hususi çalışmak yerine, bu ihtiyacı partial view yapısı ile global hale getirip lazım olan her noktada ilgili partial view’i çağırarak ihtiyacımıza dönük genelleştirilmiş bir çözüm sağlayabiliyorduk.

Yapısı itibariyle partial view, ihtiyacımızı büyük ölçüde gideren bir özellik olmasına rağmen server işlemlerine ihtiyaç duyulduğu noktada MVC paternine fazladan yük bindirmekte ve lüzumsuz bir maliyet israfına sebebiyet verebilmektedir. Bu maliyet, her server işleminde Controller katmanıyla iletişim kurmak zorunda kalmasından dolayı arz etmektedir. Aşağıdaki görseli incelerseniz eğer en basitinden bir veritabanı işlemi yapmak için bile Controller katmanına erişilmesi gerekilmekte ve o katman üzerinden gerekli birimlere talepte bulunulmak mecburiyetindedir.

Asp.NET Core 2 MVC'de View Component Yapısı

İşte bu duruma istinaden .NET geliştiricileri Asp.NET Core 2 MVC’de partial view’in bu yükünü ortadan kaldırabilmek için View Component yapılarını geliştirmişlerdir. View component yapıları aşağıdaki görselde olduğu gibi bir işlevselliğe sahiptirler;
Asp.NET Core 2 MVC'de View Component Yapısı
Yani herhangi bir server tabanlı işlemde ya da görselde olduğu gibi ufak bir veritabanı işleminde Controller’a bağlanma gereği duymaksızın direkt olarak ilgili katmana erişim sağlayarak işlemini icra edebilmekte ve gereken sonuçları elde edebilmektedir.

View Component Oluşturma

View Component yapılarını projemizde “ViewComponents” ya da “Components” vs. gibi anlamlı isimde bir klasör altında toplayarak aşağıdaki kurallar çerçevesinde inşa edebiliriz.

  • Oluşturulacak view component sınıfları aşağıdaki gibi üç farklı varyasyonda tanımlanabilir.

    1.     public class ExampleViewComponent
          {
              ...
          }
      
    2.     public class Example : ViewComponent
          {
              ...
          }
      
    3.     [ViewComponent]
          public class Example
          {
              ...
          }
      
  • Bizler 2. varyasyonu baz alarak konumuza devam edelim. View component sınıfı içerisine “IViewComponentResult” tipinden değer dönen “Invoke” isimli metodu ekliyoruz.

        public class EmployeeViewComponent : ViewComponent
        {
            DatabaseContext _dbContext;
            public EmployeeViewComponent(DatabaseContext dbContext)
            {
                _dbContext = dbContext;
            }
    
            public IViewComponentResult Invoke()
            {
                IEnumerable<Employee> employeeList = _dbContext.Employees;
                return View(employeeList);
            }
        }
    

    Burada gördüğünüz gibi örnek view componentimizin “Invoke” metodunda veritabanı işlemleri gerçekleştirilmekte ve bu işlemi Controller ile ilişkiye girmeksizin sağlamaktayız.

  • Programatik olarak oluşturulan view componentin görüntüsünü, “Views” -> “Shared” dizininde “Components” isminde oluşturulan klasör içerisine, view component adıyla birebir aynı olacak şekilde bir klasör içerisine aşağıdaki gibi oluşturuyoruz.
    Asp.NET Core 2 MVC'de View Component Yapısı
    Ya da
    oluşturulan view component herhangi bir controller’a özel oluşturulmuş olabilir. Bu durumda ilgili controller dizinininde, “Components” isimli klasör içerisinde yine view component adıyla birebir aynı olacak şekilde klasör tanımlayarak aşağıdaki gibi oluşturabilirsiniz.
    Asp.NET Core 2 MVC'de View Component Yapısı

    Burada compiler çağrılan view componenti her iki dizinde de arayacak ve bulduğunu render edecektir. Ayriyetten dikkat etmeniz gereken nokta şu ki, view component isminde belirtilen “[…ViewComponent]” eklerini bu noktalarda belirtmeden sadece ismini belirtiyoruz.

    View componentler birazdan göreceğimiz üzere çağırım esnasında aksisini belirtmediğimiz sürece varsayılan olarak “Default.cshtml” dosyasını işleyecektirler. Bizler yazımızın devamında farklı isimde “.cshtml” dosyaları üzerinden de örneklendirmede bulunacağız.

    Şimdi “Default.cshtml” dosyasının içerisinde aşağıdaki gibi bir tasarım olduğunu varsayalım ve anlatımımıza devam edelim.

    @model IEnumerable<Employee>
    
    <ul>
        @foreach (var employee in Model)
        {
            <li>@employee.Name @employee.SurName</li>
        }
    </ul>
    
  • Programatik ve görsel olarak tasarladığımız view componenti kullanabilmek için tek yapılması gereken ilgili noktada aşağıdaki şekilde çağırmaktır.

    @await Component.InvokeAsync("Employee")
    

    Dikkat ederseniz burada da “[…ViewComponent]” ekini kullanmaksızın çağırım gerçekleştirilmektedir.

    Bu şekilde kullanıldığı takdirde netice olarak view component çalışacak ve beklenen sonucu ekrana yansıtacaktır.

  • Peki farklı bir ‘.cshtml’ dosyasında çalışırsak eğer durumuna karşılık aşağıdaki örnek kodu baz alırsak;

    .
    .
    .
            public IViewComponentResult Invoke()
            {
                return View();
            }
    .
    .
    .
    

    View componentimizin “Invoke” metodu içerisinde “View()” metodunu direkt olarak yukarıdaki gibi çağırırsak eğer varsayılan olarak “Default.cshtml” dosyası render edilecektir. Yok eğer;

    .
    .
    .
            public IViewComponentResult Invoke()
            {
                return View("example");
            }
    .
    .
    .
    

    şeklinde çağırırsak “example.cshtml” dosyasını arayacak ve render edecektir.

  • Invoke metoduna nasıl parametre gönderebilirim? sorusuna istinaden ise;

    .
    .
    .
            public IViewComponentResult Invoke(int id)
            {
                return View();
            }
    .
    .
    .
    
    @await Component.InvokeAsync("Employee", new { id = 5 })
    

    şeklinde bir çalışma sergileyebiliriz.

Evet, gördüğünüz gibi Asp.NET Core view component yapıları ile partial view yapısındaki controller bağımlılığını ortadan kaldırmakta ve sistem üzerindeki lüzumsuz iş ve yersiz maliyeti minimize ederek bizlere sunmaktadır.

İlgilenenlerin faydalanması dileğiyle…

Sonraki yazılarımda görüşmek üzere…

İyi çalışmalar dilerim…

Bunlar da hoşunuza gidebilir...

22 Cevaplar

  1. Yunus dedi ki:

    Merhaba . Bu işlemi Asp.Net Mvc de yapabiliyor muyuz ?

  2. Mehmet dedi ki:

    Hocam merhabalar;
    MVC5’de kullandığımız Editor/View Template araçlarımız vardı. Bu ViewCompenentler ile bir Editor Template mantığında çalıştırabiliyormuyuz?

  3. turgay dedi ki:

    güzel paylaşım. teşekkürler. bu viewcomponent’i nasıl yenileriz? sayfa ilk yüklendiğinde gelen listeyi sağdaki seçilen kategoriye göre mesela?

  4. furkan yüksel dedi ki:

    hocam selam ya bu Mvcde olan Html.Action(Action,Controller) gibi çekemiyormuyuz html.actionu kaldırmışlar
    alt tarafı parçalı view yapacağım

  5. Ridvan dedi ki:

    Gencay bey,

    Entity classlari ile calismak mi daha mantikli yoksa Modeller ile mi calismak daha mantikli?

  6. Ramazan Kızılkaya dedi ki:

    Merhaba hocam, şuan çalıştığım e-ticaret projemde hemen hemen tüm entitiy’lerime(ürünler,kategoriler,firmalar,müşteriler vs…) ihtiyaç duyduğum side bar’ı component yaptım. Bu side bar, sitenin ürün arama ekranında bulunuyor ve ziyaretçi ürün ararken sayfa her refresh ettiğinde tekrar render ediliyor. Merak ettiğim konu şu; sayfa her refresh ettiğinde componentim sunucuya yeni istek mi gönderiyor? Bu durum sunucuya gereksiz yük bindirip sayfanın dolma süresini uzatmaz mı? Çünkü benim componentte sunucudan çektiğim veriler hep aynı. Dinamik değişen bir veri yok. Bunun yerine alternatif bir yaklaşım nasıl olabilir? Teşekkür ederim.

    • Gençay dedi ki:

      Merhaba,
      View Component’i aşağıdaki gibi cache etiketi içerisine alarak önbelleğe alabilir ve her istek neticesinde tekrar tekrar tetiklemek zorunda kalmadan kullanabilirsiniz.

      <cache expires-after="@TimeSpan.FromMinutes(5)">
          @await Component.InvokeAsync("Employee")
      </cache>
      

      Kolay gelsin.

  7. ramazan dedi ki:

    Hocam çok teşekkür ederim.

  8. efe dedi ki:

    Hocam Merhaba, Diyelim ki bir sitede 10 tane view component kullanıyoruz, Bu bizim sitemizin performansını olumsuz yönde etkiler mi?

    • Gençay dedi ki:

      Merhaba,

      Tabi ki de yapılan her türlü iş mantığı maliyeti arttıracağından dolayı dolaylı yoldan site performansını olumsuz yönde etkileyecektir. Lakin siz gerekli cacheleme işlemlerini gerçekleştirirseniz ve yazdığınız kodu ve operasyonu optimize bir şekilde inşaa ederseniz olabilecek en az maliyette en yüksek performansı elde etmiş olacaksınız.

      Nasıl ki gerektiği taktirde harcamak değilde fazladan ve lüzumsuz para harcamak israf oluyorsa, burada da gerektiği taktirde view component kullanmak doğru bir seçim lakin gerekmediği taktirde yersiz bir maliyet söz konusu olacaktır.

      Sevgiler.

  9. Güven dedi ki:

    Hocam Merhaba,
    Youtube da anlattığınız ASP.NET CORE 5.0 ViewComponent videosundan geliyorum. Söyledikleriniz aynen yaptım.
    ViewComponent sayfasında bir dropdownList kontrolüm var

                @Html.DropDownListFor(m => m.insaat_Demiri.BolgeId,
               new SelectList(Model.Bolgeler, "id", "Ad"), new
                    {
                        @class = "form-control",
                @onchange = "SelectedIndexChanged()"
                    })
    

    ViewComponent’te Model üzerinde insaat_Demiri nesnesindeki her şey gelmesine karşın, Bolgeler nesnesine ait bilgileri gelmiyor.

    Debug modunda Invoke() metodunda model tam olarak gelmesine rağmen sayfayı çağırdığımda
    DropDownListFor daki new SelectList(Model.Bolgeler, “id”, “Ad”) kısmında “Object reference not set to an instance of an object” hatası veriyor. Bu hatayı neden alıyor olabilirim? Teşekkürler.

  10. Güven dedi ki:

    Hocam yeniden merhaba biraz önceki sorumun çözümünü buldum. SelectList(Model.Bolgeler, “id”, “Ad”) kısmında “id” yerine “ID” koymam gerekiyormuş. EF migrate ederken nedense veritabanı tablolarındaki küçük harfleri büyük harflerle değiştirmiş. İsterseniz sorumu silebilirsiniz..

    • Gençay dedi ki:

      Soruları bu şekilde blog yahut youtube’dan almamın sebebi benzer problemleri yaşayanlara peşin kaynak olmasıdır. Dolayısıyla bu tarz değerli yorumları silersek bloğun vizyonu doğrultusunda anlamlı bir yanı kalmayacaktır.

      Sorunuz ve özellikle bulduğunuz çözümü paylaştığınız için teşekkür ederim.

  11. Batuhan dedi ki:

    Merhaba. Biz components klasörü altında birden fazla componentsleri bir arada tutuyoruz. peki bunları gruplayamaz mıyız? mesela anasayfanın componentlerini tutacak ayrı bir klasör olacak. ürünler sayfasının ayrı. onlarca componentim var ve klasör çok şişti. alakalı alakasız componentler tek klasör altında toplandı. anasayfa, ürünler, hakkımızda vb. gibi componentleri sayfalarına göre klasörlemem lazım. lütfen yardım edin.

  12. Bilal dedi ki:

    Teşekkürler çok yararlı bir anlatım olmuş.

  13. recep dedi ki:

    gencay bey mesela bunu sadece layout da göstermek istersek ve product login gibi sayfalarda göstermek istemesek bir yolu varmıdır.

  14. emre dedi ki:

    değerli hocam merhaba. bir Index sayfam var bu sayfa içinde örneğin “Personel” listemi gösteriyorum. Aynı Index sayfası içinde View Component kullanarak örneğin “Ürün” ile ilgili bilgileri post etmek istiyorum. @model List ile @model Urun yaptığımdan dolayı hata alıyorum.İki işlemde listeleme veya post olursa sıkıntı olmuyor.Partial View yapısında; başka model gönderebiliyorduk. View Component de @await Component.InvokeAsync(“PersonelViewModel”) yapıyorum.View Component de nasıl ekstra model gönderebilirim. çok teşekkür eder saygılar sunarım..

Güven için bir yanıt yazın Yanıtı iptal et

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir