Asp.net Mvc Bir Sayfada Partial View Render Etme

Merhabalar. Bu yazımda mvc projemizde herhangi bir cshtml view sayfamızdan partial view çağırmayı ve bu sayfada nasıl render edildiğini anlatacağım.

Görüntülemek istediğimiz bir view sayfasında partial viewlar kullanmak isteyebiliriz. Sayfada görüntülemek istediğimiz her şeyi tek bir controller actionda yüklemek yerine küçük partial sayfalara ayırmak işimizi daha kolaylaştırır ve de daha sadeleştirip, okunurluğu artırabiliriz. Bunun için bir PartialViewResult methodu oluşturalım.

public PartialViewResult Partial()
{
    return PartialView("Partial");
}

Daha sonra bu methodumuzun üzerine gelip sağ tıklayıp Add View ekranında viewa bir isim verdikten sonra View Options kısmında Create as a partial view seçip bir view ekleyelim. Eğer methodumuzun return olan PartialView() methodu içerisinde bir Partial view ismi yazıyorsa, o viewi yükler. Eğer return olan partialview() methodunun içerisi boş ise, yani hiç bir view sayfasını yüklemek istemiyorsak yukarıdaki oluşturduğumuz ve kendi belirlediğimiz isimdeki partial view’i yükler.

Şimdi ise sırada herhangi bir view sayfasının içerisinden yukarıda oluşturduğumuz Partial isimli methodu çağırma işlemi var. Bu methodu çağırdığımızda partial view render edilmiş olacak.

@Html.Action("Partial", "Home")

Böylece Html helper yardımı ile sayfamızda partial view render etmiş olduk.

Generic Repository ve Unit of Work Pattern, Entity Framework, Unit Testing, Autofac IoC Container ve ASP.NET MVC [Part 2]

Bir önceki makalemde model, servis ve repository katmanları oluşturdum. Bu makalemde ise oluşturduğum katmanlarla CRUD işlemlerini yapacağız ve Autofac IoC Container kuracağım.

Setup AutoFac:

Mvc projesi içinde Package Manager Console ekranındaki command satırına şu komutu yazın:

Install-Package Autofac.Mvc5

Ayrıca bu komut Autofac’ı da install edecektir.

Autofac kurulumu ile classlarımızı da register etmeye başlayabiliriz. Modules adında bir folder oluşturalım ve içine şu dosyaları alsın:

RepositoryModule.cs

public class RepositoryModule : Autofac.Module
   {
       protected override void Load(ContainerBuilder builder)
       {
           builder.RegisterAssemblyTypes(Assembly.Load("SampleArch.Repository"))
                  .Where(t => t.Name.EndsWith("Repository"))
                  .AsImplementedInterfaces()
                 .InstancePerLifetimeScope();
       }
   }

Bu işlem Autofac içindeki bütün classların sonuna “Repository” getirerek classları register edecektir.ServiceModule.cs

public class ServiceModule : Autofac.Module
  {
      protected override void Load(ContainerBuilder builder)
      {
          builder.RegisterAssemblyTypes(Assembly.Load("SampleArch.Service"))
                    .Where(t => t.Name.EndsWith("Service"))
                    .AsImplementedInterfaces()
                    .InstancePerLifetimeScope();
      }
  }

Bu işlem Autofac içindeki bütün classların sonuna “Service” getirerek classları register edecektir.

EFModule.cs

public class EFModule : Autofac.Module
    {
        protected override void Load(ContainerBuilder builder)
        {
            builder.RegisterModule(new RepositoryModule());
            builder.RegisterType(typeof(SampleArchContext)).As(typeof(DbContext)).InstancePerLifetimeScope();
            builder.RegisterType(typeof(UnitOfWork)).As(typeof(IUnitOfWork)).InstancePerRequest();        
        }
    }

Global.asax dosyası içindeki Application_Start methodu içerisine bazı satırlar ekleyelim:

//Autofac Configuration
          var builder = new Autofac.ContainerBuilder();
          builder.RegisterControllers(typeof(MvcApplication).Assembly).PropertiesAutowired();
          builder.RegisterModule(new RepositoryModule());
          builder.RegisterModule(new ServiceModule());
          builder.RegisterModule(new EFModule());
          var container = builder.Build();
          DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

Ayrıca şu namespaceleri de eklememiz gerekmektedir.

using Autofac.Integration.Mvc;
using Autofac;

Artık service objesini controller classları içerisine enjekte edebiliriz.

Country CRUD Implementasyonu:

Mvc projesinin içerisine Model ve Servis projelerinin referanslarını ekleyelim. Yeni bir controller ekleyip optionunu “MVC 5 Controller with Views using Entity Framework” seçelim. Name : CountryController,  Select Model : “Country“, DataContext:SampleArchContext, Set “Generate Views” true, Click Add deyip controller ekleme işini tamamlayalım. Böylece EF kullanarak action ve viewları implement etmiş olduk. Şimdi controllerımızı service katmanına göre modifiye edelim:

public class CountryController : Controller
   {
       //initialize service object
       ICountryService _CountryService;
       public CountryController(ICountryService CountryService)
       {
           _CountryService = CountryService;
       }
       //
       // GET: /Country/
       public ActionResult Index()
       {
           return View(_CountryService.GetAll());
       }      
       //
       // GET: /Country/Create
       public ActionResult Create()
       {
           return View();
       }
       //
       // POST: /Country/Create
       [HttpPost]
       [ValidateAntiForgeryToken]
       public ActionResult Create(Country country)
       {
           // TODO: Add insert logic here
           if (ModelState.IsValid)
           {
               _CountryService.Create(country);
               return RedirectToAction("Index");
           }
           return View(country);
       }
       //
       // GET: /Country/Edit/5
       public ActionResult Edit(int id)
       {           
           Country country = _CountryService.GetById(id);
           if (country == null)
           {
               return HttpNotFound();
           }
           return View(country);
       }
       //
       // POST: /Country/Edit
       [HttpPost]
       public ActionResult Edit(Country country)
       {
           if (ModelState.IsValid)
           {
               _CountryService.Update(country);
               return RedirectToAction("Index");
           }
           return View(country);
       }
       //
       // GET: /Country/Delete/5
       public ActionResult Delete(int id)
       {
           Country country = _CountryService.GetById(id);
           if (country == null)
           {
               return HttpNotFound();
           }
           return View(country);
       }
       //
       // POST: /Country/Delete/5
       [HttpPost, ActionName("Delete")]
       [ValidateAntiForgeryToken]
       public ActionResult Delete(int id, FormCollection data)
       {
           Country country = _CountryService.GetById(id);
           _CountryService.Delete(country);
           return RedirectToAction("Index");
       }
   }

Yukarıda gördüğünüz gibi Controller classımızın constructoruna servis katmanından gelen ICountryService objesini enjekte ettik. Constructor Dependency injection controller classımız teste uygun hale getirir.

Şimdi relationship içeren diğer CRUD işlemlerinin gözden geçirelim :

Person CRUD Implementasyonu :

CountryControllara benzer bir şekilde PersonController ekliyoruz. Aşağıda Entity Framework yapısı kullanarak Country dropdownList oluşturacağız. CountryController’da olduğu gibi servis katmanı ile PersonController classını da modifiye edelim.

public class PersonController : Controller
  {
      IPersonService _PersonService;
      ICountryService _CountryService;
      public PersonController(IPersonService PersonService, ICountryService CountryService)
      {
          _PersonService = PersonService;
          _CountryService = CountryService;
      }
      // GET: /Person/
      public ActionResult Index()
      {
          return View(_PersonService.GetAll());
      }
      // GET: /Person/Details/5
      public ActionResult Details(long? id)
      {
          if (id == null)
          {
              return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
          }
          Person person = _PersonService.GetById(id.Value);
          if (person == null)
          {
              return HttpNotFound();
          }
          return View(person);
      }
      // GET: /Person/Create
      public ActionResult Create()
      {
          ViewBag.CountryId = new SelectList(_CountryService.GetAll(), "Id", "Name");
          return View();
      }
      // POST: /Person/Create
      // To protect from overposting attacks, please enable the specific properties you want to bind to, for
      // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
      [HttpPost]
      [ValidateAntiForgeryToken]
      public ActionResult Create([Bind(Include = "Id,Name,Phone,Address,State,CountryId")] Person person)
      {
          if (ModelState.IsValid)
          {
              _PersonService.Create(person);
              return RedirectToAction("Index");
          }
          ViewBag.CountryId = new SelectList(_CountryService.GetAll(), "Id", "Name", person.CountryId);
          return View(person);
      }
      // GET: /Person/Edit/5
      public ActionResult Edit(long? id)
      {
          if (id == null)
          {
              return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
          }
          Person person = _PersonService.GetById(id.Value);
          if (person == null)
          {
              return HttpNotFound();
          }
          ViewBag.CountryId = new SelectList(_CountryService.GetAll(), "Id", "Name", person.CountryId);
          return View(person);
      }
      // POST: /Person/Edit/5
      // To protect from overposting attacks, please enable the specific properties you want to bind to, for
      // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
      [HttpPost]
      [ValidateAntiForgeryToken]
      public ActionResult Edit([Bind(Include = "Id,Name,Phone,Address,State,CountryId")] Person person)
      {
          if (ModelState.IsValid)
          {
              _PersonService.Update(person);
              return RedirectToAction("Index");
          }
          ViewBag.CountryId = new SelectList(_CountryService.GetAll(), "Id", "Name", person.CountryId);
          return View(person);
      }
      // GET: /Person/Delete/5
      public ActionResult Delete(long? id)
      {
          if (id == null)
          {
              return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
          }
          Person person = _PersonService.GetById(id.Value);
          if (person == null)
          {
              return HttpNotFound();
          }
          return View(person);
      }
      // POST: /Person/Delete/5
      [HttpPost, ActionName("Delete")]
      [ValidateAntiForgeryToken]
      public ActionResult DeleteConfirmed(long id)
      {
          Person person = _PersonService.GetById(id);
          _PersonService.Delete(person);
          return RedirectToAction("Index");
      }
  }

Yukarda da gördüğümüz bu controllerımızın constructoruna üzere hem CountryService , hem de PersonService nesnesini enjekte ettik. Çünkü controllerımızda her iki servisimize de erişmemiz gerekti. CountryService, ülkelerin dropdown seçimi için, PersonService ise CRUD işlemleri için gerekliydi.

Sonuç olarak view ekranımız şu şekilde olacaktır:

crud-autofac

ÖZET:

Bu makalemde Autofac kurulumunu ve Entity Framework ve Service Katmanları ile Generic Repository ve Unit of Work Pattern üzerinden base alarak CRUD işlemlerinin nasıl yapıldığını öğrendik. Diğer makalemde farklı katmanların Unit Test implementasyonunu anlatacağım.

İyi Çalışmalar.

Email ve Telefon Alanını Regular Expression ile Validate Etmek

Merhaba. Bu yazımda bir modelde telefon veya email alanına validate için attribute eklemeden regular expression ifadelerle bu alanları nasıl validate edebileceğimizi göreceğiz.

Öncelikle bir .js uzantılı bir dosya ekleyelim; adı validate.js olsun ve içine regular expression ifadelerini içeren scriptleri ve functionları ekleyelim.

function validateEmail(email) {
    var re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
    return re.test(email);
}
 
function validateTel(tel) {
    var re = /\(?([0-9]{3})\)?([ .-]?)([0-9]{3})\2([0-9]{4})/;
    return re.test(tel);
}

Daha sonra kullanacağımız view sayfasına oluşturduğumuz js dosyasını import edelim

<script src="~/Scripts/Validate.js"></script>

Bundan sonra ise yapmamız gereken view sayfamızda validate.js dosyasının içindeki fonksiyonları kullanmak. Bu fonksiyonlara email veya tel input id’sini göndermek, oradan boolean bir ifade elde etmek.

if (validateEmail($("#emailtext").val())) {
    // Email validate olduğunda yapıalacak olanlar..             
}
if (validateTel($("#teltext").val())) {
    // Tel numarasını validate olduğunda yapılacak olanlar..
}

View Tanımlama

Bu yazımda da View dosyaları nasıl tanımlanır ve nasıl kullanılır, bu konular üzerinde duracağım.

Yeni bir proje oluşturduğumuzda projenin dizininde Views klasörü vardır. Dizin yapısını incelersek her Controller sınıfı için Views klasörünün altında o Controller adında bir klasör daha vardır.

Ayrıca her Controller sınıfı için tanımlanan Views klasörünün altında ise, Controller sınıfı içerisindeki her metod için bir .cshtml veya .vbhtml uzantılı Razor sayfaları vardır. Bu razor sayfaları dinamik yapıdadır.

solution explorer

Controller classları ile view razor sayfaları ilişkilidir. Yeni bir proje oluşturulduğunda default olarak razorlar oluşturulmuş halde gelir. Ama yeni bir controller classı oluşturup, içinde herhangi bir method tanımladığımızda herhangi bir razor sayfası kendiliğinden oluşturulmaz. Bunun için sağ tıklayıp Add View deyip bir razor oluşturabiliriz.

AddView

 

Add View tıkladıktan sonra şöyle bir ekran karşımıza çıkacak.

AddViewOptionBu sayfa oluşturucağımız razorun optionlarının seçildiği sayfadır. View Engine olarak Razor veya Asp.net C# veya VB belirleyebiliriz. Ama MVC ile gelen Razor View Engine işlerimizi daha da basitleştirmektedir. Onun için genellikle Razor kullanılır. Hemen altında Create a strongly-typed view seçeneği vardır. Strongly-typed Views’a daha sonradan tekrar değineceğim. Onun altında da Create as partial view seçeneği vardır. Partial View’in Asp.net Web Forms’taki karşılığı User Controller’dir. Herhangi masterpage kullanmazlar. Bundan dolayı da sayfada css, js dosyaları sayfada tutulmaz. Ama Use a Layout or Masterpage seçeneğini tıklarsak herhangi bir Layout sayfası seçmemizi ister. Layout seçtikten sonra oluşan Razor sayfasının içeriği şu şekildedir

@{
ViewBag.Title = “Example”;
Layout = “~/Views/Shared/_LayoutDark.cshtml”;
}

<h2>Example</h2>

Böylece yeni bir View sayfası oluşturma işlemini tamamlamış olduk.

 

Views

View, geliştirilen projenin kullanıcıya gösterilen  arayüzü ve aynı zamanda Html,Css,JavaScript dökümanlarının tutulduğu yapıdır. Kullanıcının gördüğü ve arayüze dair şeyler buradadır.  View bölümünde iş akışına ait bir şeyler bulunmaz. Ayrıca View bölümü sayesinde uygulamanın arayüzü uygulamanın çekirdek kısmından ayrı tutulduğundan tasarımı ve tasarımın değiştirilmesi açısından bize avantaj sağlar.

Herhangi bir controller oluşturduğumuzda, controller sınıfına ait bir view sayfası oluşturabiliriz ve viewa gönderilecek olan nesneyi ViewBag, ViewData veya TempData ile gönderebiliriz.

public class HomeController : Controller {
public ActionResult Sample() {
ViewBag.Message = “Welcome to ASP.NET MVC!”;
return View(“Sample”);
}
}

Yukarıdaki HomeController içindeki Sample metodunun içinde ViewBag.Message içine istediğimiz bir değer atayabiliriz. Çünkü ViewBag object bir nesnedir. Viewbag nesnesi istenilen türden değer alır. Oluşturulan view sayfası örneği ise şu şekildedir :

Sample.cshtml

@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head><title>Sample View</title></head>
<body>
<h1>@ViewBag.Message</h1>
<p>
This is a sample view. It’s not much to look at,
but it gets the job done.
</p>
</body>
</html>

ViewBag kavramını daha sonraki konularda göreceğiz. Şimdilik sadece Controller sınıfında tanımlandığında View sayfasında kullanabileceğimiz “dinamic” bir değişken olarak bilmemiz yeterlidir.

ASP.net MVC NEDİR?

“ASP.NET HTML, CSS, JavaScript ve sunucu taraflı programlama ile web sayfaları ve web siteleri yapmaya yarayan bir geliştirme yapısıdır.
ASP.NET 3 farklı geliştirme modeli sunar: Web pages, MVC (Model View Controller) ve Web Forms.”

“w3school”


MVC, uygulamanın kullanıcı arayüzünü 3 temel yapıya ayırır:

Model: Verinin nasıl değişeceğini ve nasıl yönetileceğini belirleyen iş kurallarını (Business Rules) içeren sınıfların tamamının bulunduğu katmandır. Genelde bunlar veritabanını temsil eden sınıflarlar veya domaini temsil eden nesnelerdir. EntityFramework, NHibernate gibi, entity-data-model ler de, model katmanında yer alabilir. Yani uygulamamızda kullanacağımız nesneler bu katmandadır.

View: Kullanıcı arabiriminin (User Interface – UI) gösterileceği katman. Dinamik olarak üretilen HTML şablonu bu katmandadır. Kısaca veri gösterim katmanı diyebiliriz.

Controller: Tüm sistem akışının, kullanıcı ile olan etkileşimi kontrol eden ve olayları yöneten sınıfların tamamı. View ve Model katmanları arasındaki ilişkiyi yönetir. Kullanıcıdan girdi alır, modelle iletişime geçer ve ne gösterileceğine karar verir.

ASP.NET MVC 1

13 MART 2009 da resmi olarak kodlar ve birim testlerle MVC mimarisi yayınlanmıştır. MVC mimarisinin bugün kullanılan bir çok özelliği aslında MVC 2 de gelecektir.

ASP.NET MVC 2

MVC 2 ilkinden 1 yıl sonra yayınlanmıştır (MART 2010). MVC 2 de olan bazı ana özellikler şunlardır:

  • Otomatik olarak oluşturulan kullanıcı arabirimi yardımcıları (UI Helpers) ve özelleştirilebilir şablonlar.
  • Hem server, hem de istemci taraflı, nitelik tabanlı (attribute-based) bir model doğrulama (model-validation) yapısı.
  • Strongly typed HTML Helpers
  • Geliştirilen Visual Studio araçları.


ASP.NET MVC 3

MVC 3, MVC 2 den 10 ay sonra yayınlanmıştır. Eklenen ana başlıklar:

  • Razor görüntüleme motoru (Razor View Engine).
  • .NET 4 dataannotation desteği.
  • Gelişmiş model doğrulama (model validation).
  • Unobtrusive JavaScript, jQuery Validation, ve JSON için daha iyi bir JavaScript desteği.
  • Yazılım ve platforma bağlı güncellemeler ve yönetim için NuGet kullanımı.

Razor View Engine

MVC 1 den itibaren bugüne kadar yapılan en büyük HTML görüntüleme güncellemesi Razor olmuştur. MVC 1 ve MVC 2 de genel olarak kullanılan görüntüleme motoru Web Forms görüntüleme motoru ile aynı sözdizimini ve dosya uzantısındadır. (ASPX/ASCX/MASTER)

Örnek Web Forms sözdizimi:

 
<%@ Page Language="C#" MasterPageFile="</Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<MvcMusicStore.ViewModels.StoreBrowseViewModel>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
    Browse Albums
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
    <div class="genre">
        <h3><em><%: Model.Genre.Name %></em> Albums</h3>
        <ul id="album-list">
            <% foreach (var album in Model.Albums) { %>
                <li>
                    <a href="<%: Url.Action("Details", new { id = album.AlbumId }) %>">
                    <img alt="<%: album.Title %>" src="<%: album.AlbumArtUrl %>" />
                    <span><%: album.Title %></span>
                    </a>
                </li>
            <% } %>
        </ul>
    </div>
</asp:Content>

Razorun söz dizimi tamamen kod odaklı bir şablonu vardır. İlk bakıldığı anda HTML ve .Net kodları hemen anlaşılır, okunması ve anlaşılması çok kolaydır. Yukarıdaki kodun Razor ile yazılmış hali aşağıdaki gibidir:

@model MvcMusicStore.Models.Genre
@{ ViewBag.Title = "Browse Albums"; }
<div class="genre">
    <h3><em>@Model.Name</em> Albums</h3>
    <ul id="album-list">
        @foreach (var album in Model.Albums)
        {
            <li>
                <a href="@Url.Action("Details", new { id = album.AlbumId })">
                    <img alt="@album.Title" src="@album.AlbumArtUrl" />
                    <span>@album.Title</span>
                </a>
            </li>
        }
    </ul>
</div>