ASP.Net MVC KİTABI BÖLÜM 6

Makale Modulü

Bundan önceki bölümde microsoft'un bize sağlamış olduğu hazır modulü kullanarak üyelik sistemi nasıl yapılır onu öğrendik. Bu üyelik sistemini oluştururken kendimiz herhangi bir veri tabanında tablo oluşturmamıştık. Microsoft üyelik için gerekli olan tabloları bizim yerimize oluşturmuştu. Şimdi ise projemize makale modulü ekleyeceğiz ve ve bu makale modulünü oluştururken herhangi bir hazır modul kullanmadan veri tabanında gerekli olan tabloların hepsini kendimiz oluşturacağız. Özet olarak makale modulunun yapımında baştan sona biz sorumlu olacağız.

Her bölümde olduğu gibi bu bölümde de 3 kısma ayrılmaktadır.
1 - istekler
2- analiz
3- uygulama

İstekler

Makale modulünün hazırlanması için öncelikle isteklerin belirlenmesi gerekmektedir. Makale modulünü ilk defa kendimiz oluşturacağımızdan altıncı bölüm çok önemlidir. Çünkü projemize diğer modulerin(Anket,Haber..) eklenmesi makale modulünün yapım aşamalarının bir benzeridir.

Aşağıda istekler kısmı sıralanmıştır.

  1. Editör, user gibi özel kullanıcılar için tasarlanmış ve html veya başka bir yazılım dili bilmesine gerek kalmadan makale ekleyebilecekleri silebilecekler, güncelleyebilecekleri bir arayüz oluşturmak.
  2. Diğer web sitelerin kullanıcıları bizim sitemizde veri kopyalanmasına izin verilmeli Çünkü diğer site kullanıcıları kopyaladıkları yazıyı sitelerinde koyduklarında yazının altında alıntı yaptığı siteye link vereceğinden bizim sitemizin trafiği artar.
  3. Yayınlayacağımız makalenin url'i konuyla ilgili olmalıdır.
  4. Yapılcacak olan makale yönetiminde, farklı yetkilere sahip olan kullanıcılar makale ekleyebilmelidir.

Analiz

Analiz aşamasında uygulama kısmı için tasarım oluşturacağız. Açıklayacak olursak sitemizin içeriği paylaşılaşılabilir ve düzeltilebilir bir online arayüz tasarlayacağız. Aşağıdaki maddeler analiz kısmının aşamalarını oluşturmaktadır.

  1. Öncelikle yapacağımız olan makale modulünün özellikleri tutan bir liste hazırlanmalı
  2. Bu makale modulünün veri tabanı hazırlanmalı
  3. Veri ve iş katmanlarının model nesnelerini oluşturulmalı
  4. İçerik yönetimi için kullanıcı arayüzü tasarlanmalı
  5. Kısıtlı olan sayfalar belirlenmeli ve bu sayfalara ulaşım güvence altına alınmalıdır. Bu sayfaların güvenliğinin nasıl sağlanacağı açıklanmalıdır.

Uygulamanın Özellikleri

Aşağıdaki listede uygulamanın özellikleri sıralanmıştır.

Herhangi bir zamanda veri tabanında makale ekleyebilmeliyiz. Ayrıca ekleyeceğimiz makalenin yayınlanma tarihini ve yayından kaldırılış tarihini de biz vermeliyiz. Eğer yayınlanma tarihini boş bırakırsak makalemiz hemen yayınlanmalı ya da yayından kaldırılış tarihini boş bırakırsak biz herhangi bir değilşiklik yapana kadar yayında kalmalıdır. Haber veya makaleye kimin gönderdiği ve kimin altına yorum yazdığı belli olmalıdır. belli olmalıdır. Bu çok önemlidir çünkü konuyla ilgili yazı yazan kişi bundan sorumludur. Eğer makaleyi paylaşan veya makalenin altına yorum kişi yanlış bir içerik paylaştıysa hemen uyarılmalılar ve yazdıkları da silinmelidir.

  1. Yayınlanan makale bütün okuyucular için mi yoksa sitede kayıtlı olan kullanıcılar içi olduğuna karar verilmelidir.
  2. Makalenin tartışılabilmesi için sitede alanlar oluşturulmalıdır.
  3. Bu makaleyi ne kadar zaman içinde kaç kişi okumuş olduğunun öğrenilebilmesi

Veritabanı Tablosu Tasarlamak

Projemizde kullanılacak bütün tablolar için bir veritabanı oluşturmalıyız. Tablolarımız aynı veritabanında bulunacağından aynı isimde olmamasında dikkat ediilmelidir. Bizim makale modulü için üç adet tabloya ihtiyacımız vardır. Bunlardan birincisinin ismi Kategori tablosu ikincisinin ismi Makale tablosu son olarakta üçünsünün ismi Yorum tablosudur.

Bizim oluşturacağımız makale modulünün veritabaı şeması aşağıdaki gibidir.

Şekil –1


MakaleGrup(Kategori) Tablosu

Alan Adı Tipi

Uzunluk

Allow Null Açıklama
MakaleGrupID Int-PK 4 No Kategori için Id Numarası
EklemeTarihi dateTime 8 No Kategori Oluşturulma Tarihi
Ekleyen nvarchar 256 No Kategoriyi Oluşturan'ın İsmi
Baslik nvarchar 256 No Kategori Başlığı
Yolu nvarchar 256 No Url için Yol Başlıkla Aını olmalı
Onemi Int 4 No Listedeki yerini, belirlemek için
Tanimi nvarchar 256 Yes Kategorinin Tanımı
ResimYolu nvarchar 256 Yes Kategori Resiminin Url'i

Bizim yapacağımız proje sadece bir tane kategoriye sahiptir alt kategorisi yoktur. Bu çok fazla değildir. Çünkü küçük ve orta ölçekli projelerde bir tane kategori yeterli olmaktadır. Ancak sitenizi daha kapsamlı bir proje olmasını istiyorsanız Kategori tablosuna bir tane KategoriParentId eklemesiniz.

Önemli

Sitemizi oluşturduğumuzda url yolu Basliktan oluşmalıdır. Hatta aynı uzunluk ve tipte olmalıdır. Ayrıca adres çubuğunda bulunan bu yol veritabanına depolanmalıdır. Çünkü bu arama motoru oprimizasyonu açısında iyidir.

Şöyleki;

Web sitenizdeki dokümanlar için açıklayıcı kategoriler ve dosya adları vermeniz, hem sitenizin daha düzenli hale getirilmesine hem de dokümanlarınızın arama motorları tarafından daha iyi taranmasına yardımcı olur. Bu içerik dosyalarınıza bağlantı eklemek isteyenlere de kolaylık sağlar. Ziyaretçiler, çok uzun ve şifreli gibi görünen, içinde sadece birkaç anlaşılabilir kelime geçen URL'lerden rahatsız olabilirler.

Kullanıcılar URL'leri akılda tutma veya ona bağlantı oluşturmada zorlanabilirler. Ayrıca, özellikle URL'de çok fazla anlamsız parametre bulunuyorsa kullanıcılar URL'nin bir bölümünün gereksiz olduğunu düşünebilirler. URL'nin bir bölümünü silerek bağlantıyı kırabilirler.

Bazı kullanıcılar sayfanıza, sayfanın URL'sini kullanarak bağlantı verebilirler. Eğer URL'niz ilgili kelimelerden oluşursa, kullanıcılara ve arama motorlarına sayfanız hakkında bir oturum kimliği değerinden veya anlamsız parametrelerden daha fazla bilgi sağlar. (Şekil-2)

Şekil –2


Makale Tablosu

Makale tablosunda MakaleGrup tablosundaki bütün makalelerin içeriği bulunur. Makale Tablosunun içeriği aşağıdaki gibidir.

Alan Adı Tipi

Uzunluk

Allow Null Açıklama
MakaleID Int-PK 4 No Makale için Id Numarası
EklemeTarihi dateTime 8 No Makale Oluşturulma Tarihi
Ekleyen nvarchar 256 No Makaleyi Oluşturan'ın İsmi
MakaleGrupId İnt-FK 8 No Makalenin hangi kategoride olduğunu gösterir.
Baslik nvarchar 256 No Makale Başlığı
Yolu nvarchar 256 No Url için Yol Başlıkla Aynı olmalı
Ozet nvarchar 4000 Yes Makale Hakkında kısa bilgi
İçerik ntext No Makalenin içeriği
Ülke nvarchar 256 Yes Makalenin yayınlandığı ülke
İlçe nvarchar 256 Yes Makalenin yayınlandığı ilçe
İl nvarchar 256 Yes Makalenin yayınlandığı İl
Yayin Tarihi dateTime 8 No Makalenin yayınlanma tarihi
Yayin Sonu dateTime 8 No Makalenin yayından kaldırılma tarihi
Onay bit 1 No Makalenin durumunu onaylar
ListeOnay bit 1 No Makalenin listede gösterilmesini sağlar
YorumAcik bit 1 No Makalenin altına yorum yapabilmeyi sağlar
YalnizcaUyeler bit 1 No Makalenin sadece üyelere gösterilmesini sağlar
OkumaSayisi İnt 4 No Makaleyi okuma sayısı
Oy İnt 4 No Makaleye atılan oy sayısı
ToplamOran İnt 4 No Makaleye atilan oy sayısı/Makaleyi okuyan saysısı

Yayın tarihi ve yayından kaldırılış tarihi bizim için oldukça önemlidir.Bu sistem bir site için oldukça faydalıdır siteyi güncel tutma adına bizlere oldukça kolaylık sağlar. Örneğin tatile çıkacaksınız ve bu tatil süresince siteye hiç makale giremeyecek ve sitede tatil süresince güncel olmayacak ve dolayısıyla site ziyaretçi sayısı azalacak ancak yayınlanma tarihi sayesinde sitemizi kolaylıkla güncelleyebiliyoruz. Tatile çıkmadan önce yayınlayacağımız makaleleri hazırlarız ve yayın tarihini tatil'e göre ayarlarsak sitemiz güncel kalır.

Liste onay sutunuda olukça önemlidir. Çünkü eklediğimiz makaleyi makalelerin listelendiği sayfada görünür kılar. Eğr er makalenin listelenebilir özelliğine tik koymassak makalemiz listede gözükmez.

Tabloya Oylar ve ToplamOran sütunlarını neden koyduğumuza gelirsek Oluşturduğumuz makalenin beğenilme oranını hesaplaya bilmek içi koymuş bulunmaktayız. Bunun nasıl hesaplanacağına gelince yukarıdaki makale tablosunda bulunan OkumaSayisi ve

Oy sütunlarını kullanarak hesaplayacağız. Örneğin sitede bir makaleyi birkaç kişi okumuş olsun ve bunların hepsi makale beğenme durumlarına göre farklı oylar atsın atılan bu oylar OySayisi alanında toplanır ve makale her okunduğunda OkumaSayisi sutunu içinde değer bir artar. Daha sonra Oy sutunu içindeki değer OkumaSayiyina bölünür ve oluşan değer ToplamOran alanının içine yazılır böylelikle makalenin beğenilme oranını bulmuş oluruz. Anacak buişlemleri yaparken Bşr kullanıcının aynı makaleye birden fazla oy atmamaması için kullanıcının Ip adresini tablomuzda tutmak zorundayız.

Makale Yorumları Tablosu

Makale yorumları tablosu yayınladığımız makale ile ilgili okyuculardan geri dönüşüm almamızı sağlar. Makale Yorum Tablosu aşağıdaki gibidir.

Alan Adı Tipi

Uzunluk

Allow Null Açıklama
MakaleYorumID Int-PK 4 No Yorum için Id Numarası
EklemeTarihi dateTime 8 No Yorum Oluşturulma Tarihi
Ekleyen nvarcharf 256 No Yorum Oluşturan'ın İsmi
EkleyenEmail nvarchar 256 No Kategori Başlığı
EkleyenIP nvarchar 256 No Url için Yol Başlıkla Aını olmalı
RefMakaleID Int 4 No Listedeki yerini, belirlemek için
İcerik nvarchar 256 Yes Kategorinin Tanımı

Kullanıcının yorum yapabilmesi için öncelikle bir email adresleri olmak zorundadır. Sisteme kayıt olan kullanıcıların zaten minumum bir tane E-posta adresi vardır bu yüzden siteme kayıtlı olan kullanıcılar istedikleri zaman diledikleri makaleye yorum yapabilirler ancak anonymous üserler için bu geçerli değildir. Çünkü siteme kayıtlı herhangi bir E-pota adresi yoktur Bu yüzden makaleye yorum yapabilmeleri için öncelikle sisteme kayıtlı olmak zorundadırlar. Eğer kullanıcıların E-posta adresi alınmasaydı bu kullanıcılar makalenin altında Kanuni olmayan yorumlarda bulunurlar, bundan kurtlumak için yorum yapmak isteyen kişilerin hepsinin E-posta Adresi alınmak zorundadır. Bu E-posta ve EkleyenIP adres sütunları sayesinde tüm bu sıkıntılardan kurtulmuş oluruz.

Veri Tabanında Sorgu Oluşturmak

Bu kısımda MakaleGrup, MakaleYorum ve Makaleler tablosuna sorgular oluşturacağız. Oluşturacağımız tüm srogular bize oldukça yararlı olacaktır. Sorgu işlemlerini kendimiz oluşturacağımızdan sorguyu istediğimiz gibi şekillendireceğiz. Bununla birlikte sorgumuzu fonksiyonlar şeklinde oluşturacağız Bu işlemin bize sağladığı faydalara gelirsek; Örneğin Projemizde bir çok yerde makaleleri sıralatacağız. Ancak her defasında aynı sorguyu ayrı ayrı yazmak yerine ihtiyacımız olan sorguyu fonksiyon şeklinde oluştururuz. Böylelikle her defasında sorgu yazmak yerine o anda ihtiyacımız olan sorguyu

tutan fonksiyonu çağırırız ve projemizde fazla iş yükünden kurtulmuş oluruz. Ayrıca Sorgu için oluşturduğumuz tüm fonksiynlarıda ilgili mödülün sınıfında tutarız. Ve projemiz daha da anlaşılabilir hale getirmiş oluruz.

Aşşağıdaki tabloda makale modulü için gerekli olan metotlar yazılmıştır;

Sorgu Metotlarının isimleri Tanımlama
GetirMakale Girilen ID'ye göre istenen makaleyi getirir
Getir Makalele Sayisi Tüm makalelerin sayısını döndürür.
GetirMakaleler Tüm makaleleri getirir.
GetirMakaleGrup Verilen ID'ye göre MakaleGrup(Kategori) tablosunun içindeki veriye ulaşır
GetirMakaleGruplari Tüm MakaleGrup Tablosunu getirir
GetirYayinlanmisMakaleSayisi Yayınlanmış tüm makalelerin sayısını getirir.
GetirYayinlanmisMakaleler Yayınlanmış tüm makaleleri getirir.

Yukarıda yazılan bir çok komut ihtiyacımız olan standart sorgulardır. Bu sorgu metotları sistemimize performans açısından fark edilebilir bir etkisi vardır;

v Tüm sorgular makalelerin kayıt edilebilmesi için iki tane parametre almak zorundadır. İlk parametre Makalenin kaydedileceği sayfa index'ini gösterir. Diğer makale ise makalenin kategorisini(Makale grubunu) gösterir. Sayfalama mekanizması tüm makaleleri sayfa sayfa listelenmiş bir şekilde kullanıcı ve yönetici sayfalarında gösterilir.

v Makalenin gösterilebilesi için makale tablosuna eklenen makale Kategori(MakaleGrup) ID'si ile birlikte kaydedilmek zorundadır. Yine aynı şekilde İstenen Makaledeki yorumların gösterilebilmesi için yorumlar MakaleYorum tablosuna yorum yaptıkları makalenin ID'si ile birlikte kaydedilmek zorundadır. Makale veya yorumların sayfada listeleyebilmek için bir çok ayrı sorgudan kaçınmamız gerekmektedir.

v Dikkat ettiğiniz üzere veri tabanından kaydetme silme ve güncelleme sorguları yoktur. Çünkü bu işlemlerin hepsini veri ve iş katmanlarında(sınıflarda) LİNQ to SQL sayesinde otamatik olarak yapılmaktadır.

Modelin Tanımlanması

Makaleler MakaleYorum ve MakaleGrup sınıfları genel olaak ortak virtek özelliğe sahiptir. Ek olarak sorgulara ulaşmak için metotlarıda tanımlanmıştır. Burada önemli olan yer ise dönüş tipi olan IEnumerable<T>'dır. Küçüktür büyüktür işareti arasındaki T'nin yerine tablo isimleri(Makaleler,MakaleYorum gibi) gelecektir.Bu IEnumerable<T> sınıfının kütüphanesi System.collection.generic dosyasıdır. Aşağıda basit bir örneği bulunmaktadır.

IEnumerable<Makaleler> makaleler = dc.Makaleler.GetirMakale(1);

Makaleler Model Sınıfı

Makaleler tablosunun bazı alanlarına ulaşabilmek için bize kolaylık sağlaması açsından fonksiyon yazmak gerekmektedir. Örneğin makeleler tablosuna makale eklemek için her defasında Linq to sql komutu yazmak yerine bu işlemi yapan bir fonksiyon yazarız ve kayıt esnasında sadece kayıt olacak olan verileri o fonksiyona göndeririz böylelikle fazla işyükünden kurtulmuş oluruz. Linq to Sql bu sınıfı partial sınıf gibi oluşturur. Ayrıca bu sınıfın içine ek fonksiyonlarda yazabilmektedir.

Şekil –3


Makaleler sınıifının eklenen 3 özelliği vardır. Bu özellikler ise Averageing, location ve published özellikleridir ve yine bu özzelikler veritabanında gibi gözünmezler bu metotlar interementViewCount ve rate metotlarıdır. Oluşturduğumuz bir nesneyi ArticleCollectionWrapper olarak isimlendirirlir ve IEnumerable<makaleler> meydana getirmektedir.

Aşağıdaki tabloda tüm özellikler listelenmiştir.

Özellik Açıklama
MakaleID Makalelerin Id numaralarını saklar
EklemeTarihi Eklenem makalelerin tarihini tutar
Ekleyen Makaleyi Oluşturan'ın İsmi
MakaleGrupId Makalenin hangi kategoride olduğunu gösterir.
MakaleGrupBaslik Kategori Başlığı
MakaleGrup Makaleye referanslık eden parent kategori nesnesi
Baslik Başlık
Yolu Url için Yol Başlık
Ozet Kısa bilgi
İçerik İçerik
Ülke Makalenin yayınlandığı ülke
İlçe Makalenin yayınlandığı il
İl Makalenin yayınlandığı İlçe
Yayin Tarihi Makalenin yayınlanma tarihi
Yayin Sonu Makalenin yayından kaldırılma tarihi
Onay Makaenin onaylanıp onaylanmadığını gösterir.
ListeOnay Makalenin sayfada makaleler arasında listelenip listelenmeyeceğini belirler
YorumAcik Makale üzerinde kullanıcıların yorum yapıp yapmayacağını belirler
YalnizcaUyeler Makalenin sadece kayıtlı kullanıcıların mı yoksa herkesin mi okuyabileceğini belirler
OkumaSayisi Makaleyi okunma sayısı
Oy Makaleye atılan oy sayısı
ToplamOran Makalenin toplam oy sayısı
GenelDegerlendirme Makaleye atilan oy sayısı/Makaleyi okuyan saysısı
Yayinla Makaelenin yayınlanıp yayınlanmayacağını belirler. Makalenin belirli tarihler atasında yaınlanmasında tasdik edilen sutundur
Yorumlar Kullanıcılar tarafından yapılan yorumların sayfada göterilip gösterilemeyeceğini belirler.

Aşağıdaki tabloda örnek metotlar listelenmiştir.

Örnek Metot Açıklama
OkunmaSayisiniArtir Makalenin görüntülenme sayısını hesaplar
Oran Makalenin Beğenilme Oranını hesaplar

Bunların dışında tek bir makalenin veya birden çok makalenin listelenmesini sağlayan bir çok static metot vardır. Metotlar hepsi static'dir çünkü ihtiyacı olan veriler ve giriş parametreleri sabittir. Linq to Sql sayesinde makaleler tablosuna sınıfların içine sorgulama yapabilen metotlar yazılabilmiştir.

Dahili Metotlar Açıklama
GetirMakalelerGetirYayinlanmisMakaleleri Makaleleri listeleler ve listelenen makaleleri geri döndürür. Fakat bu metot iki tane parametre alır. İlk parametre sayfa için ikinci parametre ise kategori belirlemek içindir.Not: Eğer yayınlamış makaleleri görüntülemek istiyorsanız onay ve yain tarihlerini kontrol etmek gerekmektedir
GetirMakaleSayisiGetirYayinlanmisMakaleSayisi Bu metot iki tane parametre alır ve belirli bir kategorideki tüm makalelerin sayısını döndürürNot: Eğer yayınlanmış makalelerin sayısını görüntülemek istiyorsanız yine onay ve yayınlanma tarihlerini kontrol etmek gerekmektedir.
GetirMakale Bu metot girilen ID' ye tek bir makale döndürür.

MakaleGrup(Kategori) Sınıfı

Bu sınıfta tamamen makalelerin kategorileri, örnek özellikleri gibi örnek özelliklere sahiptir. Burda biz onların hepsini tanımlamayacağız. Çünkü Makaleler sınıfındaki metotların bir benzeridir. Bu metotlar oldukça basittir. Çünkü makaleler sınıfındaki gibi sayfalama ve diğer kısıtlamalar yoktur.

MakaleYorum Sınıfı

Yorum sınıfı herhangi bir yorumun detaylarını yüklenildiği yerdir ve bazı özelliklere sahip olmalıdır. Bu özelliklerin başında güvenlik açığı gelmektedir. güvenlik açığı ise javascritpt kodları neden olmaktadır bazı uyanıklık yapan kullanıcılar kendi sitesinin hit'ini arttırabilmek için bu kodları sıkça kullanmaktadır. Bu javascript kodları ise script injection ve cross-site-scripting olmak üzere olmak üzere iki tanedir. Script-injection saldırısı sitemizde yorum kısmından yapılmaktadır. Sitemize zarar verecek olan ziyaretçi yorum bölümüne gelip text kımına aşağıdaki javascript kodunu yazarak;

<script>document.location='http://www.kullanicisitesi.com'</script>

Ya da

&lt;script&gt; document.location = ‘http://www.kullanicisitesi.com'; &lt;/script&gt;

Sitemizin bir daha ki açılışında saldırgan'ın istediği siteden açılmasına neden olacaktır. Bundan kurtulmak için sitemizin yorum kısmında html etiketlerini kulanmamaları için < > karakterlerini yada ascii kodlarını aktif etmememiz gerekmektedir. Bunların hepsinden EncodedBody özelliği sayesinde kurtulmaktayız. Cross-site-scripting yöntemi ise genellikle bazı sitelerin firma ekle bölümlerinde gerçekleşmektedir. Bu sitelerin çoğunda firma ekle işlemi gerçekleştiğinde “bu kodu gidip sitenize yapıştırın” ibaresi altında gelen kod parçacığıdır. Bu kodda yine sitemizin başka sitelere yönlenmesine neden olmaktadır. O yüzden bu kod çok emin olmadıkça siteye eklenmemelidir.

Sınıflandırılmış Yorumlar

Makaleler ve Makale grupları için sınıflandırılmış özellik uygulanmayacak. Çünkü bu zaten MakaleGrup tabosunda onemialanında sınıflndırılmıştır. Halbuki makaleler en yeniden en eskiye doğru sınıflandırılmıştır. Bununla birlikte torumların sınıflandırmanın durama göre iki farklı yolu vardır:

v Kullanıcı sayfasında en eskiden en yeniye doğru sıralandığında diğer okuyucular makale hakkındaki yorumları kronik bir şekilde okuyabilir ve isterlerse de tartışmaya katılabilirler.

v Yönetici sayfasında yorumlar en yeniden en eskiye doğru sıralanır. Böylelikle Sayfada ki listenin en başında en son yorum gözükür. Bu yüzden okunan yorum normal ise düzenlenip hemen yayınlanı eğer yorum onur kırıcı nitelikte veya ahlaki değilse bir yorum derhal silinir.

Eğer yorumların sayfalanmasını istiyebilirsiniz. Ancak bu çok daha karmaşık bir yapı gerektirecektir. Bunu alternetif olarak Sql select cümleciği ile ifade edilmektedir.Fakat bu depolama yöntemlerinin avantajlarını kaybetmemize neden olmaktadır.

View Tasarlamak

Asp.net Mvc ‘de makale modulü için özel bir tasarım yapmayacağız. Bu yüzden bu konu üzerinde fazla üzerinde durmayacaız. Makale modulünde yönetici ve kullanıcı olmak üzere 2 view'e sahip olmamız gerekmektedir. Doğal olarak Asp.net mvc'de oluşturacağımız view de dikkat edilmesi gereken en önemli kısım ise oluşturacağımız viewlar'ın daha önce oluştutrduğumuz viewler ile uyum içerisinde olmasıdır. Zaten Asp.net mvc de yer alan masterpage(layput.cshtml) sayesinde işimiz oldukça kolaylaşacaktır. Bizim kullanacağımız Layout.cshtml view' önceki kullamdığımız masterpage sayfasıdır.

Index.cshtml

İstediğiniz makalegruptaki(kategori) mevcut olan makaleleri sayfalayarak listelendiği sayfadır.

  • Anasayfa
  • makalelers/page{page}
  • makalelers/makalegrups/{makalegrup}
  • makalelers/makalegrups/{ makalegrup}/page{page}

MakaleGrupGoruntule.cshtml

Mevcut olan tüm MakaleGruplarını(kategori) listelememizi sağlar.

  • makaleler/makalegrup

MakaleGoruntule.cshtml

Makaleleri ve makaleye yapılan yorumların görüntülenmek için kullanılır.

  • makaleler/{id}/{*yol}

MakaleYonetimi.cshtml

Bu sayfa sistemde mevcut olan makaleleri silmek ve düzenlemek için kullanılır.

  • admin/makaleler

  • "admin/makaleler/page{page}",

MakaleGrupYonetimi.cshtml

Mevcut olan kategorileri(makalegrup)ve linkleri silmek veya düzenlemek için kullanılır.

  • admin/makaleler/makaleGruplari

MakaleYorumYonet.cshtml

Bu sayfada makale yorumlarının silinip onaylanması ve onaylanan yorumların belirtilen sıraya göre listelenme işlemleri gerçekleşir.

  • admin/makaleler/makaleYorumlari
  • admin/makaleler/makaleYorumlari/page{page}

MakaleEkle.cshmtl

Bu sayfa ya mevcut olan makale düzenlemek için yada yeni bir makale eklemek için kullanılır.

  • admin/makaleler/makaleEkle
  • admin/duzenle/{makaleId}

MakaleGrupEkle(kategori).cshtml

MakaleGrupEkle sayfasıda mevcut olan makale düzenlenir veya yeni bir makale grubu eklemek için kullanılır.

  • admin/makaleler/makaleGruplari/ekle
  • admin/makaleler/makalegruplari/duzenle/{makaleGrupId}

MakaleSil.cshtml

Bu sayfada ise karşımıza “makaleyi silmek istediğinizden emin misiniz” bie mesaj kutusu gelir. Eğer evet'i seçersek makale sayfadan ve veritabanıdan silinir.

  • admin/makaleler/sil/{makaleId}

MakaleGrupSil.cshtml

Bu sayfada ise karşımıza “Makale Grubunu silmek istediğinizden emin misiniz” bir mesaj kutusu gelir. Eğer evet'i seçersek Makale Grubu sayfadan ve veritabanıdan silinir.

  • admin/makaleler/makalegruplari/sil/{makaleGrupId}

WYSIWYG Metin Düzenleyicisi ile Makale Yazmak

Projemizde makale yazarken kullanıcıların yazacakları makalenin veya daha önce yazmış üzerinde değişiklik yapabilecekleri kullanışlı bir arayüze sahip olması gerekmektedir. Kullanıcılar html bilmelerine gerek kalmadan makalelerine resim ekleyebilmemizi ve yine makalelerin yazı tipini, yazı büyüklüğünü kalın, italik gibi font özelliklerini kolaylıkla değiştirebilmemiz gerekmektedir. İşte bu noktada bize WYSIWYG metin düzenleyicileri yardımcı olmaktadır. Bu editör sayesinde yazının istediğimiz font özelliklerini değiştirebilir resim ekleyebilir ve kolayca düzenleyebiliriz. Piyasada bu işlemleri yapan birçok editör vardır. Bunların birkaçı ticari amaçlıdır bazıları ise ücretsiz olarak indirilebilmektedir. Bizim TinMCE editörünü kullanacağız. Ayrıca bu editör birçok tarayıcı ile uyumludur.

Şekil –4


Makalenin Elemanları

Her makalede tüm sayfalarda gösterilmesi gereken bazı özellikler vardır. Bu özellikler ise makalelerin okuna sayısı, özeti, nereden yayınlandığı gibi bir çok niteliği olabilir. Mevcut olan makalelerin hepsi listelenirken baştan sona kadar tüm makalelerde bu ortak özellikler gösterilir. Makalenin özellikleri son kullanıcı sayfasında ve siteme kayıtlı olan kullanıcılar tarafından görüntülenebilmektedir. Bu özelliklerin belirlenebilmesi için "~/Views/Shared/Makale/" klasörünün içine MakaleItem adında bir view oluşturmamız gerekmektedir. Bu MakaeItem.cshtml belirlenen sayfada istenen özelliklerin gösterilmesi sağlanmaktadır.

Atom Feeds RRS

Sitedeki yeni bir içeriğin haber başlığının nasıl sunulduğunu herkes tarafından bilinmektedir. Zaten diğer sitelere yeni bir içerik girildiği zaman masaüstü programlarında veya onlie programlarda kolaylıkla bilgisayarınızda bu haber başlığını görebilirsiniz. Makalelerin yolunun listelenmesini sağlayan bu işleme atom denir. Ve syndication olarak adlandırılır. Xml formatı kullanan Atom içeriği doğal olarak oldukça basittir. Aşağıda örnek bir atom içeriği görülmektedir.

<feed xmlns="http://www.w3.org/2005/Atom">
<title type="text">Ideas</title>
<subtitle type="text">Feed of ideas from IdeaPipe.</subtitle>
<id>http://www.ideapipe.com/</id>
<updated>2008-06-14T17:43:58-04:00</updated>
<link rel="self" href="http://www.ideapipe.com/?type=atom" />
<link rel="alternate" href="http://www.ideapipe.com/" />
<link rel="first" href="http://www.ideapipe.com/?type=atom" />
<link rel="next" href="http://www.ideapipe.com/page/2?type=atom" />
<link rel="last" href="http://www.ideapipe.com/page/5?type=atom" />
<entry>
<id>http://www.ideapipe.com/ideas/40/...</id>
<title type="text">I want to subscribe to IdeaPipe ...</title>
<published>2008-05-28T20:41:19-04:00</published>
<updated>2008-06-14T21:43:58Z</updated>
<author>
<name>nick</name>
<uri>http://www.ideapipe.com/users/nick</uri>
</author>
<link rel="alternate" href="http://www.ideapipe.com/ideas/40/..." />
<category term="Misc" />
<content type="xhtml"><![CDATA[
...
]]></content>
</entry>
<entry>
<id>http://www.ideapipe.com/ideas/32/...</id>
<title type="text">IdeaPipe should support OpenID</title>
<published>2008-05-15T22:13:42-04:00</published>
<updated>2008-06-14T21:43:58Z</updated>
<author>
<name>nick</name>
<uri>http://www.ideapipe.com/users/nick</uri>
</author>
<link rel="alternate" href="http://www.ideapipe.com/ideas/32/..." />
<category term="Misc" />
<content type="xhtml"><![CDATA[
...
]]></content>
</entry>
</feed>

Yukarıda görüldüğü üzere kullandığımız atom kaynakları göstermektedir. Atom tanımlamalar için <title> <id> and <updated> gibi bir çok etiket gereklidir. Atom içerisine konulan elemanların her biri, bir numaraya sahip olabilir. İsim uzayları <link>,<subtitle> ve diğer tanımlamaların biçimlerini içerir. Posts/makaleler/haberler ‘in alt etiket olan <entry> etiketinin içerisinde yer almaktadır. Ve title, atuhor, link, category etiketleri <entry> etiketinin içerisinde yer almaktadır. Rss kontrolü veya atom özellikleri için detaylı bilgi almak istiyorsanız http://tools.ietf.org/html/rfc4287 adresinden ulaşabilirsiniz.

Önemli olan bir başka nokta ise geçerli olan Xml biçimidir. Atom için
Xml ve Html dillerini ayrı ayrı kullanmak yerine bu her iki dilide içinde barındıran Xhtml dilinin kullanılması gerekmektedir. Xhtml'de açılan etiketler kesinlikle kapatılmak zorundadır. İki farklı biçimde etiket tanımla şekli vardır. Birincisi etiketi açıp iki etiket arasında gerekli olan içeriği girdikten sonra kapatmak( <p>içindekiler</p> ) diğeri ise direk bir etiketin içinde açıp kapatmak(<img.../>) şeklindedir. Yayınlama ve güncelleme tarihi tanımlama biçimi Yıl/Ay/GünTSaat:Dakika:Saniye:z şekilinde olmalıdır. Ve gösterilmesi gereken haber makale gibi içerik content etiketinin içine yazılmalıdır.

Eğer Atom feeds her bir sayfa için yapmak istiyorsanız aşağıdaki gibi bir meta etiketinin içine kendi sitenizin özelliklerini yazarak her bir sayfanın üztüne ekleyebilirsiniz.

<link rel="alternate" type="application/atom+xml" title="IdeaPipe Feed"

href="http://www.ideapipe.com/?type=atom" />

Controller Oluşturmak

Controller kısmı makale modulü için iş yükü en az olan bölümdür. Çünkü bu modul için işin en zor kısmı view ve model elemanlarıydı. Biz model ve view kısımlarını oluşturduğumuzdan işin zor olan kısmını bitirmiş olduk. Öncelikle maklale adında bir controller oluşturulmalıdır. Daha sonra model view ve map gibi gerekli olan dosyalar için action result fonksiyonları oluşturulmalıdır. Gerekli olan ationresult fonksiyonlarımız aşağıdaki tabloda tanımlanmıştır. Tablonun ilk sütunu actioon metoduuzun ismidir. İkinci sütunu ise yetki alanıdır. Ve son olarak üçüncü situn ise action metodumuzun alacağı parametre sayısıdır.

Action Metot Güvenlik Parametre
IndexMakaleGrupIndexMakaleGoruntule
MakaleOranlaMakaleYonetMakaleGrupYonetMakaleYorumYonetMakaleEkleMakaleDuzenle

MakaleSil

MakaleGrupEkle

MakaleGrupDuzenle

MakaleGrupSil
YorumEkle

YorumDuzenle

YorumSil

--------
----
----EditorEditorEditorContributorEditorEditorEditorEditor

Editor

---

Editor

Editor

String MakaleGrup, int page----int Id, string yolint makaleId, int oranint page--------
int? refMakaleGrupId, string baslik, string ozet, string icerik, string ulke, string ilce, string sehir, DateTime? yayinTarihi, DateTime? yayinSonu, bool? onay, bool? listeOnay, bool? yorumaAcik, bool? YalnizcaUyelerint makaleID, int? RefmakaleGrupID, string baslik, string ozet, string icerik, string ulke, string ilce, string sehir, DateTime? yayinTarihi, DateTime? yayinSonu, bool? onay, bool? listeOnay, bool? yorumaAcik, bool? yalnizcaUyelerint makaleId, string silstring baslik, int? onemi, string resimYolu, string tanimiint makaleGrupID, string baslik, int? onemi, string resimYolu, string tanimi

int makaleGrupID, int? yeniMakaleGrupID, string sil

int makaleID, string adi, string email, string içerik

int yorumID, string adi, string içerik

int yorumID

Güvenlik için gerekli olan ihtiyaçlar

Makale yönetim modulü temelde gerekli olan iki ayrı parçadan oluşmaktadır.

v Yönetim bölümünden Web sorumlusuna veya diğer belirlenmiş bireylere kategorileri veya makaleleri ekleme, düzenleme, silme ve yayınlama izni veya yorumları onaylama,düzenleme izni verilebilmelidir.

v Son kullanıcı bölümünde sitede gezinme süresince o makalenin okunma sayısı beğenilme oranı gibi haber başlığı gibi birtakım özellikler güvenli bir şekilde gösterilmelidir.

Elbette ki her sayfada farklı güvenlik boyutları mevcuttur. Örneğin yönetici sayfasına hiçbir zaman son kullanıcı erişememelidir. Ayrıca anonim kullanıcılar login olmadan üyelik sitemi ile verilen yetkilere sahip olmamalıdır.

Bu modul için iki tane yetkiye ihtiyaç vardır.

  • Yönetici ve Editörler: Makale işlemlerinin hepsi bu kullanıcılar üzerinden yürütülmektedir. Bu yetkiye sahip kullanıcılar yotumları ınaylayabilir kategori ve makale ekleyebilir, silebilir ve güncelleyebilir.
  • Yazar: Bu yetkiye sahipo kullanıcıların makale yazabilmesi için editör veya Yönetici tarafından onaylanması gerekmektedir.

Uygulama

Uygulama bölümünde model view ve controllerın güvenliğinin sağlanması için analiz kısmındaki veritabanı tablolarının oluşumundan bazı yolları kullanacağız.

Configuration Modulü

Web configten veri almak için kullanılır. MakaleElement sınıfı ~/Configuration/ MakalelerElement.cs dosyasında bulunur. Web configten veri almak oldukça karmaşıktır. Bir çok Asp.net Mvc kullanıcısı web configten veri almak kısmında sıkıntı yaşamaktadır. Web configten veri alabilme,k bize oluşturduğumuz projede sayfalama mekanizması oluştururken oldukça kolaylık sağlamaktadır. Web.configten veri alabilen genel bir uygulama yaparak projemiz içinde yer alan configuration modulünü anlamanız daha kolay olacaktır.

Öncelikle Asp.net Mvc 3.0'da verialma adında bir proje oluşturuyoruz. Ancak oluşturduğumuz projenin tipini seçerken internet uygulaması seçmeyi unutmuyoruz.Web configte veri alabilmek için ilk olarak web.config dosyasına giderek section'ınımızın ismi yazıyoruz. Buradaki isim oluşturduğumuz section ismi olarak aynı olmak zorundadır.(Şekil-5)

Şekil –5


Daha sonra Projemize Configuration adında bir klasör ekliyoruz ve içine bir tane veriAlmaSection adında cs dosyası oluşturuyoruz. Ve içine şekil-6 deki gibi düzenliyoruz.

Şekil-6


Sonraki aşamada ise yine Configuration klasörünün içine MakalelerElement adında bir cs dosyası oluşturuyoruz ve içini şekil-7 teki gibi düzenliyoruz.

Şekil –7


Daha sonra ise yine web config dosyasının içine giderek webconfigten alacağımız veriyi yazıyoruz. Ancak oluşturduğumuz veri section ismi ile aynı olan etiketler arasına yazmak zorundayız.(şekil-8)

Şekil –8


Yukarıdaki tüm ayarlamalar web configten veri alabilmek içindi şimdi ise bu veriyi alabilmek için gerekli olan kodu Index ActionResult'ın içne yazıyoruz ve view ‘a gönderiyoruz.(şekil-9)

Şekil –9


Son olrak ise projemizi çalıştırdığımızda ekran çıktısı aşağıdaki gibidir.(Şekil-10)

Şekil –10


Model Uygulaması

Veri tabanı tabloları Microsoft SQL Server Management Studio Express ile doğru bir şekilde oluşturulduğundan tabloalar üzerinden fazla durmayacağız. Tabladaki her bir alanın ayarlaması analiz bölümünde bahsetmiştik

Tablolar arası ilişkiler

Sql server 2008'e oluşturduğumuz tabloları şema biçiminde de görebiliriz. Öncelikle server explorer üzerinde kendi veri tabanımızla bağlantı kurup gerekli ona veri tabanını ekliyoruz. Daha sonra database diagram üzerine gelip sağtuş yapıp yeni bir Add New Diagram tıklayıp makale için gerekli olan tabloları(makale,MakaleGrup,Yorum) ekliyoruz. Bu üç tablo arasındaki bağlantıların otamatik olarak server explorer tarafından oluşturulur. Eğer MakaleGrupId alanına tıklanmaz ve sürükleyip Makaleler tablosunun ikonu üzerine bırakılmazsa bu ilişkilendirmeyi server explorer yapamaz. İlişkilendirme yapılırken butonu bıraktığımızda karşımıza bir dialog kutusu açılır. Açılan dialog kutusundan gerekli ilişkilendirmeler yapılır ve tamam denir ve böylelikle kolaylıkla iki tabloyu ilişkilendirmiş oluruz. Yine aynı yoları izleyerek makaleler tablosu ile yorum tablosu ilişkilendirilir.

Tablolar ilişkilendirildikten sonra unutulmaması gereken bir diğer nokta ise bir biri ile ardı sıra ilişkili tablolarda silme ve günceleme kuralıdır. Yine bu sıkıntıyda Asp. Net MVC'de içinde yer alan cascade ile kolaylıkla halledilebilmektedir. Cascade kısmına gelebilmek için ilişki kurduğumuz bağlantı üzerine gelip sağtuş yapıp properties tıklayarak veya F4'e basarak gelinebilir. Daha sonra Update Rule ve Delete Rule Kısımları Cascade yapılarak işlemler tamamlanmış olur.

Şekil –11


Update Rule = MakaleGrup tablosundan categoriid(MakaleGrupId ) değiştirildiyse, bu değişikliklerin makaleler tablosunda da yapılması gerekmektedir. Ancak cascade tercihlerinden update rule seçersek bizim yapmamı gereken tüm işlemleri asp.net mvc bizim yerimize yapar ve bizi bir sürü iş yükünden kurtarır.

Delete Rule = Delete Rule seçeneği eğer bir kategori silmek istendiğinde onunla bağlantılı tüm makaleleri silinmesini sağlamaktadır. Böylelikle veritabanında veri tabanını fazladan veri ile meşgul edilmeyecektir. Eğer buy seçeneği seçmeyi unutursan veri tabanı ulaşılamayan makalelerle dolar. Ve sistemimizde performans kayıpları meydana gelir.

LINQ to Entity Şemasının Oluşturulması

Öncelikle MakaleGrup Makaleler ve MakaleYorumlari Tablolari oluşturulmalıdır. Ve bu işelemler server explorer içinde yapılmalıdır. Linq to entity şemasına henüz programınızın içerisinde yoksa Models klasörünün üzerine sağ tıklayıp ekleyebilirsiniz(~/Models ve ekle). Oluşan şema aşağıda şekil-12 gibi olmalıdır

Şekil –12


Linq to Sql Edmx

Linq to Sql EDMX adında özel bir dile daha sahip olmuştur. Edmx dili veri tabanında bağlantılı nesne oluşturmak için kullanılır. Linq to Sql dilinin öncek i versiyonları sadece sql veritabanı ile bağlantı kurabilirken Edmx dili sayesinde diğer bütün veritabanı modelleri ile bağlantı kurulabilmektedir. Bu özellik sayesinde özel yapılarla veri tabanına tablo eklenilir ve bu tablolara sutun eklenebilmetedir. Soluntion explorer kısmında yer alan .edmx uzantılı dosya bu eklediğimiz üç tablonun görsel olarak göstermektedir. Ancak bu görsel olarak oluşturulan tabloların birde kayna kod kısmı dediğimiz Xml bölümü vardır. Görsel olarak gördüğünüz bütün sütunların xml tarafında karşılığı bulunmaktadır. Bu üç tablonun Xml kısmı aşağıdaki gibidir. Bu Xml kısmını ve görsel kısmını görerek işlem yapmak veritabanı işlemerini anlamanız açsısından oldukça yararlı olacaktır.

Makale Tablosu

<EntitySetMapping Name="Makalelers">
<EntityTypeMapping TypeName="KarayelModel.Makaleler">
<MappingFragment StoreEntitySet="Makaleler">
<ScalarProperty Name="ToplamOran" ColumnName="ToplamOran" />
<ScalarProperty Name="Oy" ColumnName="Oy" />
<ScalarProperty Name="OkunmaSayisi" ColumnName="OkunmaSayisi" />
<ScalarProperty Name="YalnizcaUyeler" ColumnName="YalnizcaUyeler" />
<ScalarProperty Name="YorumaAcik" ColumnName="YorumaAcik" />
<ScalarProperty Name="ListeOnay" ColumnName="ListeOnay" />
<ScalarProperty Name="Onay" ColumnName="Onay" />
<ScalarProperty Name="YayinSonu" ColumnName="YayinSonu" />
<ScalarProperty Name="YayinTarihi" ColumnName="YayinTarihi" />
<ScalarProperty Name="Sehir" ColumnName="Sehir" />
<ScalarProperty Name="Ilce" ColumnName="Ilce" />
<ScalarProperty Name="Ulke" ColumnName="Ulke" />
<ScalarProperty Name="Icerik" ColumnName="Icerik" />
<ScalarProperty Name="Ozet" ColumnName="Ozet" />
<ScalarProperty Name="Yolu" ColumnName="Yolu" />
<ScalarProperty Name="Baslik" ColumnName="Baslik" />
<ScalarProperty Name="RefMakaleGrupID" ColumnName="RefMakaleGrupID" />
<ScalarProperty Name="Ekleyen" ColumnName="Ekleyen" />
<ScalarProperty Name="EklemeTarihi" ColumnName="EklemeTarihi" />
<ScalarProperty Name="MakaleID" ColumnName="MakaleID" />
</MappingFragment>
</EntityTypeMapping>
</EntitySetMapping>
<EntitySetMapping Name="MakaleYorumlaris">
<EntityTypeMapping TypeName="KarayelModel.MakaleYorumlari">
<MappingFragment StoreEntitySet="MakaleYorumlari">
<ScalarProperty Name="Icerik" ColumnName="Icerik" />
<ScalarProperty Name="RefMakaleID" ColumnName="RefMakaleID" />
<ScalarProperty Name="EkleyenIP" ColumnName="EkleyenIP" />
<ScalarProperty Name="EkleyenEmail" ColumnName="EkleyenEmail" />
<ScalarProperty Name="Ekleyen" ColumnName="Ekleyen" />
<ScalarProperty Name="EklemeTarihi" ColumnName="EklemeTarihi" />
<ScalarProperty Name="MakaleYorumID" ColumnName="MakaleYorumID" />
</MappingFragment>
</EntityTypeMapping>
</EntitySetMapping>
<EntitySetMapping Name="Ulkes">
<EntityTypeMapping TypeName="KarayelModel.Ulke">
<MappingFragment StoreEntitySet="Ulke">
<ScalarProperty Name="UlkeAdi" ColumnName="UlkeAdi" />
<ScalarProperty Name="UlkeID" ColumnName="UlkeID" />
</MappingFragment>
</EntityTypeMapping>
</EntitySetMapping>
</EntityContainerMapping>
</Mapping>
</edmx:Mappings>
<Association Name="FK_MakaleYorumlari_Makaleler">
<End Role="Makaleler" Type="KarayelModel.Store.Makaleler" Multiplicity="1">
<OnDelete Action="Cascade" />
</End>
<End Role="MakaleYorumlari" Type="KarayelModel.Store.MakaleYorumlari" Multiplicity="*" />
<ReferentialConstraint>
<Principal Role="Makaleler">
<PropertyRef Name="MakaleID" />
</Principal>
<Dependent Role="MakaleYorumlari">
<PropertyRef Name="RefMakaleID" />
</Dependent>
</ReferentialConstraint>
</Association>

Yukarıdaki kodda en alttaki Association etiketi içerisindeki kısım bize tablonun özellikleri hakkında bilgi vermektedir. Örneğin makaleler tablosunun hangi tablolar ile ilişkili olduğu cascade özellikleri gibi tablo özellikleri yer almaktadır.

MakaleGrup Tablosu

<EntityType Name="MakaleGrup">
<Key>
<PropertyRef Name="MakaleGrupID" />
</Key>
<Property Name="MakaleGrupID" Type="int" Nullable="false" StoreGeneratedPattern="Identity" />
<Property Name="EklemeTarihi" Type="datetime" Nullable="false" />
<Property Name="Ekleyen" Type="nvarchar" Nullable="false" MaxLength="256" />
<Property Name="Baslik" Type="nvarchar" Nullable="false" MaxLength="256" />
<Property Name="Yolu" Type="nvarchar" MaxLength="256" />
<Property Name="Onemi" Type="int" Nullable="false" />
<Property Name="Tanimi" Type="nvarchar" />
<Property Name="ResimYolu" Type="nvarchar" MaxLength="256" />
</EntityType>
MakaleYorumlari Tablosu
<EntityType Name="MakaleYorumlari">
<Key>
<PropertyRef Name="MakaleYorumID" />
</Key>
<Property Name="MakaleYorumID" Type="int" Nullable="false" StoreGeneratedPattern="Identity" />
<Property Name="EklemeTarihi" Type="datetime" Nullable="false" />
<Property Name="Ekleyen" Type="nvarchar" Nullable="false" MaxLength="256" />
<Property Name="EkleyenEmail" Type="nvarchar" Nullable="false" MaxLength="256" />
<Property Name="EkleyenIP" Type="nvarchar" Nullable="false" MaxLength="15" />
<Property Name="RefMakaleID" Type="int" Nullable="false" />
<Property Name="Icerik" Type="nvarchar(max)" Nullable="false" />
</EntityType>

The LINQ to Entity Classes

Öncelikle System.Object kütüphanesinden türetilmiş olan bir sınıf oluşturulmalıdır.

Bu sınıf önemli kısımdır. Çünkü veri tabanı ile kurulur ve tablonu alanların herhangi bir değişik olduğu zaman veri tabanını güncellemek gerekmektedir. Bu aşağıda yazan iki olay bu güncellemeleri yerine getirmektedir.

public event PropertyChangingEventHandler PropertyChanging;

public event PropertyChangedEventHandler PropertyChanged;

Bu olaylar sınıfa eklenir. DataContext bu olayları izler ve her nesne için yapılan değişiklikleri denetler. Eğer bir değişiklik gördüyse bu değişikliği veritabanına kaydeder. Bu sınıf aşağıdaki kodları içermektedir.

using System;
using System.Data.Objects;
using System.Data.Objects.DataClasses;
using System.Data.EntityClient;
using System.ComponentModel;
using System.Xml.Serialization;
using System.Runtime.Serialization;
[assembly: EdmSchemaAttribute()]
#region EDM Relationship Metadata
[assembly: EdmRelationshipAttribute("KarayelModel", "FK_Makale_Categories", "MakaleGrup", System.Data.Metadata.Edm.RelationshipMultiplicity.One, typeof(KarayelTasarim.Models.MakaleGrup), "Makaleler", System.Data.Metadata.Edm.RelationshipMultiplicity.Many, typeof(KarayelTasarim.Models.Makaleler), true)]
[assembly: EdmRelationshipAttribute("KarayelModel", "FK_MakaleYorumlari_Makaleler", "Makaleler", System.Data.Metadata.Edm.RelationshipMultiplicity.One, typeof(KarayelTasarim.Models.Makaleler), "MakaleYorumlari", System.Data.Metadata.Edm.RelationshipMultiplicity.Many, typeof(KarayelTasarim.Models.MakaleYorumlari), true)]
#endregion
namespace KarayelTasarim.Models
{
#region Contexts
/// <summary>
/// No Metadata Documentation available.
/// </summary>
public partial class KarayelEntities : ObjectContext
{
#region Constructors
/// <summary>
/// Initializes a new KarayelEntities object using the connection string found in the 'KarayelEntities' section of the application configuration file.
/// </summary>
public KarayelEntities() : base("name=KarayelEntities", "KarayelEntities")
{
this.ContextOptions.LazyLoadingEnabled = true;
OnContextCreated();
}
/// <summary>
/// Initialize a new KarayelEntities object.
/// </summary>
public KarayelEntities(string connectionString) : base(connectionString, "KarayelEntities")
{
this.ContextOptions.LazyLoadingEnabled = true;
OnContextCreated();
}
/// <summary>
/// Initialize a new KarayelEntities object.
/// </summary>
public KarayelEntities(EntityConnection connection) : base(connection, "KarayelEntities")
{
this.ContextOptions.LazyLoadingEnabled = true;
OnContextCreated();
}
#endregion
#region Partial Methods
partial void OnContextCreated();
#endregion
#region ObjectSet Properties
/// <summary>
/// No Metadata Documentation available.
/// </summary>
public ObjectSet<MakaleGrup> MakaleGrups
{
get
{
if ((_MakaleGrups == null))
{
_MakaleGrups = base.CreateObjectSet<MakaleGrup>("MakaleGrups");
}
return _MakaleGrups;
}
}
private ObjectSet<MakaleGrup> _MakaleGrups;
/// <summary>
/// No Metadata Documentation available.
/// </summary>
public ObjectSet<Makaleler> Makalelers
{
get
{
if ((_Makalelers == null))
{
_Makalelers = base.CreateObjectSet<Makaleler>("Makalelers");
}
return _Makalelers;
}
}
private ObjectSet<Makaleler> _Makalelers;
/// <summary>
/// No Metadata Documentation available.
/// </summary>
public ObjectSet<MakaleYorumlari> MakaleYorumlaris
{
get
{
if ((_MakaleYorumlaris == null))
{
_MakaleYorumlaris = base.CreateObjectSet<MakaleYorumlari>("MakaleYorumlaris");
}
return _MakaleYorumlaris;
}
}
private ObjectSet<MakaleYorumlari> _MakaleYorumlaris;
/// <summary>
/// No Metadata Documentation available.
/// </summary>
public ObjectSet<Ulke> Ulkes
{
get
{
if ((_Ulkes == null))
{
_Ulkes = base.CreateObjectSet<Ulke>("Ulkes");
}
return _Ulkes;
}
}
private ObjectSet<Ulke> _Ulkes;
#endregion
#region AddTo Methods
/// <summary>
/// Deprecated Method for adding a new object to the MakaleGrups EntitySet. Consider using the .Add method of the associated ObjectSet&lt;T&gt; property instead.
/// </summary>
public void AddToMakaleGrups(MakaleGrup makaleGrup)
{
base.AddObject("MakaleGrups", makaleGrup);
}
/// <summary>
/// Deprecated Method for adding a new object to the Makalelers EntitySet. Consider using the .Add method of the associated ObjectSet&lt;T&gt; property instead.
/// </summary>
public void AddToMakalelers(Makaleler makaleler)
{
base.AddObject("Makalelers", makaleler);
}
/// <summary>
/// Deprecated Method for adding a new object to the MakaleYorumlaris EntitySet. Consider using the .Add method of the associated ObjectSet&lt;T&gt; property instead.
/// </summary>
public void AddToMakaleYorumlaris(MakaleYorumlari makaleYorumlari)
{
base.AddObject("MakaleYorumlaris", makaleYorumlari);
}
/// <summary>
/// Deprecated Method for adding a new object to the Ulkes EntitySet. Consider using the .Add method of the associated ObjectSet&lt;T&gt; property instead.
/// </summary>
public void AddToUlkes(Ulke ulke)
{
base.AddObject("Ulkes", ulke);
}
#endregion
}
#endregion
#region Entities
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[EdmEntityTypeAttribute(NamespaceName="KarayelModel", Name="MakaleGrup")]
[Serializable()]
[DataContractAttribute(IsReference=true)]
public partial class MakaleGrup : EntityObject
{
#region Factory Method
/// <summary>
/// Create a new MakaleGrup object.
/// </summary>
/// <param name="makaleGrupID">Initial value of the MakaleGrupID property.</param>
/// <param name="eklemeTarihi">Initial value of the EklemeTarihi property.</param>
/// <param name="ekleyen">Initial value of the Ekleyen property.</param>
/// <param name="baslik">Initial value of the Baslik property.</param>
/// <param name="onemi">Initial value of the Onemi property.</param>
public static MakaleGrup CreateMakaleGrup(global::System.Int32 makaleGrupID, global::System.DateTime eklemeTarihi, global::System.String ekleyen, global::System.String baslik, global::System.Int32 onemi)
{
MakaleGrup makaleGrup = new MakaleGrup();
makaleGrup.MakaleGrupID = makaleGrupID;
makaleGrup.EklemeTarihi = eklemeTarihi;
makaleGrup.Ekleyen = ekleyen;
makaleGrup.Baslik = baslik;
makaleGrup.Onemi = onemi;
return makaleGrup;
}
#endregion
#region Primitive Properties
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[EdmScalarPropertyAttribute(EntityKeyProperty=true, IsNullable=false)]
[DataMemberAttribute()]
public global::System.Int32 MakaleGrupID
{
get
{
return _MakaleGrupID;
}
set
{
if (_MakaleGrupID != value)
{
OnMakaleGrupIDChanging(value);
ReportPropertyChanging("MakaleGrupID");
_MakaleGrupID = StructuralObject.SetValidValue(value);
ReportPropertyChanged("MakaleGrupID");
OnMakaleGrupIDChanged();
}
}
}
private global::System.Int32 _MakaleGrupID;
partial void OnMakaleGrupIDChanging(global::System.Int32 value);
partial void OnMakaleGrupIDChanged();
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
[DataMemberAttribute()]
public global::System.DateTime EklemeTarihi
{
get
{
return _EklemeTarihi;
}
set
{
OnEklemeTarihiChanging(value);
ReportPropertyChanging("EklemeTarihi");
_EklemeTarihi = StructuralObject.SetValidValue(value);
ReportPropertyChanged("EklemeTarihi");
OnEklemeTarihiChanged();
}
}
private global::System.DateTime _EklemeTarihi;
partial void OnEklemeTarihiChanging(global::System.DateTime value);
partial void OnEklemeTarihiChanged();
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
[DataMemberAttribute()]
public global::System.String Ekleyen
{
get
{
return _Ekleyen;
}
set
{
OnEkleyenChanging(value);
ReportPropertyChanging("Ekleyen");
_Ekleyen = StructuralObject.SetValidValue(value, false);
ReportPropertyChanged("Ekleyen");
OnEkleyenChanged();
}
}
private global::System.String _Ekleyen;
partial void OnEkleyenChanging(global::System.String value);
partial void OnEkleyenChanged();
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
[DataMemberAttribute()]
public global::System.String Baslik
{
get
{
return _Baslik;
}
set
{
OnBaslikChanging(value);
ReportPropertyChanging("Baslik");
_Baslik = StructuralObject.SetValidValue(value, false);
ReportPropertyChanged("Baslik");
OnBaslikChanged();
}
}
private global::System.String _Baslik;
partial void OnBaslikChanging(global::System.String value);
partial void OnBaslikChanged();
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=true)]
[DataMemberAttribute()]
public global::System.String Yolu
{
get
{
return _Yolu;
}
set
{
OnYoluChanging(value);
ReportPropertyChanging("Yolu");
_Yolu = StructuralObject.SetValidValue(value, true);
ReportPropertyChanged("Yolu");
OnYoluChanged();
}
}
private global::System.String _Yolu;
partial void OnYoluChanging(global::System.String value);
partial void OnYoluChanged();
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
[DataMemberAttribute()]
public global::System.Int32 Onemi
{
get
{
return _Onemi;
}
set
{
OnOnemiChanging(value);
ReportPropertyChanging("Onemi");
_Onemi = StructuralObject.SetValidValue(value);
ReportPropertyChanged("Onemi");
OnOnemiChanged();
}
}
private global::System.Int32 _Onemi;
partial void OnOnemiChanging(global::System.Int32 value);
partial void OnOnemiChanged();
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=true)]
[DataMemberAttribute()]
public global::System.String Tanimi
{
get
{
return _Tanimi;
}
set
{
OnTanimiChanging(value);
ReportPropertyChanging("Tanimi");
_Tanimi = StructuralObject.SetValidValue(value, true);
ReportPropertyChanged("Tanimi");
OnTanimiChanged();
}
}
private global::System.String _Tanimi;
partial void OnTanimiChanging(global::System.String value);
partial void OnTanimiChanged();
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=true)]
[DataMemberAttribute()]
public global::System.String ResimYolu
{
get
{
return _ResimYolu;
}
set
{
OnResimYoluChanging(value);
ReportPropertyChanging("ResimYolu");
_ResimYolu = StructuralObject.SetValidValue(value, true);
ReportPropertyChanged("ResimYolu");
OnResimYoluChanged();
}
}
private global::System.String _ResimYolu;
partial void OnResimYoluChanging(global::System.String value);
partial void OnResimYoluChanged();
#endregion
#region Navigation Properties
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[XmlIgnoreAttribute()]
[SoapIgnoreAttribute()]
[DataMemberAttribute()]
[EdmRelationshipNavigationPropertyAttribute("KarayelModel", "FK_Makale_Categories", "Makaleler")]
public EntityCollection<Makaleler> Makalelers
{
get
{
return ((IEntityWithRelationships)this).RelationshipManager.GetRelatedCollection<Makaleler>("KarayelModel.FK_Makale_Categories", "Makaleler");
}
set
{
if ((value != null))
{
((IEntityWithRelationships)this).RelationshipManager.InitializeRelatedCollection<Makaleler>("KarayelModel.FK_Makale_Categories", "Makaleler", value);
}
}
}
#endregion
}
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[EdmEntityTypeAttribute(NamespaceName="KarayelModel", Name="Makaleler")]
[Serializable()]
[DataContractAttribute(IsReference=true)]
public partial class Makaleler : EntityObject
{
#region Factory Method
/// <summary>
/// Create a new Makaleler object.
/// </summary>
/// <param name="makaleID">Initial value of the MakaleID property.</param>
/// <param name="eklemeTarihi">Initial value of the EklemeTarihi property.</param>
/// <param name="ekleyen">Initial value of the Ekleyen property.</param>
/// <param name="refMakaleGrupID">Initial value of the RefMakaleGrupID property.</param>
/// <param name="baslik">Initial value of the Baslik property.</param>
/// <param name="yolu">Initial value of the Yolu property.</param>
/// <param name="icerik">Initial value of the Icerik property.</param>
/// <param name="yayinTarihi">Initial value of the YayinTarihi property.</param>
/// <param name="onay">Initial value of the Onay property.</param>
/// <param name="listeOnay">Initial value of the ListeOnay property.</param>
/// <param name="yorumaAcik">Initial value of the YorumaAcik property.</param>
/// <param name="yalnizcaUyeler">Initial value of the YalnizcaUyeler property.</param>
/// <param name="okunmaSayisi">Initial value of the OkunmaSayisi property.</param>
/// <param name="oy">Initial value of the Oy property.</param>
/// <param name="toplamOran">Initial value of the ToplamOran property.</param>
public static Makaleler CreateMakaleler(global::System.Int32 makaleID, global::System.DateTime eklemeTarihi, global::System.String ekleyen, global::System.Int32 refMakaleGrupID, global::System.String baslik, global::System.String yolu, global::System.String icerik, global::System.DateTime yayinTarihi, global::System.Boolean onay, global::System.Boolean listeOnay, global::System.Boolean yorumaAcik, global::System.Boolean yalnizcaUyeler, global::System.Int32 okunmaSayisi, global::System.Int32 oy, global::System.Int32 toplamOran)
{
Makaleler makaleler = new Makaleler();
makaleler.MakaleID = makaleID;
makaleler.EklemeTarihi = eklemeTarihi;
makaleler.Ekleyen = ekleyen;
makaleler.RefMakaleGrupID = refMakaleGrupID;
makaleler.Baslik = baslik;
makaleler.Yolu = yolu;
makaleler.Icerik = icerik;
makaleler.YayinTarihi = yayinTarihi;
makaleler.Onay = onay;
makaleler.ListeOnay = listeOnay;
makaleler.YorumaAcik = yorumaAcik;
makaleler.YalnizcaUyeler = yalnizcaUyeler;
makaleler.OkunmaSayisi = okunmaSayisi;
makaleler.Oy = oy;
makaleler.ToplamOran = toplamOran;
return makaleler;
}
#endregion
#region Primitive Properties
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[EdmScalarPropertyAttribute(EntityKeyProperty=true, IsNullable=false)]
[DataMemberAttribute()]
public global::System.Int32 MakaleID
{
get
{
return _MakaleID;
}
set
{
if (_MakaleID != value)
{
OnMakaleIDChanging(value);
ReportPropertyChanging("MakaleID");
_MakaleID = StructuralObject.SetValidValue(value);
ReportPropertyChanged("MakaleID");
OnMakaleIDChanged();
}
}
}
private global::System.Int32 _MakaleID;
partial void OnMakaleIDChanging(global::System.Int32 value);
partial void OnMakaleIDChanged();
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
[DataMemberAttribute()]
public global::System.DateTime EklemeTarihi
{
get
{
return _EklemeTarihi;
}
set
{
OnEklemeTarihiChanging(value);
ReportPropertyChanging("EklemeTarihi");
_EklemeTarihi = StructuralObject.SetValidValue(value);
ReportPropertyChanged("EklemeTarihi");
OnEklemeTarihiChanged();
}
}
private global::System.DateTime _EklemeTarihi;
partial void OnEklemeTarihiChanging(global::System.DateTime value);
partial void OnEklemeTarihiChanged();
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
[DataMemberAttribute()]
public global::System.String Ekleyen
{
get
{
return _Ekleyen;
}
set
{
OnEkleyenChanging(value);
ReportPropertyChanging("Ekleyen");
_Ekleyen = StructuralObject.SetValidValue(value, false);
ReportPropertyChanged("Ekleyen");
OnEkleyenChanged();
}
}
private global::System.String _Ekleyen;
partial void OnEkleyenChanging(global::System.String value);
partial void OnEkleyenChanged();
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
[DataMemberAttribute()]
public global::System.Int32 RefMakaleGrupID
{
get
{
return _RefMakaleGrupID;
}
set
{
OnRefMakaleGrupIDChanging(value);
ReportPropertyChanging("RefMakaleGrupID");
_RefMakaleGrupID = StructuralObject.SetValidValue(value);
ReportPropertyChanged("RefMakaleGrupID");
OnRefMakaleGrupIDChanged();
}
}
private global::System.Int32 _RefMakaleGrupID;
partial void OnRefMakaleGrupIDChanging(global::System.Int32 value);
partial void OnRefMakaleGrupIDChanged();
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
[DataMemberAttribute()]
public global::System.String Baslik
{
get
{
return _Baslik;
}
set
{
OnBaslikChanging(value);
ReportPropertyChanging("Baslik");
_Baslik = StructuralObject.SetValidValue(value, false);
ReportPropertyChanged("Baslik");
OnBaslikChanged();
}
}
private global::System.String _Baslik;
partial void OnBaslikChanging(global::System.String value);
partial void OnBaslikChanged();
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
[DataMemberAttribute()]
public global::System.String Yolu
{
get
{
return _Yolu;
}
set
{
OnYoluChanging(value);
ReportPropertyChanging("Yolu");
_Yolu = StructuralObject.SetValidValue(value, false);
ReportPropertyChanged("Yolu");
OnYoluChanged();
}
}
private global::System.String _Yolu;
partial void OnYoluChanging(global::System.String value);
partial void OnYoluChanged();
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=true)]
[DataMemberAttribute()]
public global::System.String Ozet
{
get
{
return _Ozet;
}
set
{
OnOzetChanging(value);
ReportPropertyChanging("Ozet");
_Ozet = StructuralObject.SetValidValue(value, true);
ReportPropertyChanged("Ozet");
OnOzetChanged();
}
}
private global::System.String _Ozet;
partial void OnOzetChanging(global::System.String value);
partial void OnOzetChanged();
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
[DataMemberAttribute()]
public global::System.String Icerik
{
get
{
return _Icerik;
}
set
{
OnIcerikChanging(value);
ReportPropertyChanging("Icerik");
_Icerik = StructuralObject.SetValidValue(value, false);
ReportPropertyChanged("Icerik");
OnIcerikChanged();
}
}
private global::System.String _Icerik;
partial void OnIcerikChanging(global::System.String value);
partial void OnIcerikChanged();
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=true)]
[DataMemberAttribute()]
public global::System.String Ulke
{
get
{
return _Ulke;
}
set
{
OnUlkeChanging(value);
ReportPropertyChanging("Ulke");
_Ulke = StructuralObject.SetValidValue(value, true);
ReportPropertyChanged("Ulke");
OnUlkeChanged();
}
}
private global::System.String _Ulke;
partial void OnUlkeChanging(global::System.String value);
partial void OnUlkeChanged();
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=true)]
[DataMemberAttribute()]
public global::System.String Ilce
{
get
{
return _Ilce;
}
set
{
OnIlceChanging(value);
ReportPropertyChanging("Ilce");
_Ilce = StructuralObject.SetValidValue(value, true);
ReportPropertyChanged("Ilce");
OnIlceChanged();
}
}
private global::System.String _Ilce;
partial void OnIlceChanging(global::System.String value);
partial void OnIlceChanged();
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=true)]
[DataMemberAttribute()]
public global::System.String Sehir
{
get
{
return _Sehir;
}
set
{
OnSehirChanging(value);
ReportPropertyChanging("Sehir");
_Sehir = StructuralObject.SetValidValue(value, true);
ReportPropertyChanged("Sehir");
OnSehirChanged();
}
}
private global::System.String _Sehir;
partial void OnSehirChanging(global::System.String value);
partial void OnSehirChanged();
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
[DataMemberAttribute()]
public global::System.DateTime YayinTarihi
{
get
{
return _YayinTarihi;
}
set
{
OnYayinTarihiChanging(value);
ReportPropertyChanging("YayinTarihi");
_YayinTarihi = StructuralObject.SetValidValue(value);
ReportPropertyChanged("YayinTarihi");
OnYayinTarihiChanged();
}
}
private global::System.DateTime _YayinTarihi;
partial void OnYayinTarihiChanging(global::System.DateTime value);
partial void OnYayinTarihiChanged();
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=true)]
[DataMemberAttribute()]
public Nullable<global::System.DateTime> YayinSonu
{
get
{
return _YayinSonu;
}
set
{
OnYayinSonuChanging(value);
ReportPropertyChanging("YayinSonu");
_YayinSonu = StructuralObject.SetValidValue(value);
ReportPropertyChanged("YayinSonu");
OnYayinSonuChanged();
}
}
private Nullable<global::System.DateTime> _YayinSonu;
partial void OnYayinSonuChanging(Nullable<global::System.DateTime> value);
partial void OnYayinSonuChanged();
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
[DataMemberAttribute()]
public global::System.Boolean Onay
{
get
{
return _Onay;
}
set
{
OnOnayChanging(value);
ReportPropertyChanging("Onay");
_Onay = StructuralObject.SetValidValue(value);
ReportPropertyChanged("Onay");
OnOnayChanged();
}
}
private global::System.Boolean _Onay;
partial void OnOnayChanging(global::System.Boolean value);
partial void OnOnayChanged();
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
[DataMemberAttribute()]
public global::System.Boolean ListeOnay
{
get
{
return _ListeOnay;
}
set
{
OnListeOnayChanging(value);
ReportPropertyChanging("ListeOnay");
_ListeOnay = StructuralObject.SetValidValue(value);
ReportPropertyChanged("ListeOnay");
OnListeOnayChanged();
}
}
private global::System.Boolean _ListeOnay;
partial void OnListeOnayChanging(global::System.Boolean value);
partial void OnListeOnayChanged();
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
[DataMemberAttribute()]
public global::System.Boolean YorumaAcik
{
get
{
return _YorumaAcik;
}
set
{
OnYorumaAcikChanging(value);
ReportPropertyChanging("YorumaAcik");
_YorumaAcik = StructuralObject.SetValidValue(value);
ReportPropertyChanged("YorumaAcik");
OnYorumaAcikChanged();
}
}
private global::System.Boolean _YorumaAcik;
partial void OnYorumaAcikChanging(global::System.Boolean value);
partial void OnYorumaAcikChanged();
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
[DataMemberAttribute()]
public global::System.Boolean YalnizcaUyeler
{
get
{
return _YalnizcaUyeler;
}
set
{
OnYalnizcaUyelerChanging(value);
ReportPropertyChanging("YalnizcaUyeler");
_YalnizcaUyeler = StructuralObject.SetValidValue(value);
ReportPropertyChanged("YalnizcaUyeler");
OnYalnizcaUyelerChanged();
}
}
private global::System.Boolean _YalnizcaUyeler;
partial void OnYalnizcaUyelerChanging(global::System.Boolean value);
partial void OnYalnizcaUyelerChanged();
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
[DataMemberAttribute()]
public global::System.Int32 OkunmaSayisi
{
get
{
return _OkunmaSayisi;
}
set
{
OnOkunmaSayisiChanging(value);
ReportPropertyChanging("OkunmaSayisi");
_OkunmaSayisi = StructuralObject.SetValidValue(value);
ReportPropertyChanged("OkunmaSayisi");
OnOkunmaSayisiChanged();
}
}
private global::System.Int32 _OkunmaSayisi;
partial void OnOkunmaSayisiChanging(global::System.Int32 value);
partial void OnOkunmaSayisiChanged();
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
[DataMemberAttribute()]
public global::System.Int32 Oy
{
get
{
return _Oy;
}
set
{
OnOyChanging(value);
ReportPropertyChanging("Oy");
_Oy = StructuralObject.SetValidValue(value);
ReportPropertyChanged("Oy");
OnOyChanged();
}
}
private global::System.Int32 _Oy;
partial void OnOyChanging(global::System.Int32 value);
partial void OnOyChanged();
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
[DataMemberAttribute()]
public global::System.Int32 ToplamOran
{
get
{
return _ToplamOran;
}
set
{
OnToplamOranChanging(value);
ReportPropertyChanging("ToplamOran");
_ToplamOran = StructuralObject.SetValidValue(value);
ReportPropertyChanged("ToplamOran");
OnToplamOranChanged();
}
}
private global::System.Int32 _ToplamOran;
partial void OnToplamOranChanging(global::System.Int32 value);
partial void OnToplamOranChanged();
#endregion
#region Navigation Properties
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[XmlIgnoreAttribute()]
[SoapIgnoreAttribute()]
[DataMemberAttribute()]
[EdmRelationshipNavigationPropertyAttribute("KarayelModel", "FK_Makale_Categories", "MakaleGrup")]
public MakaleGrup MakaleGrup
{
get
{
return ((IEntityWithRelationships)this).RelationshipManager.GetRelatedReference<MakaleGrup>("KarayelModel.FK_Makale_Categories", "MakaleGrup").Value;
}
set
{
((IEntityWithRelationships)this).RelationshipManager.GetRelatedReference<MakaleGrup>("KarayelModel.FK_Makale_Categories", "MakaleGrup").Value = value;
}
}
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[BrowsableAttribute(false)]
[DataMemberAttribute()]
public EntityReference<MakaleGrup> MakaleGrupReference
{
get
{
return ((IEntityWithRelationships)this).RelationshipManager.GetRelatedReference<MakaleGrup>("KarayelModel.FK_Makale_Categories", "MakaleGrup");
}
set
{
if ((value != null))
{
((IEntityWithRelationships)this).RelationshipManager.InitializeRelatedReference<MakaleGrup>("KarayelModel.FK_Makale_Categories", "MakaleGrup", value);
}
}
}
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[XmlIgnoreAttribute()]
[SoapIgnoreAttribute()]
[DataMemberAttribute()]
[EdmRelationshipNavigationPropertyAttribute("KarayelModel", "FK_MakaleYorumlari_Makaleler", "MakaleYorumlari")]
public EntityCollection<MakaleYorumlari> MakaleYorumlaris
{
get
{
return ((IEntityWithRelationships)this).RelationshipManager.GetRelatedCollection<MakaleYorumlari>("KarayelModel.FK_MakaleYorumlari_Makaleler", "MakaleYorumlari");
}
set
{
if ((value != null))
{
((IEntityWithRelationships)this).RelationshipManager.InitializeRelatedCollection<MakaleYorumlari>("KarayelModel.FK_MakaleYorumlari_Makaleler", "MakaleYorumlari", value);
}
}
}
#endregion
}
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[EdmEntityTypeAttribute(NamespaceName="KarayelModel", Name="MakaleYorumlari")]
[Serializable()]
[DataContractAttribute(IsReference=true)]
public partial class MakaleYorumlari : EntityObject
{
#region Factory Method
/// <summary>
/// Create a new MakaleYorumlari object.
/// </summary>
/// <param name="makaleYorumID">Initial value of the MakaleYorumID property.</param>
/// <param name="eklemeTarihi">Initial value of the EklemeTarihi property.</param>
/// <param name="ekleyen">Initial value of the Ekleyen property.</param>
/// <param name="ekleyenEmail">Initial value of the EkleyenEmail property.</param>
/// <param name="ekleyenIP">Initial value of the EkleyenIP property.</param>
/// <param name="refMakaleID">Initial value of the RefMakaleID property.</param>
/// <param name="icerik">Initial value of the Icerik property.</param>
public static MakaleYorumlari CreateMakaleYorumlari(global::System.Int32 makaleYorumID, global::System.DateTime eklemeTarihi, global::System.String ekleyen, global::System.String ekleyenEmail, global::System.String ekleyenIP, global::System.Int32 refMakaleID, global::System.String icerik)
{
MakaleYorumlari makaleYorumlari = new MakaleYorumlari();
makaleYorumlari.MakaleYorumID = makaleYorumID;
makaleYorumlari.EklemeTarihi = eklemeTarihi;
makaleYorumlari.Ekleyen = ekleyen;
makaleYorumlari.EkleyenEmail = ekleyenEmail;
makaleYorumlari.EkleyenIP = ekleyenIP;
makaleYorumlari.RefMakaleID = refMakaleID;
makaleYorumlari.Icerik = icerik;
return makaleYorumlari;
}
#endregion
#region Primitive Properties
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[EdmScalarPropertyAttribute(EntityKeyProperty=true, IsNullable=false)]
[DataMemberAttribute()]
public global::System.Int32 MakaleYorumID
{
get
{
return _MakaleYorumID;
}
set
{
if (_MakaleYorumID != value)
{
OnMakaleYorumIDChanging(value);
ReportPropertyChanging("MakaleYorumID");
_MakaleYorumID = StructuralObject.SetValidValue(value);
ReportPropertyChanged("MakaleYorumID");
OnMakaleYorumIDChanged();
}
}
}
private global::System.Int32 _MakaleYorumID;
partial void OnMakaleYorumIDChanging(global::System.Int32 value);
partial void OnMakaleYorumIDChanged();
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
[DataMemberAttribute()]
public global::System.DateTime EklemeTarihi
{
get
{
return _EklemeTarihi;
}
set
{
OnEklemeTarihiChanging(value);
ReportPropertyChanging("EklemeTarihi");
_EklemeTarihi = StructuralObject.SetValidValue(value);
ReportPropertyChanged("EklemeTarihi");
OnEklemeTarihiChanged();
}
}
private global::System.DateTime _EklemeTarihi;
partial void OnEklemeTarihiChanging(global::System.DateTime value);
partial void OnEklemeTarihiChanged();
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
[DataMemberAttribute()]
public global::System.String Ekleyen
{
get
{
return _Ekleyen;
}
set
{
OnEkleyenChanging(value);
ReportPropertyChanging("Ekleyen");
_Ekleyen = StructuralObject.SetValidValue(value, false);
ReportPropertyChanged("Ekleyen");
OnEkleyenChanged();
}
}
private global::System.String _Ekleyen;
partial void OnEkleyenChanging(global::System.String value);
partial void OnEkleyenChanged();
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
[DataMemberAttribute()]
public global::System.String EkleyenEmail
{
get
{
return _EkleyenEmail;
}
set
{
OnEkleyenEmailChanging(value);
ReportPropertyChanging("EkleyenEmail");
_EkleyenEmail = StructuralObject.SetValidValue(value, false);
ReportPropertyChanged("EkleyenEmail");
OnEkleyenEmailChanged();
}
}
private global::System.String _EkleyenEmail;
partial void OnEkleyenEmailChanging(global::System.String value);
partial void OnEkleyenEmailChanged();
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
[DataMemberAttribute()]
public global::System.String EkleyenIP
{
get
{
return _EkleyenIP;
}
set
{
OnEkleyenIPChanging(value);
ReportPropertyChanging("EkleyenIP");
_EkleyenIP = StructuralObject.SetValidValue(value, false);
ReportPropertyChanged("EkleyenIP");
OnEkleyenIPChanged();
}
}
private global::System.String _EkleyenIP;
partial void OnEkleyenIPChanging(global::System.String value);
partial void OnEkleyenIPChanged();
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
[DataMemberAttribute()]
public global::System.Int32 RefMakaleID
{
get
{
return _RefMakaleID;
}
set
{
OnRefMakaleIDChanging(value);
ReportPropertyChanging("RefMakaleID");
_RefMakaleID = StructuralObject.SetValidValue(value);
ReportPropertyChanged("RefMakaleID");
OnRefMakaleIDChanged();
}
}
private global::System.Int32 _RefMakaleID;
partial void OnRefMakaleIDChanging(global::System.Int32 value);
partial void OnRefMakaleIDChanged();
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
[DataMemberAttribute()]
public global::System.String Icerik
{
get
{
return _Icerik;
}
set
{
OnIcerikChanging(value);
ReportPropertyChanging("Icerik");
_Icerik = StructuralObject.SetValidValue(value, false);
ReportPropertyChanged("Icerik");
OnIcerikChanged();
}
}
private global::System.String _Icerik;
partial void OnIcerikChanging(global::System.String value);
partial void OnIcerikChanged();
#endregion
#region Navigation Properties
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[XmlIgnoreAttribute()]
[SoapIgnoreAttribute()]
[DataMemberAttribute()]
[EdmRelationshipNavigationPropertyAttribute("KarayelModel", "FK_MakaleYorumlari_Makaleler", "Makaleler")]
public Makaleler Makaleler
{
get
{
return ((IEntityWithRelationships)this).RelationshipManager.GetRelatedReference<Makaleler>("KarayelModel.FK_MakaleYorumlari_Makaleler", "Makaleler").Value;
}
set
{
((IEntityWithRelationships)this).RelationshipManager.GetRelatedReference<Makaleler>("KarayelModel.FK_MakaleYorumlari_Makaleler", "Makaleler").Value = value;
}
}
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[BrowsableAttribute(false)]
[DataMemberAttribute()]
public EntityReference<Makaleler> MakalelerReference
{
get
{
return ((IEntityWithRelationships)this).RelationshipManager.GetRelatedReference<Makaleler>("KarayelModel.FK_MakaleYorumlari_Makaleler", "Makaleler");
}
set
{
if ((value != null))
{
((IEntityWithRelationships)this).RelationshipManager.InitializeRelatedReference<Makaleler>("KarayelModel.FK_MakaleYorumlari_Makaleler", "Makaleler", value);
}
}
}
#endregion
}
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[EdmEntityTypeAttribute(NamespaceName="KarayelModel", Name="Ulke")]
[Serializable()]
[DataContractAttribute(IsReference=true)]
public partial class Ulke : EntityObject
{
#region Factory Method
/// <summary>
/// Create a new Ulke object.
/// </summary>
/// <param name="ulkeID">Initial value of the UlkeID property.</param>
/// <param name="ulkeAdi">Initial value of the UlkeAdi property.</param>
public static Ulke CreateUlke(global::System.Guid ulkeID, global::System.String ulkeAdi)
{
Ulke ulke = new Ulke();
ulke.UlkeID = ulkeID;
ulke.UlkeAdi = ulkeAdi;
return ulke;
}
#endregion
#region Primitive Properties
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[EdmScalarPropertyAttribute(EntityKeyProperty=true, IsNullable=false)]
[DataMemberAttribute()]
public global::System.Guid UlkeID
{
get
{
return _UlkeID;
}
set
{
if (_UlkeID != value)
{
OnUlkeIDChanging(value);
ReportPropertyChanging("UlkeID");
_UlkeID = StructuralObject.SetValidValue(value);
ReportPropertyChanged("UlkeID");
OnUlkeIDChanged();
}
}
}
private global::System.Guid _UlkeID;
partial void OnUlkeIDChanging(global::System.Guid value);
partial void OnUlkeIDChanged();
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[EdmScalarPropertyAttribute(EntityKeyProperty=true, IsNullable=false)]
[DataMemberAttribute()]
public global::System.String UlkeAdi
{
get
{
return _UlkeAdi;
}
set
{
if (_UlkeAdi != value)
{
OnUlkeAdiChanging(value);
ReportPropertyChanging("UlkeAdi");
_UlkeAdi = StructuralObject.SetValidValue(value, false);
ReportPropertyChanged("UlkeAdi");
OnUlkeAdiChanged();
}
}
}
private global::System.String _UlkeAdi;
partial void OnUlkeAdiChanging(global::System.String value);
partial void OnUlkeAdiChanged();
#endregion
}
#endregion
}

Yukarıdaki sınıf bize özel metot oluşturabilme imkanı sağlamıştır. Bu sayade bir metot oluşturup o metot üzerinde veri tabanında değişiklik yapabilmekteyiz. Ayrıca veri tabanında yapılan değişiklikleri kontrol edebilir. Bu değişiklikler oluşumuna bağlı olarak istediğimiz metotlar çalıştırabilmemizi sağlamaktadır.

Partial metotlar c# 3.0 ile gelen bir özelliktir. Bu partial metotlar tıpkı sanal methodlar gibi çok basit çalışırlar. Ancak partial metodu oluştururken dikkat edilmesi gereken birkaç husus vardır.
  • Eğer partial metot tanımlanmadan oluşturulursa çalışmaz.
  • Eğer bir sanal bir metotdunuz varsa action metodunuzun isimlendirdiğinizden emin olmalısınız.

Bizim projemizde gerekl, olan birkaç partial metot aşağıdaki gibidir.

partial void OnUlkeIDChanging(global::System.Guid value);

partial void OnUlkeIDChanged();

partial void OnEklemeTarihiChanging(global::System.DateTime value);

partial void OnEklemeTarihiChanged();

Partial metotlar veritabanındaki her bir sütun için yazılır. Bu metotlar veri tabanında istenen değişiklik her olduğunda otamatik olarak çağrılmaktadır.

Dahili LINQ Nesneleri

Makale modulü için ihtiyaç duyulan Linq nesneleri EDMX den sırasıyla projeye eklenmelidir. Bu dahil edilen özellikler ve metotlar controller içindeki action metotlardan ve view'lerde yazılanları kaydetmeyi sağlamaktadır.

Daha öncede yaptığımız gibi ~Models klasöründe yer alan KarayelDb.edmx dosyası gerekli olan partial sınıflarını eklemeniz gerekmektedir

Makale Sınıfı

Bu sınıf ~/Models/Makale.cs içinde yer almaktadır. Bu sınıf partial olarak oluşturulmuş bir sınıfdır ve belirtilen veritananı tablosu ile aynı isimde olmalıdır. Projen derlendiği andan itibaren bu sınıfta veri tabanından gelen veriler toplanarak bu veriler üzerinde işlem yapabilmemizi sağlamaktadır. Böylelikle veri tabanına ekstradan yük oluşturmadan istediğimiz verileri üzerinde değişiklik yaparak controller'a veya view gönderebilmemizi sağlamaktadır

public partial class Makaleler

{

}

Bu sınıfta bir çok hesaplama ve okuma işlemleri yapılabilmektedir. Location metodu makaleler tablosunda bulunan tüm location değerlerini alarak onlar üzerinde işlem yaparak döndürmemizi sağlamaktadır. Örneğin makaler tablosundan aldığı alanları birleştirerek view gerekli olan konum bilgisi için yeni bir alan o oluşturulmuş olur. Böylelikle veritabanında fazladan bir alan daha oluşturmamış oluruz. Location ile ilgili partial sınıf metodumuz aşağıdaki gibidir.

public string Location
{
get
{
string sehir = this.Sehir ?? String.Empty;
string ilce = this.Ilce ?? String.Empty;
string ulke = this.Ulke?? String.Empty;
string konum = sehir.Split(';')[0];
if (ilce.Length > 0)
{
if (konum.Length > 0)
konum += ", ";
konum += ilce.Split(';')[0];
}
if (ulke.Length > 0)
{
if (konum.Length > 0)
konum += ", ";
konum += ulke.Split(';')[0];
}
return konum;
}
}

Bir diğer metodumuz ise makale oran hesapla metodumuzdur. Bölğnme işleminin olup olmadığını kontrol eder. Eğer bölünme olmadıysa DivideByZeroException hatası verir ve geriye sıfır(0) döndürür.

public double OrtalamaOran
{
get
{
if (this.Oy >= 1)
return ((double)this.ToplamOran/ (double)this.Oy);
else
return 0D;
}
}

Diğer bir metodumuz ise yayınlama özelliği üzeride işlem yapılan metottur. Eğer makale onaylanmışsa ve belirtilen tariharasında ise true döndürür.

public bool YayinlanmaAraligi
{
get
{
return (this.Onay && this.YayinTarihi <= DateTime.Now && this.YayinSonu> DateTime.Now);
}
}
Bu metot rate metoduna sahiptir ancakview kısmındada buna benzer bir metot bulunmaktadır.
public void OkunmaSayisiniArtir()
{
OkunmaSayisi++;
}
public void Oranla(int oran)
{
Oy++;
ToplamOran+= oran;
}

Yorum sınıfı

Yorum sınıfıda makakale sınıfı gibi ~/Models/Yorum.cs içinde konumlandırılır. Bu sınıfta makale sınıfı gibi partial bir sınıf olarak tanımlandırılabilir. aslında yapı olarak makale sınıfı ile tamamen aynıdır.

public partial class Makale
{

}

EncodedBody özelliğini kullanabilmek için öncelikle yorum sınıfı eklemelidir. Html'de encode çok önemlidir. Çünkü güvenliği sağlamaktadır. Bir örnekle açıklamak gerekirse;
Saldırganlar sitede herhangi bir makalenin altına eğer script kodunu yerleştirirse ve bunu siteye post ederse o siteye ait olan tüm özel bilgilere ulaşabilir. EncodedBody bu tip saldırılardan sitenizi güvenli bir şekilde koruyabilmektedir.

public string EncodedBody
{
get { return HttpContext.Current.Server.HtmlEncode(Body); }
}

Sayfaalandırma düzeninin oluşturulması

Bir projede kullanıcılar tarafından bir çok şekilde sayfalandırma yapılabilir. Burada sayfalandırma için iki temel tür vardır. Bunlardan ilk olanı birçok blog yazılımlarında olduğu gibi ileri veya geri yaparak sayfa atlanabilen sayfalandırma diğeri ise doğrusal olmayan sayfalandırma ki bu kullanıcıya belirli bir aralıkta atlayabilme olanağı tanımaktadır(Google arama motoruna ait sayfalandırma yapısı gibi). İkinci yöntemi kullanmak daha avantajlıdır. Çünkü kullanıcıya sayfalar arası esneklik tanımaktadır. Bu yüzden bizde projenizde ikinci yöntemi kullanmanız tavsiye edilmektedir.

Bu sayfalandırma yapısını az bir bilgiyle kolaylıkla anlayabilirsiniz. Öncelikle bu sayfalandırmaya başlarken veri tabanından tüm veriler çekilerek her sayfada kaç tane veri gösterileceğine karar verilmeli. Daha sonra toplam veri sayısı bulunmalı ve her sayfada gösterileek eleman sayısına bölünmelidir. Eğer sonuç küsuratlı çıkarsa o sayı bir üstündeki sayıya yuvarlanarak toplam sayfa sayısı bulunabilir.

Sayfalandırma işlemleri yürütebileceğimiz için bu kodları içine yazacağımız pagination<T> adı ile isimlendireceğimiz sınıf oluşturulmalıdır. Bu sınıf ihtiyacımız olan gerekli değişkenleri içine otamatik olarak oluşturduğundan işimiz oldukça kolay olacaktır.

Bu özellikler TotalCount,RequestedCount, StartIndex, PageIndex, and PageCount. PageIndex ve PageCount bu özelliklerin ilk üçü hesaplama yapmamızı sağlamaktadır. Ayrıca bu sınıf diğer modellerin yanına ~/Models/Pagination.cs, oluşturmalıdır çünkü pagination bir kaç parça model sorgusuyla birlikte çalışmaktadır.

public class Pagination<T> : IEnumerable<T>, IPagination
{
private IEnumerable<T> _collection;
public Pagination(
IEnumerable<T> collection,
int startIndex,
int requestedCount,
int totalCount
) {
_collection = collection;
StartIndex = startIndex;
PageSize = requestedCount;
TotalCount = totalCount;
}
public virtual int TotalCount { get; protected internal set; }
public virtual int PageSize { get; protected internal set; }
public virtual int StartIndex { get; protected internal set; }
public virtual int PageNumber
{
get { return (StartIndex / PageSize) + 1; }
}
public virtual int PageCount
{
get {
return (int)Math.Ceiling(
(double)TotalCount / (double)RequestedCount);
}
}
#region IEnumerable<T> Members
public IEnumerator<T> GetEnumerator()
{
return _collection.GetEnumerator();
}
#endregion
#region IEnumerable Members
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
#endregion
}

Sizde dikkat etmişsinizdir ki tanımlamalar için aşağıdaki kod parçacığını kullanmadık.{get; private set;}Bu sintax c#3.0 ile gelen yeni bir özelliktir derleyici bu tür bir tanımnlama gördüğünde gönderme ve alma için gerekli olan tanımnlamaları ototmatik olarak yapmaktadır. Biz bu sintax'ı birden çok yerde defalarca kullanabilriz tıpkı Pagination<T> da olduğu gibi.

Makalelerin Görüntülerini Sağlamak

Makalelerin görüntülerini elde etmeden önce veri tabanında çekilen veriler bir yerde tutulmalıdır. Bu yer ise sarmalama ( wrapper ) işlemidir. Wrapper makalelerin başarılı bir şekilde görüntülenmesi için mevcut olan kullanıcıyı ve yetkisini kotrol eder. Wrapper ise son olarak görüntüleri html kısmına gönderir. Bu şekilde veri gönderim biçimi çok önemlidir. Çünkü yetki modeli çok karmaşıktır ve veri tabanından kolaylıkla veri çekilememektedir. İleriki bölümlerde size transparent collection enumerator gücünü göstermek ve nasıl kullandığını anlatılacaktır.

Transparent collection enumerator(paket koleksiyon sayıcısı) için temel kelime yield anahtar kelimesidir. .Bu anahtar kelime sadece yineleyici (tekrar edici) bloglarda çok kullanılır. Ayrıca yinelemenin sonunda bir değer sağlamak için kullnılır.yield return <expression>;yield break;

The Transparent Collection Enumerator

The transparent collection enumerator MakaleCollectionWrapper dan çağrılır ve diğer modeller ile birlikte ~/Models/MakaleCollectionWrapper.cs. de yer alır. MakaleCollectionWrapper hangi makalenin nesnesinde tanımlandıysa oraya yerleştirilecektir.

namespace KarayelTasarim.Models
{
>
internal class MakaleCollectionWrapper : IEnumerable<Makaleler>
{
private IEnumerable<Makaleler> _makaleler;
public MakaleCollectionWrapper(IEnumerable<Makaleler> makaleler)
{
_makaleler = makaleler;
}
#region IEnumerable<Makaleler> Uyeler
/// </returns>
public IEnumerator<Makaleler> GetEnumerator()
{
bool isAuthenticated = false;
HttpContext context = HttpContext.Current;
if (context.User != null && context.User.Identity != null)
isAuthenticated = context.User.Identity.IsAuthenticated;
foreach (Makaleler makaleler in _makaleler)
{
if (makaleler.YalnizcaUyeler && !isAuthenticated)
continue;
yield return makaleler;
}
}
#endregion
#region IEnumerable Members
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
#endregion
}
}

Kodun bu kısmı çok önemlidir. Dikkat ettiğniz üzere eğer güncel makaleler yalnızca üyeler için ise ve mevcut olan kullanıcıların o makaleyi okumaya yetkisi yok ise bu nesne yield olarak döndürülmemiş bir sonraki makaleye atlamış demektir

Bunun yanında MakaleCollectionWrapper ı bir dahil sınıf gibi oluştururuz çünkü o paket, ambalaj kurgunun dısındadır. Bu wrapper sorgudan döndüğünde IEnumerator<Makaleler>, den dönecektir çünkü IEnumerator<Makaleler> bu sınıfın yerleştirilmiş olan bir arayüzdür.

LINQ to Entity Framework Sorgularının Oluşturulması

Model ayarlamalarında bir sonraki adım ise sorguların oluşturulmasıdır. Bu sorgular contorolerden çağrılmaktadır. Analiz kısmındada bahsettiğimniz gibi sorgular genişletilmiş metodarda bulnur. Eğer metotlar sınıf içierisinde tasarlanmış ve hazrılanmış ise bu bize doğal olarak onları çağıra bilme imkanını sağlamaktadır.

Oluşturacağımız projenin amlaşılabilir olamsı için oluşturulan sınıfların isimlerini açıklayıcı nitelik taşımasına dikkat edilmelidir. bu yüzden sorguların bulunacağı sınıfın ismi uygun olara makalesorgulari.cs denilmelidir. Bu sınıf static bir sınıf olmalıdır. Böylelikle tüm metotlar static özellikte olur.

GetirYayinlanmisMakaleleri Sorgusu

GetirYayinlanmisMakaleleri Sorgusundan altıncı bölümün analiz kısmında söz etmiştik. Aşağıdaki kodlar analiz kısmından yazan kurallara göre oluşturulmuştur. Bu sorguya parametre olarak gelen makalegrub değişkeni hangi makale grubuna ait olan makalelerin döndürüleceğine karar vermektedir. GetirYayinlanmisMakaleleri sorgu yapısı aşağıdaki gibidir.

private static IEnumerable<Makaleler> GetirYayinlanmisMakaleleri(IEnumerable<Makaleler> dataContext, string makaleGrup)
{
// makale grubu boş ise null değer ver değilse değer aynen kalsın
makaleGrup = String.IsNullOrEmpty(makaleGrup) ? null : makaleGrup;
bool isAuthenticated = false;
HttpContext context = HttpContext.Current;
if (context.User != null && context.User.Identity != null)
isAuthenticated = context.User.Identity.IsAuthenticated;
var query = from a in dataContext //.ToArray() 07.10.10 //.Makalelers
orderby a.YayinTarihi descending
where a.Onay == true
&& a.ListeOnay == true
&& (isAuthenticated == true || a.YalnizcaUyeler== false)
&& a.YayinTarihi <= DateTime.Now
&& (a.YayinSonu == null || a.YayinSonu> DateTime.Now)
&& (makaleGrup == null || a.MakaleGrup.Yolu== makaleGrup)
select a;
return query;
}

Bu linq to entity framework sorguları kolaydır. Ancak dikkat edilmesi gerekn birkaç husus bulunmaktadır.

Bir sonraki sorguda bir önceki sorgununun overload edilmiş halidir.

public static Pagination<Makaleler> GetirYayinlanmisMakaleleri(this IEnumerable<Makaleler> kaynakTablo, string makaleGrup, int page)
{
int count = Configuration.KarayelTasarimSection.Current.Makaleler.PageSize;
int index = (page - 1) * count;
return new Pagination<Makaleler>( //GetirYayinlanmisMakaleleri(kaynakTablo as KarayelEntities
new MakaleCollectionWrapper(GetirYayinlanmisMakaleleri(kaynakTablo, makaleGrup).Skip(index).Take(count)),
index,
count,
GetirYayinlanmisMakaleleSayisi(kaynakTablo, makaleGrup)
);
}

Muhtemelen skip ve take methodlarının GetirYayinlanmisMakaleleri methodunda kullanıldığını farketmişsindir. Bu Linq to Entity framework'de sayfalandırmanın yoludur. Bu sorgu yapısı oldukça basittir; Gerekli olan sorgu her neyse o yazılmalır bu sayade istenen veri veritabanından çekilebilmektedir.

Son sorgu ise makalelerin yayınlanması ve tekrar gözden geçirilmesini sağlamaktadır. Bu metot makalelerin anasayfada sayfalandırılmış bir şekilde gösterilmesini sağlamaktadır. Ve içeriği aşağıdaki gibidir.

public static Pagination<Makaleler> GetirYayinlanmisMakaleleri(this IEnumerable<Makaleler> kaynakTablo, int page)
{
int count = 10;//Configuration.KarayelTasarimSection.Current.Makaleler.PageSize;
int index = (page - 1) * count;
return new Pagination<Makaleler>( //GetirYayinlanmisMakaleleri(kaynakTablo as KarayelEntities.......
new MakaleCollectionWrapper(GetirYayinlanmisMakaleleri(kaynakTablo, null).Skip(index).Take(count)),
index,
count,
GetirYayinlanmisMakaleleSayisi(kaynakTablo)
);
}

GetirYayinlanmisMakaleleSayisi Sorgusu

Bu sorgu yayınlanmış makalerin sayısını bize döndürmektedir. Bu sorgu bizim için önemli bir sorgudur. Çünkü veri tabanındaki makalelerin sayısını bilmiyorsanız, yayınlanacak sayfanını büyüklğüğü ve sayfa sayısı hakkında hiçbir fikrin olmayacaktır.

Bu ilk metot bize belirli bir makale grubuna ait yayınlanmış makalelerin sayısını döndürmektedir.

public static int GetirYayinlanmisMakaleleSayisi(this IEnumerable<Makaleler> kaynakTablo, string makaleGrup)

{

//GetirYayinlanmisMakaleleri(kaynakTablo as KarayelEntities

return GetirYayinlanmisMakaleleri(kaynakTablo, makaleGrup).Count();

}

Bu metot ise veri tabanındaki tüm yayınlanmış makalelerin sayısını döndürmektedir.

public static int GetirYayinlanmisMakaleleSayisi(this IEnumerable<Makaleler> source)

{

// GetirYayinlanmisMakaleleri(source as KarayelEntities

return GetirYayinlanmisMakaleleri(source, null).Count();

}

GetirMakaleler Sorgusu

Bu kod makaleleri yayınlanma tarihlerine göre sıralayarak bize döndürür. Bu metot MakaleYonet.cshtml sayfasında kullanılır.

private static IEnumerable<Makaleler> GetirMakaleler(this IEnumerable<Makaleler> dataContext, string makaleGrup)
// makale grubu boş ise null değer ver değilse değer aynen kalsın
makaleGrup = String.IsNullOrEmpty(makaleGrup) ? null : makaleGrup;
var query = from a in dataContext //.Makalelers
orderby a.YayinTarihi descending
where makaleGrup == null || a.MakaleGrup.Yolu== makaleGrup
select a;
return query;
}

Bu sorgu ise önceki sorgu ile aynı isme sahip olup overload edilmiş bir halidir. Bu sorgunun amacı makale grubu ve sayfası belli olan makaleleri bulup döndürmeyi saplamaktadır.

public static Pagination<Makaleler> GetirYayinlanmisMakaleleri(this IEnumerable<Makaleler> kaynakTablo, string makaleGrup, int page)
{
int count = Configuration.KarayelTasarimSection.Current.Makaleler.PageSize;
int index = (page - 1) * count;
return new Pagination<Makaleler>( //GetirYayinlanmisMakaleleri(kaynakTablo as KarayelEntities
new MakaleCollectionWrapper(GetirYayinlanmisMakaleleri(kaynakTablo, makaleGrup).Skip(index).Take(count)),
index,
count,
GetirYayinlanmisMakaleleSayisi(kaynakTablo, makaleGrup)
);
}

Son olarak aşağıdaki sorgusunun amacı ise bütün makale grubuna ait makaleleri döndürmektedir. Bu sorgu MakaleYonet .cshtml sayfasında kullanılmaktadır. Ancak makaler birçok olacağından sayfalandırmaya gidilmiştir.

public static Pagination<Makaleler> GetirMakaleler(this IEnumerable<Makaleler> kaynakTablo, int page)
{
int count = Configuration.KarayelTasarimSection.Current.Makaleler.PageSize;
int index = (page - 1) * count;
return new Pagination<Makaleler>(
new MakaleCollectionWrapper(
GetirMakaleler(
kaynakTablo,
null
).Skip(index).Take(count)),
index,
count,
GetirMakaleSayisilari(kaynakTablo)
);
}

GetirMakaleSayisi Sorgusu

Bu sorgu yönetici view'ında sadece yöneticini görebileceği makalelerin sayısını döndürmektedir. Belirli nir makale grubundaki makalelerin sayısını döndürmektedir

public static Pagination<Makaleler> GetirMakaleler(this IEnumerable<Makaleler> kaynakTablo, string makaleGrup, int page)
{
int count = Configuration.KarayelTasarimSection.Current.Makaleler.PageSize;
int index = (page - 1) * count;
return new Pagination<Makaleler>(
new MakaleCollectionWrapper(GetirMakaleler(kaynakTablo, makaleGrup).Skip(index).Take(count)),
index,
count,
GetirMakaleSayisi(kaynakTablo, makaleGrup)
);
}

Bu ikinci sorgu da veri tabanın kayıtlı olan tüm makalelerin sayısını verir

public static int GetirYayinlanmisMakaleleSayisi(this IEnumerable<Makaleler> kaynakTablo, string makaleGrup)
{
//GetirYayinlanmisMakaleleri(kaynakTablo as KarayelEntities
return GetirYayinlanmisMakaleleri(kaynakTablo, makaleGrup).Count();
}

GetirMakale Sorgusu

Bu sorgu id'si bilinen makaleyi göndürür. Bu sorgu belirtilen makaleyi düzenlemek için veya görüntülemek için kullanılmaktadır.

public static MakaleYorumlari GetirMakaleYorumlari(this IEnumerable<MakaleYorumlari> kaynakTablo, int id)
{
return kaynakTablo.SingleOrDefault(c => c.MakaleYorumID == id);
}

Bu sorguda henüz daha görmesekte SingleOrDefault metodunu kullanılır. Bu metot sayesinde veritabanında oluşabilecek bir hatadan kurtulmuş oluruz. Şöyleki ; Eğer sorgu veri tabanından istenen makaleye ulaşamaz ise bize örnek bir makale döndürmektedir.

GetirMakaleGrup Sorgusu

Bu sorgu tüm katogori leri başlık ve önem sırasına göre sıralar. Bu prosedürün amacı

o tüm kategorileri getirse bile senin ihtiyacın olan iş kurallarına göre sıralar.

public static IEnumerable<MakaleGrup> GetirMakaleGruplari(this IEnumerable<MakaleGrup> kaynakTablo)
{
return from c in kaynakTablo
orderby c.Onemi, c.Baslik
select c;
}

MakaleGrubuMevcutmu Sorgusu

Bu sorgu ID yi doğrulamak için kullanılır böylelikle Id'ye göre makalegrubu olup olmadığını kontrol etmek etmektedir. Bu sorgu makale grubu silerken veya güncellerken kullanılmaktadır.

public static bool MakaleGrubuMevcutmu(this IEnumerable<MakaleGrup> kaynakTablo, int id)
{
return kaynakTablo.Count(c => c.MakaleGrupID == id) > 0;
}

MakaleGrubu Sorgusu

Bu sorgu istenen kimliğe göre tek bir makale grubu getirir. Bu sorgu bir makale grubunu yönetmek için kullanılmaktadır.

public static MakaleGrup GetirMakaleGrup(this IEnumerable<MakaleGrup> kaynakTablo, int id)//tek bir tane makale okumak için
{
return kaynakTablo.SingleOrDefault(a => a.MakaleGrupID== id);
}

GetirYorumYonetimIcin Sorgusu

Bu sorgu yorumları en son yazılan dan ilk yazılana göre sıralar. Bu sorgu yalnızca yönetici tarafından kullanılabilir.

public static Pagination<MakaleYorumlari> GetirYorumYonetimIcin(this IEnumerable<MakaleYorumlari> kaynakTablo, int page)
{
int count = Configuration.KarayelTasarimSection.Current.Makaleler.PageSize;
int index = (page - 1) * count;
var query = from c in kaynakTablo
orderby c.EklemeTarihi descending
select c;
return new Pagination<MakaleYorumlari>(
query.Skip(index).Take(count),
index,
count,
kaynakTablo.Count()
);
}

GetirMakaleYorumlari Sorgusu

Bu sorgu özel bir yorumu almak için kullanılmaktadır. Bu sorgu bundan önceki sorgularda olduğu gibi yine kimliğe(id) göre arama yapmaktadır.

public static MakaleYorumlari GetirMakaleYorumlari(this IEnumerable<MakaleYorumlari> kaynakTablo, int id)

{

return kaynakTablo.SingleOrDefault(c => c.MakaleYorumID == id);

}

Controller Uygulaması

Daha önceki bölümlerde bir controller nasıl oluşturulur. İçine bir action metodu nasıl yazılır ve yine bu action metoda ait olan view nasıl eklenir bunların hepsini öğrenmiştik. Bu yüzden bu bölümü anlamanız kolay olacaktır. Öncelikle action metotlarımızı içine yazacağımız makale adında bir controller oluşturulmalıdır. Controller içinde kullanılan action metotlar veritabanından veri çekmek için kullanılmaktadır. Ayrıca bu action metotlar kendi viewleri ile bağlantılıdır. Daha doğrusu Model katmanı ve View katmanı arasında bağlayıcı nitelik taşımaktadır. Bu yüzden controller'a genel anlamda haritalama denilmektedir.

Index Action

Bu controlller için ilk action metodumuz olan Index action'ımız yayınlanan makaleleri gösterebilmemiz için kullanılmaktadır. Bu zction metodumuz MakaleGrup ve page adında iki tane değişken almaktadır.

public ActionResult Index(string makaleGrup, int page)
{
KarayelEntities dc = new KarayelEntities();
var viewData = dc.Makalelers.GetirYayinlanmisMakaleleri(makaleGrup, page);
var viewCategory = dc.MakaleGrups.GetirMakaleGrup(makaleGrup);
ViewData["MakaleGruplari"] = dc.MakaleGrups.GetirMakaleGruplari();
ViewData["SayfaBaslik"] = (viewCategory != null ? viewCategory.Baslik: "Tüm") + " Makaleler";
return View(viewData);
}

Altıncı bölümde analiz kısmında ihtiyacımız olan route'ları tanımlamıştık. Genel itibariyle ihtiyacımız olan bazı route'lar aşağıdaki gibidir.

  1. anasayfa
  2. makaleler/page{page}
  3. makalele/makalegrup/{makalegurp}
  4. makalele/makalegrup/{makalegurp}/page/{page}

Action ve controller için tanımlanan global.asax dosyasının içinde yer almaktadır. Yukarıda tanımlanan bu dört yöne action metotları kullanabilmek için ihtiyacımız vardır.

Anasayfa

Bu route anasayfa için tanımlanmıştır. Anasayfa diğer sayfalardan farklı ve kendine has durumları bulunmaktadır. Bu özel durumun oluşmasının sebebi ise;

Örneğin sitenize ilk defa giriş yapan bir kullanıcının karşısına anasayfa view'ı gelecektir. Ancak anasayfa kullanıcıya sayfa içerisinde herhangi bir yere tıklamadan gelecektir. Dolayısıyla url kısmında da anasayfa kısmı gözükmeyecektir. Bu yüzden global.asax dosyasının içeriside yer alan Route map biraz daha farklı olacaktır. Global asax içinde yer alan tüm route'ların arasında en zor olan kısım burasıdır. Bu yeri anladıkten sonra diğer tüm route anlamanız kolay olacaktır.

Öncelikle sitemizin anasayfasında nelerin göstereceğimiz kararlaştırılmalıdır. Mesela yayınlanmış makaleler gösterilebilir fakat bu yayınlanmış makaleleri hangisininde gösterileceğine karar verilemelidir. Çünkü yayınlanmış bir çok makale olacağından sitemize gelen kullanıcı daha önce gördüğü bir makaleyi, görmek istemez Dolayısıyla buradaki makaleler herzaman en yeni olanlar seçilmelidir. Aşağıdaki tanımlamalarda default olarak ayarlamalar yapılmıştır.

routes.MapRoute(
"MakaleIndex",
"makaleler",
new { controller = "Makale",
action = "Index",
makaleGrup = (string)null,
page = 1
}
);

Yukarıda ki route anonim kullanıcılar için tanımlanmıştır. Bu route makale controller içinde Index action'ını işaret etmektedir. Anonim kullanıcılar için default ayarlamalar yapılmıştır. Ayrıca Index action fonksiyonuna iki parametre aldığı için makaleGrup(null) ve page(1) adında iki tane parametre gönderilmiştir.

makaleler/makaleGruplari/{makaleGrup}/page{page}

Bu route yayınlanmış olan sayfa ve makalegrubu olan makaleler için tanımlanmıştır.

routes.MapRoute(
"MakaleGrupGoruntuleIndexPaged",
"makaleler/makaleGruplari/{makaleGrup}/page{page}",
new {
controller = "Makale",
action = "Index",
makaleGrup =(string)null,
page = (int?)null
},
new {
makaleGrup = "[a-zA-Z0-9\\-]+",
page = "[0-9]+"
}
);

Bu route'ta parametreler default olarak null'a kurulur. Bu yüzden Action metodunuzu iyi ayarlamak gerekmektedir.Yukarıdaki route'ta daha önce görmediğiniz bir new özelliği yer almaktadır. Bu yukarıda yazan ikinci new'in içerisindeki anlamsız gibi görüne ifadeler aslında bir koşullayıcıdır. Şöyleki (makaleGrup="[a-zA-Z0-9\\-]+) yazan kısım makeleGrubu badlı değişkenin alabileceği karakter çeşitlilliklerini gösterir. Örneğin makaleGrub değişkeni A'dan Z' ye, a'dan z'ye, 0ve 9 arası tüm sayıları, tire(-) ve artı(+) dahil olmak üzere sadece bu karakterlerin oluşturduğu tüm kelimeleri değişken olarak kabul edebilmektedir. Mesala makaleGrup değişkenimiz üzerinde soru işareti gibi yukarıda belirtilmemiş herhangi bir karakter barındırırsa global.asax kısmında da hata olacaktır. Yine page değişkenimiz sadece 0 ve 9 arası rakamları ayrıca artı(+)karakterini içermelidir.

makaleler/makaleGruplari/{makaleGrup}

Bu route özel bir makaleGruba ait yayınlanmış makaleri göstermek için kullanılır.

routes.MapRoute(
"MakaleVeGrupGoruntuleIndex",
"makaleler/makaleGruplari/{makaleGrup}",
new { controller = "Makale",
action = "Index",
makaleGrup = (string)null,
page = 1 },
new { makaleGrup = "[a-zA-Z0-9\\-]+",
page = "[0-9]+" }
);

makaleler/page{page}

Bu route yayınlanmış olan sayfa ve makalegrubu olan makaleler için tanımlanmıştır.

routes.MapRoute(
"MakaleIndexPaged",
"makaleler/page{page}",
new { controller = "Makale",
action = "Index",
makaleGrup = (string)null,
page = (int?)null },
new { page = "[0-9]+" }
);

MakaleGrubIndex Aciton Metot

Bir sonraki actionımız olan MakaleGrupIndex metodumuz categorilerimizin listelenerek gösterilmesiniz sağlayan controller metodumudur.

public ActionResult MakaleGrupIndex()
{
KarayelEntities dc = new KarayelEntities();
var viewData = dc.MakaleGrups.GetirMakaleGruplari();
ViewData["SayfaBaslik"] = "Tüm Kategoriler";
return View(viewData);
}

Bu action gerekliolan route aşağıdaki gibidir.

routes.MapRoute(
"MakaleGrupSirala",
"makaleler/categories",
new { controller = "Makale", action = "MakaleGrupIndex" },
new { makaleGrup = "[a-zA-Z0-9\\-]+",page = "[0-9]+" }
);

MakaleGoruntule Action Metot

Projemiz içi öneml actionlardan birisidir. Bu action models klasöründe oluşturulan makale nesnesinden verileri alarak makale view'ında yayınlamak için kullanılmaktadır. Bu action daha önceki oluşturulan action metotlardan farklı olduğu için parça parça işlenerek anlatılmıştır.,
public ActionResult MakaleGoruntule(int id, string yol)

{

KarayelEntities dc = new KarayelEntities();

Makaleler viewData = dc.Makalelers.GetirMakale(id);

MakaleGoruntule action metodumuzun içinde yer alan yukarıdaki kod parçacığı actio metodun parametreleri arasında olan Id parametresine göre istenen makaleyi veri tabanından çekmeyi sağlamaktadır.

if (viewData == null)

throw new HttpException(404, "Makale bulunamıyor.");

Kodun bu kısmı ise istenen makalenin bulunamaması durumunda 404 hatayı kullanıcı sayfasına döndürmek için kullanılır(GetirMakale metodu null döndürdüğü zaman). Şöyleki bu hata oluşmasını kontrol etmek gerekmektdir. Çünkü web server üzerinde çalışan sitemizde böyle bir hata oluşursa sitem 404 hatayı gösterecektir. Ancak hiçbir kullanıcı böyle bir hatayı görmek istemez durum böyle oluncada oluşabilecek tüm hataları daha öncesinden kontrol etmek gerekektedir.
if (!String.Equals(yol, viewData.Yolu,StringComparison.OrdinalIgnoreCase))

return this.RedirectToAction(301, "View", new { id = viewData.MakaleID, path = viewData.Yolu})

Bu kısım güvenlik içindir. Url bölümünde yolun tam doğru bir şekilde gösterilmesini sağlamaktadır. Url bölümünde yolun doğru bir şekilde gösterilmesi SEO işlemleri için önemlidir. Çünkü tüm arama motorları aradığı konuyla ilgili baslığın Url bölmünde hiyerarşik bir şekilde gösteren sitelere öncelik vermektedir. Bu yüzden Url kısmının doğru olması önemlidir. Ancak burada dikkat edilmesi gerekeken bir diğer husus ise aynı içeriğe sahip farklı yollar yazmak doğru değildir. Çünkü aynı Id sahip olan makale birden çok yola sahip olacaktır. Bu kısımda yapılan böyle bir hata sitenizin Google tarafından banlanmasına sebebiyet vermektedir. Google arama motoru 2003 yılından beri aynı içeriğe bir çok konu açan siteleri bulup banlayabilmektedir.

Diğer önemli bir kısım ise karşımıza ilerde karşımıza çıkabilecek bir sorun için daha şimdiden önlem alınmalıdır. Yukarudaki kod öncelikle yolun makalenin gereçk yoluna eşit olup olmadığına kontrol eder. Eğer yol eşit değilse 301 url'ni aktarır.

if (viewData.YalnizcaUyeler&& HttpContext.User != null

&& HttpContext.User.Identity != null

&& !HttpContext.User.Identity.IsAuthenticated)

throw new HttpException(401, "Bu makale yalnızca üyeler tarafından okunabilir.");

Makaleleri sadece üyelerin okunmasını kontrol etmektedir. Eğer kullanıcı sitede ancak sitenin içinde log in değilse herhangi bir makaleleri okumak isterse öncelikle kullanıcı giriş sayfasına yönlendirilmelidir. Daha sonra sisteme giriş yapmış olan kullanıcın o makaleyi okuma yetkisi ve OnlyForMembers özelliği true olmalıdır. Eğer o kullanıcın bu özelliklerden herhangi biri eksik ise istemci tarayıcısına cevap niteliğinde 401 hatası göndermelidir ki kullanıcı tekrar giriş sayfasına yönlendirilsin.

try

{

viewData.OkunmaSayisi++;

dc.SaveChanges();

}

catch { /* tüm çakışmaları gözardı et, çok kritik değil*/ }

ViewData["SayfaBaslik"] = viewData.Baslik;

return View(viewData);

Yukarda ki ko d kısmı ise makale her okunduğunda makalenin o0kunma sayısını bir arttırmayı sağlamaktadır. Daha sonra ise makalenin okunma sayısı kullanıcıya döndürülmektedir. Bu action aşağıdaki gibi bir tane route'a sahiptir.

routes.MapRoute(

"GoruntuleMakale",

"makaleler/{id}/{*yol}",

new { controller = "Makale", action = "MakaleGoruntule", id = (string)null, yol = (string)null },

new { id = "[0-9]+", yol = "[a-zA-Z0-9\\-]*" }

);

MakaleOranla Action Metot

Makale oranla action methodumuzda, güvenlik açısından ve bu methodun dışarıyla bir bağlantılı veriye ihtiyaç duymuyacağından, projemizin uygulama kısmında sadece bu action methodu, javascprit kodları aracılıyla çağırma ihtiyacı duyacağız.

[ServiceOnly, HttpPostOnly]
public ActionResult MakaleOranla(int makaleId, int oran)
{
KarayelEntities dc = new KarayelEntities();
Makaleler viewData = dc.Makalelers.GetirMakale(makaleId);
try
{
viewData.Oranla(oran);
dc.SaveChanges();
}
catch { /* tüm çakışmaları gözardı et, çok kritik değil*/ }
return View(new { MakaleID=makaleId, averageRating = viewData.OrtalamaOran});
}

MakaleYonet Action Metot

Bu action metot makalelerin listelenerek gösterilmesini sağlamaktadır. Aynı zamanda maklenin listelendiği yerde makalelerin yönetim işlemleride gerçekleştirilmektedir.

[Authorize(Roles = "Editor")]
public ActionResult MakaleYonet(int page)
{
KarayelEntities dc = new KarayelEntities();
var viewData = dc.Makalelers.GetirMakaleler(null, page);
ViewData["SayfaBaslik"] = "Makale Yönet";
return View(viewData);
}

Bu action diğer action metotlara göre nispeten daha basittir. Bu action metot bundan önceki action metotlardan farklı olarak authorized özelliğine sahiptir. Bu özellik Context.user kullanarak kullanıcı kimliğine ulaşılabilmektedir. Bu durumdan yukarıdaki kodda görüldüğü gibi bu action kısıtlanmıştır. Sadece yetkisi editör olanlar bu action'ın metoda ulaşabilmektedir. Eğer kullanıcın makaleyi yönetme yetkisi yoksa kullanıcı böyle bir istekte bulunduğunda o kullanıcı giriş sayfasına yönlendirilmelidir.

MakaleGrupYonet ve YorumYonet metotları bu action metot ile hemen hemen aynıdır. Bu yüzden o action'ları anlamanız oldukça kolay olacaktır. Bu action metot, makalegrupyonet ve yorumyonet action metotları aşağıdaki route'lara sahiptir.

  1. admin/makaleler
  2. admin/makaleler/page{page}
  3. admin/makaleler/makalegruplari
  4. admin/makaleler/makaleyorum
  5. admin/makaleler/makaleyorumlari/page{page}

admin/makaleler

Bu route bütün makaleri düzeltmek için kullanılmaktadır.

routes.MapRoute(

"YonetMakale",

"admin/makaleler",

new { controller = "Makale", action = "MakaleYonet", page = 1 }

);

admin/makaleler/page{page}

Bu route belirli sayfalardaki makaleeri düzeltmek için kullanılmaktadır.

routes.MapRoute(

"YonetMakalePaged",

"admin/makaleler/page{page}",

new { controller = "Makale", action = "MakaleYonet", page = (int?)null },

new { page = "[0-9]+" }

);

admin/makaleler/makalegruplari

Bu route bütün makale gruplarını düzeltmek için kullanılmaktadır.

routes.MapRoute(

"YonetMakaleGrup",

"admin/makaleler/makaleGruplari",

new { controller = "Makale", action = "MakaleGrupYonet" }

);

admin/makaleler/makaleyorum

Bu route bütün makale yorumlarını düzeltmek için kullanılmaktadır.

routes.MapRoute(

"YonetMakaleYorum",

"admin/makaleler/makaleYorumlari",

new { controller = "Makale", action = "MakaleYorumYonet", page = 1 }

);

admin/makaleler/makaleyorumlari/page{page}

MakaleDuzenle ve MakaleEkle Action Metotları

Makale ekle ve makale düzenle action metotları bir arada oluşturulmalıdır. Zaten bu iki action birbiri ile tam bir ilişki içerisindedir ve aynı zamanda benzer kodları içermektedirler.

MakaleEkle Action Metot

Makalegoruntue metodunda gösterilen makalelerin eklenme işlemi bu action sayesinde gerçekleştirilmektedir. Yine bu kodunda anlaşılmasını kolaylaştırmak için parça parça aşağıdaki gibi işlenecektir.

[Authorize(Roles = "Contributor")]

[ValidateInput(false)]

public ActionResult MakaleEkle(int? refMakaleGrupId, string baslik, string ozet, string icerik, string ulke, string ilce, string sehir, DateTime? yayinTarihi, DateTime? yayinSonu, bool? onay, bool? listeOnay, bool? yorumaAcik, bool? YalnizcaUyeler)

{

KarayelEntities dc = new KarayelEntities();

var makaleGruplari = dc.MakaleGrups.GetirMakaleGruplari();

Analiz bölümde de açıkladığımız gibi sadece belirlenen kullanıcılar MakaleEkle action metodundan faydalanmalıdır. Yukarıdaki kodta bizim koyduğumuz sınırlama ise kullanıcın MakaleEkle action metodundan faydalabilmesi için Contributor(yazar) yetkisine sahip olması gerekmektedir.

Diğer kodlar ise bu metodun view'ından veri alabilmek için makaleekle view'ında yer alan form elemanlarının ismini parametre olarak almaktadır. Böylelikle makale ekleyebilmek için ihtiyacımız olan verileri alabilmezi sağlamaktadır.

if (refMakaleGrupId.HasValue &&

!String.IsNullOrEmpty(baslik) &&

!String.IsNullOrEmpty(icerik))

MakaleEkle metodunun bu kısmı ise veri tabanında karmaşıklığa yol açmamak için kullanılmaktadır.Örneğin başlıksız ve içeriksiz bir makale olamaz Bu yüzden makalenin formdan gelen verilerin diğerleri dolu olsa bile bu makale veri tabanına kaydedilmeyecektir.

{

try

{

Makaleler makale = new Makaleler

{

RefMakaleGrupID = refMakaleGrupId.Value,

Baslik = baslik,

Yolu = baslik.ToUrlFormat(),

Ozet = ozet,

Icerik = icerik,

Ulke = ulke,

Ilce = ilce,

Sehir = sehir,

YayinTarihi = yayinTarihi ?? DateTime.Today,

YayinSonu = yayinSonu,

Onay = onay ?? false,

ListeOnay = listeOnay ?? false,

YorumaAcik = yorumaAcik ?? false,

YalnizcaUyeler = YalnizcaUyeler ?? false,

Ekleyen = User.Identity.Name,

EklemeTarihi = DateTime.Now

};

dc.Makalelers.AddObject(makale);

dc.SaveChanges();

Yukarıdaki kod parçacığı ise veri tabanına makaleyi ve özelliklerini kaydedebilmek içindir. Bu değerleri bu action metot parametre olarak alır ve yukarıdaki gibi belirtilen olan veritabanı alanlarına kaydedilir. Eğer parametreleden boş gelen değerler olursa veritabanına default olarak Null atanmaktadır. Veri tabanı alanlarına Null atamak C# editörü içinde tyer alan ?? karakterleri ile oldukça kolaydır. Makelernin tüm özellikleri oluşturulduktan sonra veritabanına kaydedilmesi gerekmektedir. Bu işlemi gerçekleştirebilmek için Add.Object metodundan faydalanılmaktadır

TempData["TamamlandiMesaj"] = "Makaleniz başarıyla kaydedildi.";

return RedirectToAction("MakaleGoruntule", new { id = makale.MakaleID, yol = makale.Yolu });

}

catch (Exception exc)

{

TempData["HataMesaj"] = exc.Message;

}

}

ViewData["refMakaleGrupID"] = new SelectList(makaleGruplari, "makaleGrupID", "Baslik", refMakaleGrupId);

ViewData["baslik"] = baslik;

ViewData["ozet"] = ozet;

ViewData["icerik"] = icerik;

ViewData["ulke"] = new SelectList(Iso3166UlkeKodlari.UlkeDictionary, "Key", "Value", ulke ?? "TR");

ViewData["ilce"] = ilce;

ViewData["sehir"] = sehir;

ViewData["yayinTarihi"] = yayinTarihi;

ViewData["yayinSonu"] = yayinSonu;

ViewData["onay"] = onay;

ViewData["listeOnay"] = listeOnay;

ViewData["yorumaAcik"] = yorumaAcik;

ViewData["yalnizcaUyeler"] = YalnizcaUyeler;

ViewData["SayfaBaslik"] = "Makale Oluştur";

return View("MakaleEkle");

}

Yukarıdaki kod parçacığı ise makalenin kayıt durumu hakkında kullanıcıya mesaj döndürmektedir. Eğer kaydetme işlemi sırasında bir problem oluşmamışsa Makale başarılı bir şekilde kaydedildi” gibi bir yaxı döndürülmelidir. Eğer makale kayıt işlemi sırasında bir hata oluşmuşsa “ makale kayıt edilemedi” gibi bir mesaj döndürülmeli ve ardıdan tekrar makale ekle sayfasına yönlendirilmelidir.

MakaleDuzenle Action Metot

MakaleDuzenle Action metodu MakaleEkle action metodundan kaydedeğer bir farklılığı yoktur. MakaleDuzenle Action metodunun içeriği aşağıdaki gibidir.

[Authorize(Roles = "Editor")]
[ValidateInput(false)]
public ActionResult MakaleDuzenle(int makaleID, int? RefmakaleGrupID, string baslik, string ozet, string icerik, string ulke, string ilce, string sehir, DateTime? yayinTarihi, DateTime? yayinSonu, bool? onay, bool? listeOnay, bool? yorumaAcik, bool? yalnizcaUyeler)
{
KarayelEntities dc = new KarayelEntities();
var makaleGruplari = dc.MakaleGrups.GetirMakaleGruplari();
if (IsPostBack)
{
onay = onay ?? false;
listeOnay = listeOnay ?? false;
yorumaAcik = yorumaAcik ?? false;
yalnizcaUyeler = yalnizcaUyeler ?? false;
}
Makaleler makale = dc.Makalelers.GetirMakale(makaleID);
if (makale == null)
throw new HttpException(404, "Makale bulunamadı.");
if (RefmakaleGrupID.HasValue
&& !String.IsNullOrEmpty(baslik)
&& !String.IsNullOrEmpty(icerik))
{
try
{
makale.RefMakaleGrupID = RefmakaleGrupID.Value;
makale.Baslik= baslik;
makale.Ozet= ozet;
makale.Icerik = icerik;
makale.Ulke = ulke;
makale.Ilce= ilce;
makale.Sehir = sehir;
makale.YayinTarihi = yayinTarihi ?? makale.YayinTarihi;
makale.YayinSonu = yayinSonu;
makale.Onay= onay ?? false;
makale.ListeOnay = listeOnay ?? false;
makale.YorumaAcik= yorumaAcik ?? false;
makale.YalnizcaUyeler = yalnizcaUyeler ?? false;
dc.SaveChanges();
TempData["TamamlandiMesaj"] = "Makaleniz başarıyla güncellendi.";
}
catch (Exception exc)
{
TempData["HataMesaj"] = exc.Message;
}
}
ViewData["RefMakaleGrupID"] = new SelectList(makaleGruplari, "MakaleGrupID", "Baslik", RefmakaleGrupID ?? makale.RefMakaleGrupID);
ViewData["baslik"] = baslik ?? makale.Baslik;
ViewData["ozet"] = ozet ?? makale.Ozet;
ViewData["icerik"] = icerik ?? makale.Icerik;
ViewData["ulke"] = new SelectList(Iso3166UlkeKodlari.UlkeDictionary, "Key", "Value", ulke ?? makale.Ulke ?? "TR");
ViewData["ilce"] = ilce ?? makale.Ilce;
ViewData["sehir"] = sehir ?? makale.Sehir;
ViewData["yayinTarihi"] = yayinTarihi ?? makale.YayinTarihi;
ViewData["yayinSonu"] = yayinSonu ?? makale.YayinSonu;
ViewData["onay"] = onay ?? makale.Onay;
ViewData["listeOnay"] = listeOnay ?? makale.ListeOnay;
ViewData["yorumaAcik"] = yorumaAcik ?? makale.YorumaAcik;
ViewData["yalnizcaUyeler"] = yalnizcaUyeler ?? makale.YalnizcaUyeler;
ViewData["SayfaBaslik"] = "Makale Düzenle";
return View("MakaleEkle");
}

MakaleDuzenle action metodu için önemli olan temel unsurlar vardır;

  • Autdorized özelliği editör veya yazar olarak değiştirilebilir.
  • Makalenin Id'sini route'dan parametre olarak almaktadır.

  • IspostBack kısmının içerisinde eklediğimiz makalenin özellikleri vardır. Bu özellikler mutlaka dolu olmalıdır. Eğer kullanıcı bu özellikleri doldurmamışsa default olarak siteme false olarak kaydedilir. Çünkü checkBox hiçbir zaman null olamaz.
  • ViewData elemanlarının değerleri ya parametrelerden gelir ya da orijinal olarak makale nesnesinden alır.

MakaleEkle ve MakaleDuzenle action metotlarının route'ları sırasıyla aşağıdaki gibidir.

admin/makaleler/makaleEkle

routes.MapRoute(

"makaleEkle",

"admin/makaleler/makaleEkle",

new { controller = "Makale", action = "MakaleEkle" }

);

admin/duzenle/{makaleId}

routes.MapRoute(

"MakaleDuzenle",

"admin/duzenle/{makaleId}",

new { controller = "Makale", action = "MakaleDuzenle", makaleId = (int?)null },

new { makaleId = "[0-9]+" }

);

MakaleSil Action Metot

Bu action metot ise makale ekle actiom metodu ile oluşturulan makaleri silmek için kullanılmakdır. Bu action metot silebilmek içn öncelikle gerekli yetkilere sahip olamak gerekmektedir. Bizim projemizde makale siebilme yetkisi aşağıda kodda görüldüğü gibi authorize'ı Edior olan kullanıcılar aittir.

MakleSil action metodu diğer şimdiye kadar gördüğünüz action metotlardan biraz farklıdır. Bu farklılığın sebebi kullanıcıya makaleyi silerken bir mesaj kutusuna yönlendirmemizden kaynaklanmaktadır.

Şöyleki;

Kullanıcı makleyi sil linkine tıkladığı zaman karşısına bir mesaj kutusu açılır ve mesaj kutusunda makaleyi silmek istiyormusunuz gibi bir soru yöneltilir eğer kullanıcı bu kısımda evet butonuna tıklarsa makale tamamen veritabanından silinir. Hayır butonuna tıklarsa işlemler geri alınır ve kullanıcı makaleler sayfasına yönlendirilir. Bu nedenle MakaleSil view'ına ikitane extradan buton eklenmelidir.

[Authorize(Roles = "Editor")]

public ActionResult MakaleSil(int makaleId, string sil)

{

KarayelEntities dc = new KarayelEntities();

Makaleler makale = dc.Makalelers.GetirMakale(makaleId);

// Veritabanında aranan makale bunulanamzsa 404 hatası fırlat

if (makale == null)

throw new HttpException(404, "Makale Bulunamadı.");

if (String.Equals(sil,"evet", StringComparison.OrdinalIgnoreCase))

{

dc.Makalelers.DeleteObject(makale);

dc.SaveChanges();

TempData["TamamlandiMesaj"] = makale.Baslik+ " başlıklı makale, başarıyla silindi.";

makale = null;

}

else if (String.Equals(sil,"hayir", StringComparison.OrdinalIgnoreCase))

{

TempData["BilgiMesaj"] = "Makale, " + makale.Baslik+ ", silinemedi.";

}

else

{

TempData["UyariMesaj"] = "Silmek İstediğinize Emin misiniz " + makale.Baslik+ ". Onayladıktan sonra Makale kalıcı olarak silinecektir. Tekrar geri getirilemez.";

}

ViewData["SayfaBaslik"] = "Makaleyi Sil";

return View(makale);

}

Bu action metodunun route'u aşağıdaki gibidir.

admin/makaleler/sil/{makaleId}

routes.MapRoute(

"SilMakale",

"admin/makaleler/sil/{makaleId}",

new { controller = "Makale", action = "MakaleSil", MakaleID = (int?)null },

new { makaleId = "[0-9]+" }

);

MakaleGrupEkle ve MakaleGrupDüzenle Action Metotları

MakaleGrup action metotları makalecontroller.cs sınıfının içeriside yer almaktadır. MakaleGrupEkle ve MakaleGrupDuzenle action metotları anlamanız oldukça kolay olacaktır. Zaten kod yapısı olarak MakaleEkle ve MakaleDuzenle action metotları ile benzerdir.

MakaleGrupEkle

MakaleGrupEkle Action metodu MakaleEkle Metodu ile hemen hemen aynıdır. Ancak farklılık gösterdiği bazı yerlede mevcuttur. Bu action metot ile MakaleEkle actionmetou kıyaslandığında iki tane fark bulunmaktadır. İlk fark aralarındaki parametre sayılarıdır. Diğer fark ise kullanıcı bir makale oluşturduğu anda o kullanıcı makale ekle sayfasına yönlendirilir.

MakaleGrupEkle action metodunun kod yapısı aşağıdaki gibidir.

[Authorize(Roles = "Editor")]
[ValidateInput(false)]
public ActionResult MakaleGrupEkle(string baslik, int? onemi, string resimYolu, string tanimi)
{
if (!String.IsNullOrEmpty(baslik)
&& !String.IsNullOrEmpty(resimYolu)
&& !String.IsNullOrEmpty(tanimi))
{
try
{
KarayelEntities dc = new KarayelEntities();
MakaleGrup makaleGrup = new MakaleGrup
{
Baslik = baslik,
Onemi = onemi ?? -1,
ResimYolu = resimYolu,
Tanimi = tanimi,
Ekleyen = User.Identity.Name,
EklemeTarihi = DateTime.Now,
Yolu = baslik.ToUrlFormat()
};
dc.MakaleGrups.AddObject(makaleGrup);
// değişikilikleri veritabanında gerçekleştir
dc.SaveChanges();
TempData["TamamlandiMesaj"] = "Makale grubu başarıyla oluşturuldu.";
return RedirectToAction("MakaleYonet");
}
catch (Exception exc)
{
TempData["HataMesaj"] = exc.Message;
}
}
ViewData["baslik"] = baslik;
ViewData["onemi"] = onemi;
ViewData["resimYolu"] = resimYolu;
ViewData["tanimi"] = tanimi;
ViewData["SayfaBaslik"] = "Makale Grubu Oluştur";
return View("MakaleGrupEkle");
}
Bu action metodunun route'u aşağıdaki gibidir.
admin/makaleler/makaleGruplari/ekle
routes.MapRoute(
"EkleMakaleGrup",
"admin/makaleler/makaleGruplari/ekle",
new { controller = "Makale", action = "MakaleGrupEkle" }
);

MakaleGrupDuzenle action metodu seçilen makalegrubunun düzenlenmesini için kullanılmaktadır. MakaleGrupDuzenle Action metodunun içeriği aşağıdaki gibidir.

[Authorize(Roles = "Editor")]
[ValidateInput(false)]//Bu Ne İşe yarıyor
public ActionResult MakaleGrupDuzenle(int makaleGrupID, MakaleGrup mkr )
{
KarayelEntities dc = new KarayelEntities();
MakaleGrup makaleGrup = dc.MakaleGrups.GetirMakaleGrup(makaleGrupID);
// Veritabanında aranan makale grubu bunulanamzsa 404 hatası fırlat
if (makaleGrup == null)
throw new HttpException(404, "Makale grubuna ulaşılamadı.");
if (!String.IsNullOrEmpty(mkr.Baslik)
&& !String.IsNullOrEmpty(mkr.ResimYolu)
&& !String.IsNullOrEmpty(mkr.Tanimi))
{
try
{
makaleGrup.Baslik = mkr.Baslik;
makaleGrup.Onemi =mkr.Onemi;
makaleGrup.ResimYolu = mkr.ResimYolu;
makaleGrup.Tanimi = mkr.Tanimi;
// değişiklikleri veritabanında da gerçekleştir
dc.SaveChanges();
TempData["TamamlandiMesaj"] = "Makale Grubu Başarıyla Güncellendi.";
}
catch (Exception exc)
{
TempData["HataMesaj"] = exc.Message;
}
}
ViewData["baslik"] = mkr.Baslik ?? makaleGrup.Baslik;
if (!String.IsNullOrEmpty(Convert.ToString( makaleGrup.Onemi)))
ViewData["onemi"] = makaleGrup.Onemi;
ViewData["resimYolu"] = mkr.ResimYolu ?? makaleGrup.ResimYolu;
ViewData["tanimi"] = mkr.Tanimi ?? makaleGrup.Tanimi;
ViewData["SayfaBaslik"] = "Makale Grup Düzenle";
ViewBag.ibrahim = "İbrahim";
return View("MakaleGrupEkle");
}
Bu action metodunun route'u aşağıdaki gibidir.
admin/makaleler/makalegruplari/duzenle/{makaleGrupId}
routes.MapRoute(
"DuzenleMakaleGrup",
"admin/makaleler/makalegruplari/duzenle/{makaleGrupId}.Uzanti",
new { controller = "Makale", action = "MakaleGrupDuzenle", makaleGrupId = (int?)null },
new { makaleGrupId = "[0-9]+" }
);

MakaleGrupSil Action Metot

MakaleGrupSil action metodu MakaleSil action metotundan biraz farklıdır. Bu farklılığın sebebi ise sistemin güvenliği için makale grubu silinmeden önce yapılması gereken birkaç önemli işlemin bulunmasıdır. Bunu bir örnekle açıklamak gerekirse;

Veri tabanından silinmek istenen makalenin bağlantılı olduğu tek bir tane makale grubu bulunmaktadır. Böylelikle silinmek istenen makaleId ile makaleGrupId aynı tabloda, aynı satırda yer aldığı için silinme aşamasında herhangi bir sorun yaşanmamaktadır. Ancak makale grubu silinmek istenirse durum biraz farklılık göstermektedir. Çünkü silinmek istenen makale grubu veritabanında makaleler tablosu ile bağlantılıdır. Bunu da bir örnekle açıklamak gerekirse;

Veri tabanında silinmek makale grububun bir çok makalesi olabilir. Böylelikle makale grubu silinmek istenirse bu makale grubuna ait olan makaler ileride sorun çıkarmaktadır.Çünkü makale grubu olmayan bir makale düşünelemez.

Bu sorunu ise birkaç farklı yolla çözülebilmektedir. Silinen makale grubunun makaleleri silinmeden önce ya bir başka makale grubuna aktarılmalı yada o makalelerin tamamı silinmelidir.

[Authorize(Roles = "Editor")]
public ActionResult MakaleGrupSil(int makaleGrupID, int? yeniMakaleGrupID, string sil)
{
KarayelEntities dc = new KarayelEntities();
var makaleGrup = dc.MakaleGrups.GetirMakaleGruplari();
MakaleGrup mgrup = dc.MakaleGrups.GetirMakaleGrup(makaleGrupID);
bool yeniKategoriVarmi = makaleGrupID != yeniMakaleGrupID && dc.MakaleGrups.MakaleGrubuMevcutmu(yeniMakaleGrupID ?? -1);
// Veritabanında aranan makale grubu bunulanamzsa 404 hatırası fırlat
if (mgrup == null)
throw new HttpException(404, "Makale Grubu bulunamadı.");
if (String.Equals(sil, "evet", StringComparison.OrdinalIgnoreCase) && yeniKategoriVarmi)
{
foreach (Makaleler makale in mgrup.Makalelers)
makale.RefMakaleGrupID = yeniMakaleGrupID.Value;
dc.MakaleGrups.DeleteObject(mgrup);
dc.SaveChanges();
TempData["TamamlandiMesaj"] = "Makale Grup, " + mgrup.Baslik+ ", başarıyla silindi.";
mgrup = null;
}
else if (String.Equals(sil, "hayir", StringComparison.OrdinalIgnoreCase))
{
TempData["BilgiMesaj"] = "Makale grup, " + mgrup.Baslik+ ", silinemedi.";
}
else
{
ViewData["yeniMakaleGrupID"] = new SelectList(makaleGrup, "makaleGrupID", "Baslik", yeniMakaleGrupID);
TempData["UyariMesaj"] = mgrup.Baslik + " başlıklı makaleyi silmek istediğinize emin misiniz? Eğer silmek istediğinize eminseniz, farklı bir makale grubu seçin ve Evet tuşuna basın.";
}
ViewData["SayfaBaslik"] = "Makale Grubu Sil";
return View(mgrup);
}

Not: Makale veya makale grubu güncelleştirnemiz gerekirse o makenin veya makele grubunun bağlantılı olduğu tablolardan da gerekli güncelleştirilmelerinin(makaleId,MakaleGrupId) yapılması da unutulmamalıdır.

Bu action metodunun route'u aşağıdaki gibidir.

admin/makaleler/makalegruplari/sil/{makaleGrupId}

routes.MapRoute(

"SilMakaleGrup",

"admin/makaleler/makalegruplari/sil/{makaleGrupId}",

new { controller = "Makale", action = "MakaleGrupSil", makaleGrupId = (int?)null },

new { makaleGrupId = "[0-9]+" }

)

YorumEkle Action Metot

Yorum Ekle actin metodu daha önce yaptığımız action metotlardan biraz farklıdır. Bu metot diğerine göre biraz farklı özelliklere sahiptir. Çünkü yorum ekle action metoda bağlı view'ın içine fazladan birkaç daha eklenmelidir.

  1. Server üzerinde yorum ekle action metoduna POST işlemi gerçekleştirebilirsiniz. Böylelikle yapılan yorum makalenin altında gözükür. Bu sistem internette kullanılan yöntemlerden birisidir. Anacak yorumun gözüke bilmesi için refresh işlemi gerektiği için bazı sıkıntılar meydana gelmektedir.
  2. Bir başka yol ise server üzerinde Ajax ile Post işlemidir post işelmi gerçekleştikten sonra gerekli bilgiler server üzerine gönderilir ve bizde anında gönderdiğimiz yorumu refresh işlemi olmadan makalenin altında görürüz. Bu yapmk için java script ile birlikte birkaç istemci programı gereklidir.

[ServiceOnly, HttpPostOnly]
[ValidateInput(false)]
public ActionResult YorumEkle(int makaleID, string adi, string email, string icerik)
{
KarayelEntities dc = new KarayelEntities();
Makaleler makale = dc.Makalelers.GetirMakale(makaleID);
// Veritabanında aranan makale bunulanamzsa 404 hatası fırlat
if (makale == null)
throw new HttpException(404, "Makale Bulunamadı.");
MakaleYorumlari yorum = new MakaleYorumlari
{
Ekleyen = adi,
EkleyenEmail = email,
EkleyenIP = Request.UserHostAddress,
EklemeTarihi = DateTime.Now,
Icerik = icerik
};
makale.MakaleYorumlaris.Add(yorum);
// değişiklikeri veritabanında da gerçekleştir
dc.SaveChanges();
return View(new
{
yorumId = yorum.MakaleYorumID,
adi = yorum.Ekleyen,
icerik = yorum.Icerik
});
}

Bu action metot için gerekli olan route standart olarak {controller}/{act.ion} şeklinde ulaşılmaktadır.

  • "/makale/YorumEkle"

YorumDuzenle Action Metot

Yorum düzenle action metodu yorum ekle action metodu ile hemen hemen aynı olmakla birlikte bu action metoda yetkisi editör olan kullanıcılar kullanabilmektedir. Bu action metot makaleyonet.cshtml sayfasında kullanılabilmektedir ve bu sayfadan tamamen javascript ve Ajax içermektedir. Biz projenizde Ajax kullanmanızı tavsiye ediyoruz. Çünkü Ajax gerekli olan tüm tüm kodları dersteklemektedir.

[

Authorize(Roles = "Editor")]
[ServiceOnly, HttpPostOnly]
[ValidateInput(false)]
public ActionResult YorumDuzenle(int yorumID, string adi, string icerik)
{
KarayelEntities dc = new KarayelEntities();
MakaleYorumlari yorum = dc.MakaleYorumlaris.GetirMakaleYorumlari(yorumID);
// Veritabanında aranan makale yorumu bunulanamzsa 404 hatası fırlat
if (yorum == null)
throw new HttpException(404, "Makale yorumu bulunamadı.");
yorum.Ekleyen = adi==null ? adi : "test"; //null ? viewCategory.Baslik: "Tüm"
yorum.Icerik= icerik;
// değişiklikleri güncelle
dc.SaveChanges();
return View(new
{
yorumID = yorum.MakaleYorumID,
adi = yorum.Ekleyen,
icerik = yorum.Icerik
});
}

Bu action metot için gerekli olan route standart olarak {controller}/{act.ion} şeklinde ulaşılmaktadır.

  • /makale/YorumDuzenle

YorumSil Action Metot

YorumSil action metodu YorumDuzenle action metoduna benzemektedir. Bu metot da Ajax kullanılmaktadır. Böylelikle silinmek istenenen yorum hiçbir sıkıntı olamadan kolayca silinebilmektedir. Ancak bu metodu sadece yetkisi olan kullanıcılar kullanabilmektedir.

[Authorize(Roles = "Editor")]
[ServiceOnly, HttpPostOnly]
public ActionResult YorumSil(int yorumID)
{
KarayelEntities dc = new KarayelEntities();
MakaleYorumlari yorum = dc.MakaleYorumlaris.GetirMakaleYorumlari(yorumID);
// Veritabanında aranan makale yorumu bunulanamzsa 404 hatası fırlat
if (yorum == null)
throw new HttpException(404, "Yorum bulunamadı.");
dc.MakaleYorumlaris.DeleteObject(yorum);
dc.SaveChanges();
return View(new { yorumId = yorumID });
}
#endregion
}

Silme işleminde javascrit kullanılması işlemlerin hız gerçekleşmesini sağlamaktadır.

Bu action metot için gerekli olan route standart olarak {controller}/{act.ion} şeklinde ulaşılmaktadır.

  • makale/YorumSil

Lazy loading İşlemi

Lazy load işlemi bizim projemizin performasında fark edilir bir değişiklik sağlamıştır. Lazy load sayesinde veritabanı ile ilgili işlemleri oldukça kolaylaşmıştır. Bu layzy load işlemi sayesinde veri tabanından veri çekilmek istendiğinde program her seferinde veritabanına gitmek zorunda olmayacaktır. Böylelikle zaman kaybı olmayacak ve işlemler hızlı bir şekilede gerçekleşecektir. Ayrıca veritabanını modelsde .edmx dosyasına kopyalandığı için veri tabanı yorulmayacaktır.

Ancak lazy load işleminde dikkat edilmesi gereken önemli bir yer bulunmaktadır. Lazy load işleminin doğru bir şekilde sonuç üretebilmesi için update, insert, delete sorgularının gerçekleşmemesine dikkat edilmelidir. Çünkü update, delete, insert sorguları gerçekleştiğinde veritabanında değişikler meydana gelir. Ardından kullanıcı isteklerine göre çalışan sonraki sorgular bu değiştirilen verileri kullanarak sonuç göstermelidir. Eğer bu kısma dikkat edilmez ise program eski veriler üzerinden işlemlerini yürütür. Dolayısıyla veritabanından çekilen sorgular yanlış sonuç üretilir. Bu yüzden veritabanı her güncelleştirildiğinde(Update,Insert,Delete...) tekrardan bir Lazy loading işlemi daha yapılmalıdır.

View'in uygulanışı

Makaleler modulü için model ce controller bölümlerini tamamlamış bulunmaktayız. Şimdi ise makale modulünün görsel kısımlarını oluşturacağı view kısmı incelenecektir. Makale model kısmı veritabanından veri tabanında birtakım değişikler yapılırken kullanılmaktaydı. View kısmı ise bu değişikliklerin yapılabilceği sayfaların oluşturulmasını kapsamaktadır.

MakaleGrup.chtml

Bu view ~/Views/Shared/Makale klasörünün içerisinde bulunmaktadır. Hem makaleGrup.cshtl hem de makalegrupIndex.cshtl sayfaları model nesnesinin içesinde yer alan makalegrup tablosu ile doğrudan bağlantılıdır. Olşturacağımız bir makale grubu dayfada aşağıdaki gibi gösterilecektir.

Şekil –13


Yukarıda gördüğününüz gibi layout oldukça basittir. Yukarıdaki ahlak yazısı makale grubu ismidir. Bu yazı bu makale grubu dahil tüm makalelerin gösterildiği sayfa ile bağlantılıdır. Her makale grubunda bazı ortak özeller vardır. Örneğin her makale grubun ekranda gösterilirken kendine ait bir başlığı vardır. Ayrıca makalegrupduzenle ve sil view'larına gidilebilcek birer tane bağlatıya sahiptir. Bunların her birini ayrı ayrı yazmak yerine ~view/shared/makale/makalegrupitem.cshtml dosyası oluşturulmuştur. Bu dosya sayesinde her makale grubunda ortak olan özellikler tek bir dosyadan helledilebimektedir.

HTML view conrtorülünde eşittir basitlik anlamına gelir.HTML her categori için kullanılır,biz genellikle belli başlı iki tipi kyullanırız. Birinci tür emsalsiz bir tanıtıcıdır;ki bu durumda categor kelimesi ve categori kimliği yorumlarnır(rendering).

BU şu sebeğten yaparız çünkü js ve css ten özel bir refereans ihtiyacın olursa diye.İkinci tür ise genel bir belirleyicidir,ki tüm HTML DOM larda aynı şeklde uygulanır;bu alanda kelime sadece categoridir(bu cğmlye bi bak220 son cümleden önce..).Bunun ndeni buna genel bir tanıtıcı eklemiş olmamız ki bu tğm HTML DOM larında kullanıldığı gibi css ve js de ve yeni bir çok frame work te de kullanılabilir ve sadece bir sınıf sayesinde.Bunların asıl yararlarını müşteriye yönelik ve js kullanılan programlamada göreceksiniz.

Eğer henüz HTML de yeniyseniz,veya düzenlemede HTML ile tanloları kullanmıyorsanız,bu kategori için oluşturacağımız sade minimalist tasarım sizi şaşırtacak, aşağıdaki kodlarda gösterildiğ gibi,resim farzedelim categorinin soluna yerleştirilsin figure 6,8 de olduğu gibi.bu yaklaşımı almamızn sbebi bu kötü bir dizayn alıştırmasıdır0,yoldur tabloları kullanmak,halbuki bundan bir kaç yıl önce bu gayet kabul edilen bir yöntemdi.Yeni nesil tasarırımcılar tabloların sadece tablosal verileri gösteriminde kullanılması gerktiğini söylüyorlar ve taracıyıcı için genişlik still ve yerleşimin birleşimi bir kombşnasyon kullanılmsaı gerektşğini tavsiye ediyorlar.::code::

bir önce ki kodun kaynağı ViewData.Model view contorlunda kayıt altına alındı.o özel bir kategori türü, t olarak önceki kod bloğunda ayarlamıştık.

bunun yanında refens olarak Url.Action da sana ArticleController da bir kaç kez lazım olacaktır.:code::bundan önceki alanda index alanındaki kaynaklar, parametrelerdir kategori ve page mutlaka doğru yerde,yolda,yörüngede olmadlıdırlar view modelinin içinde,ve bu URL ilk sayfada başlamalı. bu URL sonucunda,

/articles/category/the-model-path oluşur. yönlendirme ve kurallrı Global.asax dosyasında tanımlamalısın.

Bir sonraki adımda dizaynının bir parçası olan CategoryItem i tanımlamalısın, ve figure 6-8 deki gibi bir görüntü için ise CSS e ihtiyacın var,bu stiller senin ana stilin olan ~/Content/styles/site.css. yerde eklidri halıi hazırda.::code::

Eğer daha önce CSS ile ilgilenmediysen ve pek fazla bilgi sahibi değilsen www.w3schools.com/css sitesini ziyaret et çok kulanışlı basit ve akıcı tarzda bir çok örnekle beraber güzel bir anlatımı bu sitede bulabilir,kendini kolayca CSS üzerinde geliştirebilirsin.

AdminSidebar.cshtml Kontrolü

Bu view contorolü ~/Views/Shared/Article dosyasında bulunur ve bağlantıları kurmak, kategoriler oluşturmak makale ve yorumları düzenlemek için kullanılmaktadır. Bu view bize diğer sayfalar arasında kolaylıkla gezinmemizi sağlamaktadır. Böyle bir view bizi fazla koddan kurtarmış olmaktadır. Örneğin yönetici yetkisine sahip bir kullanıcı makale yönetimine tıkladığı anda bu AdminSidebar elemanları sağda bir kutunun gözükmesi gerekmektedir. Ve bu makale yönetim sekleri arasında gezinme süresi boyunca bu AdminSidebar elemanları sağda gözükmeye devam etmelidir. Bu view'ın içeriği aşağıdaki gibidir.

<div id="articles-admin">
<h2>Makaleler</h2>
<div>
<ul>
<li>@Html.ActionLink("Makale Gruplarını Görüntüle", "MakaleGrupYonet") </li>
<li>@Html.ActionLink("Yeni Makale Grubu Ekle", "MakaleGrupEkle") </li>
<li>@Html.ActionLink("Makaleleri Görüntüle", "MakaleYonet") </li>
<li>@Html.ActionLink("Yeni Makale Ekle", "MakaleEkle")</li>
<li>@Html.ActionLink("Makale Yorumları", "MakaleYorumYonet")</li>
</ul>
</div>
</div>

MakaleGrupYonetimi.cshtml Kontrolü

Bu view ise ~/Views/Makale lokasyonunda bulunmaktadır. Yönetici ve Editörlerin kullanabileceği makale grubu slime ve makale grubu ekleme işlemleri bu sayfa üzerinden yönetilmektedir. Bu sayfanın ekran görüntüsü aşağıdaki resimdeki gibidir.

Şekil –14


Burada bir foreach döngüsü ile tüm kategoriler gösterilmiş. Buna ek olarakta makelenin sağıda makaleyi düzenleyebilmemiz vr silebilmemiz için iki ayrı linklerde oluşturulmuştur. Düzenle linkine tıkladığınızda makaleduzenle metoduna giderek bizi gerekli sayfaya yöneledirir. Daha doğrusu düzenleme işlemleri başka bir view sayfasında gereçekleşir. MakaleGrupYonetimi.cshtml sayfası aşağıdaki kodları içermektedir.

@model KarayelTasarim.Models.Pagination<KarayelTasarim.Models.Makaleler>
@MvcHtmlString.Create(Html.If(!String.IsNullOrEmpty(TempData["HataMesaj"] as string), () => "<div class=\"error\">" + TempData["HataMesaj"] + "</div>")
.ElseIf(!String.IsNullOrEmpty(TempData["TamamlandiMesaj"] as string), () => "<div class=\"success\">" + TempData["TamamlandiMesaj"] + "</div>")
.ElseIf(!String.IsNullOrEmpty(TempData["UyariMesaj"] as string), () => "<div class=\"warning\">" + TempData["UyariMesaj"] + "</div>")
.ElseIf(!String.IsNullOrEmpty(TempData["BilgiMesaj"] as string), () => "<div class=\"info\">" + TempData["BilgiMesaj"] + "</div>")
.Else(() => String.Empty))
<div id="articles">
@{ foreach (KarayelTasarim.Models.Makaleler makale in ViewData.Model)
{
<div>@Html.ActionLink("Düzenle", "MakaleDuzenle", new { controller = "Makale", makaleId = makale.MakaleID }) | @Html.ActionLink("Sil", "MakaleSil", new { controller = "Makale", makaleID = makale.MakaleID })</div>
<hr />
@Html.Partial("~/Views/Shared/Makale/MakaleItem.cshtml", makale)
} }

Bu sayfaya geldiğimizde sağtaraftaki makale yönetimleri ilgili linklerin bulunduğu kutunun kaybolmaması için bu view en altına aşağıdaki kodu yazmamız gerekmektedir. Yukarıda oluşturduğumuz AdminSidebar.cshtml view'I sayesinde bu işlem kolaylık haledilebilmektedir.

@section SidebarContent {
@Html.Partial("~/Views/Shared/Makale/AdminSidebar.cshtml")
}

MakaleGrupEkle.cshtml Kontrolü

MakaleYonet.cshtml view'ında olduğu gibi bu view da ~Views/Makale konumunda bulunmaktadır. Bu view yetkisi yönetici ve editör olan kullanıcıların makale grubunu ekleyebilmesini sağlamaktadır. Aşağıda makale grup ekle sayfasının şekil-15'te resmi bulunmaktadır.

Şekil –15


MakaleGrupEkle.cshtml view'ının iki görevi vardır. Bu görevlerden ilki makele grubu oluşturmak ikincisi ise oluşturulan makale grubunu düzenlemektir. MakaleGrupekle ve MakaleGrupDuzenle metotları ile ilişkilidir.

Bu viewda dikkat edilmesi gereken diğer bir nokta ise kullanızılara makale grubu eklerken ekleme aşamasında yardımcı olmaktır. Bunun en iyi yolu resimdeki gibi alanların altına nasıl doldurulması gerektiğini ifade eden küçük yardıcı notlar eklemektir.(şekil-16)

Şekil –16


Veya değer alma noktasında bir hata oluşmuş ise bunu kutunun altın da resimde de olduğu gibi vurugulamaktır.(Şekil –17)

Şekil –17


Bizde js kullanacağız eğer js www.jquery.com dan faydalnarak bu problem halledebiliriz. Ancak bu Js ilei lgili daha fazlasını öğrenmeke istiyorsanız büyük aramam motorlarına jQuery help” yazarak yeterli bilgiye sahip olabilirsiniz

Şimdi ise kodları tek tek inceleyerek makale grubu ekle view'ını anlamaya çalışalım. MakaleGrupEkle.cshtml Temel içerik Script içerik ve son olarakta Sidebar içerik olmak üzere view'ı 3 farklı Html içeriğine sahiptir.

Temel İçerik

Buna genel içerikte denilebilir. Bu temel içerik bizim formumuzda makale grubu ekleyebilmek için gerekli olan HTML elementlerini tutmaktadır. Örneğin makale grubunun başlığı ve içeriğini ekleyebilmemiz için sırasıyla bir tane textBox ve bir tanede textArea'ya ihiyacımız vardır. işte bu Html elementlerinin kod kısmı buraya yazılmaktadır.

<form method="post" action="@Url.Action(this.ViewContext.RouteData.Values["action"] as string, "Makale") ">
<p><label for="baslik">Başlık</label><br />
@Html.TextBox("baslik", ViewData["baslik"], new { maxlength = 256 })
<span></span></p>
<p><label for="onemi">Önemi</label><br />
@Html.TextBox("onemi", ViewData["onemi"], new { maxlength = 3 })
<span></span></p>
<p><label for="resimYolu">Resim</label><br />
@Html.TextBox("resimYolu", ViewData["resimYolu"], new { maxlength = 256 })
<span></span></p>
<p><label for="tanimi">Tanım</label><br />
@Html.TextArea("tanimi", ViewData["tanimi"])
<span></span></p>
@if(this.ViewContext.RouteData.Values["action"] as string == "MakaleGrupDuzenle") {
<p><button type="submit" id="category-create-button">Güncelle</button></p>
} else {
<p><button type="submit" id="category-create-button">Yeni Makale Grubu Ekle</button></p>
}
</form>

Yukarıdaki kodlar kopyala yapıştır bir kod değildir bu kodlar üzerinde oynanmıştır. Bu sayfa makale grubu düzenleme ve makale grubu ekleme gibi iki farklı amaç için kullanılmaktadır. B u view'ı iki farklı şekilde kullanabilmek tek yapmamamız gereken için global.asax kısmında iki ayrı tanımlama yapmaktır. Böylelelikle makale grubu eklemek ve makale grubu düzenlemek için iki ayrı view oluşturmamıza gerek kalmayacaktır.

Script İçerik

Bu kısımda js ile kullanıcıya göstermke istediğimiz uyaruıyada hata mesajlarının, doğrulama yada yönlendirme açısından nasıl yapılacağına değineceğiz. Öncelikle aşağıdaki kod MakaleGrupEkle.cshtml view'ının en altına eklenmelidir.

@section ScriptContent {
<script type="text/javascript" src="/content/scripts/yonet-makalegrup.js"></script>
@if (IsPostBack) {
<script type="text/javascript">
ValidateCategory();
</script>
} }

Daha sonra yukarıdaki kodu doğrulamak için belirtilen konuma(/content/scripts/ yonet-makalegrup.js bir javascript dosyası eklemektir. Sonra bu dosyanın içrisine gerekli olan kodlar yazılalacaktır

yonet-makalegrup.js

Yonet-makalegrup.js dosyası ~/Content/scripts/ konumunda bulunur ve genel olarak client-side actions larda MakaleGrupEkle.cshtml viewinde kullanılır. Biz bu js dosyanın 3 farklı parçaya ayıracağız böylece mevzuyu daha iyi anlayabileceksiniz ve bu dosyalar üzerinde daha verimli, çalışabileceksiniz. İlk kısımda bilgi mesajlarını ele alcağız sonra doğrulama ve hata mesajları son olarak da göndermeden önce formdaki doğulamayı göreceğiz.

  1. Aşağıdaki kod baslik, Onemi, resimyolu, ve tanimi textboxlarına tıklandığında ShowMessage fonksiyonu ile bir mesaj göstereceği anlamına gelmektedir.

$("#baslik").focus(function () { ShowMessage(this, "Başlık giriniz."); });
$("#onemi").focus(function () { ShowMessage(this, "(İsteğe bağlı) Makale grubunun önemini giriniz. Makaleler görüntülenirken önem derecesi değerlendirilir."); });
$("#resimYolu").focus(function () { ShowMessage(this, "Makale Grubunda görüntülenmesini istediğiniz Resmin web url adresini giriniz"); });
$("#tanimi").focus(function () { ShowMessage(this, "Kullanıcıların görebilmesi için kısa bir tanımlama giriniz"); });

 
    1. Aşağıdaki 3 fonksiyon title, imageUrl, and description alanlareının doğrulanmasından emin olabilmeyi sağlamaktadır.

function ValidateTitle () {
return VerifyRequiredField("#baslik", "lütfen değer giriniz");
}
function ValidateImageUrl () {
return VerifyRequiredField("#resimYolu", "lütfen değer giriniz");
}
function ValidateDescription () {
return VerifyRequiredField("#tanimi", "lütfen değer giriniz");
}

  1. ValidateCategory metodu da tüm doğrulamalarda kullanılır bu formumuzun içinde ve eğer tüm doğrulamalar herhangi bir problem oluşmamış ise işlemin devam etmesine izin verir ancak herhangibir hata oldu ise sistem yapılan işlem durdurulur ve bir hata mesajı gösterilir.

f

unction ValidateCategory () {
var validTitle = ValidateTitle();
var validImage = ValidateImageUrl();
var validDescription = ValidateDescription();
return validTitle && validImage && validDescription;
}
$("form.category-create").validate(ValidateCategory);

MakaleGrupSil.Cshtml Kontrolü

Bu view ~ /Views/Makale klasöründe bulunmaktadır. Bu view yetkisi editör ve admin olan kullanıcılara makale gruplarını silebilmelerine olanak sağlamaktadır. View'ın görünümü aşağıdaki gibidir.

Şekil –18


Temel İçerik

Bu view bir evet bir de hayır butonu içierir ayrıca silenebilecek olan kategorilerin listesini de içerir. Bu evet butonu silmek istediğimizi onaylamak için hayır ise silmek istemimizden vazgeçttiğimizi belirtmek içindir.

@if (ViewData.Model != null) {
<form method="post" action="@Url.Action("MakaleGrupSil", "Makale", new { makaleGrupID= ViewData.Model.MakaleGrupID}) " class="category-remove">
<p><label for="categoryId">Makaleleri kaynak gruptan taşı: <em>@ViewData.Model.Baslik </em> Hedef gruba:</label><br />
@Html.DropDownList("yeniMakaleGrupID")
<span></span></p>
<button type="submit" name="sil" value="evet">evet</button>
<button type="submit" name="sil" value="hayir">hayir</button>
</form>
}

Kodlarda her iki buton da aynı isme sahiptir bunun nedeni o butonlardan sadece bir anesinin bir değer gönderebilmesini sağlamak içindir.

CSS

CSS butonların renklerini ayarlanma noktasında ihtiyacımız olmaktadır.

button.yes {
background-color: #DB0000;
color: #ffffff;
font-weight: bold;
width: 75px;
margin: 0 5px;
}
button.no {
background-color: #00DB00;
color: #ffffff;
font-weight: bold;
width: 75px;
margin: 0 5px;
}

MakaleItem.cshtml Kontrolü

Daha öncede değinidiğmiz gibi, bu code MakaleYonet.cshtml view sayfasındaki ve son kullanıcı Index.cshtml sayfasındaki makaleleri listeler, bu sayfalar kendi kendilerine sayfadaki yerine yerleşmez ancak ayrı bir kullanıcı kontrol tarafınfan çağırılır. Bu dosya yerel olarak ~/Views/Shared/Makale/MakaleItem.cshtml sayfasındadır. Bu kontrol tüm kategoriler için yada seçilmiş bir kategori için tüm makalelerin belirtilen özelliklerini aşağıdaki resimdeki gibi liste halinde sayfalar.

Şekil –19


Bu kontrol bir öncekine göre biraz daha farklı çünkü bu bizim için yararlı bir metot içerir ki bu, genel olarak oran hesaplamak için puanlamada kullanılır.

public string ResimOyUrl = "/Content/images/stars35.gif" ;
{
public string ResimOyUrl
{
get
{
double value = ViewData.Model.OrtalamaOran;
string url = "/Content/images/stars{0}.gif";
if (value <= 1.3)
url = String.Format(url, "10");
else if (value <= 1.8)
url = String.Format(url, "15");
else if (value <= 2.3)
url = String.Format(url, "20");
else if (value <= 2.8)
url = String.Format(url, "25");
else if (value <= 3.3)
url = String.Format(url, "30");
else if (value <= 3.8)
url = String.Format(url, "35");
else if (value <= 4.3)
url = String.Format(url, "40");
else if (value <= 4.8)
url = String.Format(url, "45");
else
url = String.Format(url, "50");
return url;
}
}

ResimOyUrl bize makale ile bir resimin yolu için yardımcı olurak kullanılır. Ayrıca oylama için rakanm kullanmak yerine grafiksel çizim kullanamak daha uygundur. MakaleItem.cshtml ‘de view sayfasında gösterilmesini istediğimiz özellikler ayarlanmaktadır. Bizim istediğimiz özelliklerin html kısmı aşağdaki gibidir.

@model KarayelTasarim.Models.Makaleler
<div id="article-@ViewData.Model.MakaleID" class="article">
<img src="@ViewData.Model.MakaleGrup.ResimYolu" class="category-image" title="@Model.MakaleGrup.Baslik" alt="makale" />
<h3>@Html.ActionLink(ViewData.Model.Baslik, "MakaleGoruntule", new { controller = "Makale", id = ViewData.Model.MakaleID, yol = ViewData.Model.Yolu })</h3>
<p>@( !(String.IsNullOrEmpty(ViewData.Model.Ozet)) ? Model.Ozet : Model.Icerik) </p>
<ul>
<li><strong>Oy Oranı: </strong>@ViewData.Model.Oy tarafından oylandı @if (ViewData.Model.OrtalamaOran > 0) { <img src="/Content/images/stars35.gif" alt="@ViewData.Model.OrtalamaOran" /> } </li>
<li><strong>Ekleyen Kullanıcı: </strong>@ViewData.Model.Ekleyen</li>
<li><strong>Görüntüleme</strong>Bu makale @ViewData.Model.OkunmaSayisi kez okunmuştur</li>
<li><strong>Lokasyon :</strong>@ViewData.Model.Location</li>
<li><strong>Yayın Tarihi :</strong>@ViewData.Model.EklemeTarihi</li>
</ul>
</div>

Bİr sonraki adımda ise her bir makaklelenin CSS ayarlamasını yapmalıddır.

.article {
min-height: 91px;
}
.article h3 {
font-size: 1.3em;
}
.article .category-image {
float: right;
margin: 5px;
}

MakaleYonet.cshtml View

Bu view de ~/Views/Article dosyası konumunda bulunmaktadır. Yönetici veya editör olan kulanıcılaların makale düzenleme ve silme işlemlerinin gerçekleştirebilmesi için makalelerin listelenerek gösterildiği view'dır. Şekil de ne yapacağımızın örnek bir gösterimi yer almaktadır.

Yorum sınıfı

Şekil –20


Daha öncede MakaleGrup.cshtml view'ında yapmış olduğumuz gibi makalelerin gösterimi içn bir foreach döngüsü kullanılmaktadır. Düzenle ve silme linkleri makalenin sağında yer almaktadır. Düzenle linki makaleDuzenle action metoduna gönderirken Sil linki

MakaleSil action metoduna göndermektedir. MakaleYonet view'ının iki alanı master page uygular bunlar: MainContent and SidebarContent dir.

Temel İçerik

Temel içerik alanı Html.ActionLink metodu kullanılarak duzenle ve sil linklerini oluşturulur.

<div id="articles">
@{ foreach (KarayelTasarim.Models.Makaleler makale in ViewData.Model)
{
<div>@Html.ActionLink("Düzenle", "MakaleDuzenle", new { controller = "Makale", makaleId = makale.MakaleID }) | @Html.ActionLink("Sil", "MakaleSil", new { controller = "Makale", makaleID = makale.MakaleID })</div>
<hr />
@Html.Partial("~/Views/Shared/Makale/MakaleItem.cshtml", makale)
} }

MakaleEkle.cshtml View

Bu .chstml sayfası editörle ve yazarların yeni bir makale ekleyebilmek veya oluşturulmuş olan makaleyi düzemlemek için kullanılmaktadır. Eğer kullanıcı oluşturulmuş olan olan makaleyi düzenlemek isterse aşağıdaki resimde olduğu gibi bi düzenleme modu karşısına çıkmaktadır. Ancak yönetici veya editor yetkisine sahip olan kullanıcılar bu sayfayı görebilmektedir. Bunun güvenliği web.config bölümünden sağlanmaktadır.

Şekil –21


Bu resimden tahmin edebileceğin gibi formda fieldlerin gösterimi için MakaleGupEkle view'ındaki gibi benzer metotlar kulanılır. BODY alanı open-source TİnyMCE editorunu kullanır. Bu TİnyMCE editörün yonet-makale .js dosyasında tanımlı olarak bulunmaktadır.

TinyMCE yi kumak için onu http://tinymce.moxiecode.com adresinden indirebilirsiniz

var __editorConfig = {
mode: "textareas",
theme: "advanced",
plugins: "advhr,advimage,advlink,contextmenu,inlinepopups,media,paste,safari,
spellchecker,xhtmlxtras",
theme_advanced_toolbar_location: "top",
theme_advanced_toolbar_align: "center",
theme_advanced_statusbar_location: "bottom",
theme_advanced_resizing_use_cookie: false,
theme_advanced_resize_horizontal: false,
theme_advanced_resizing: true,
theme_advanced_resizing_min_height: 200,
convert_urls: false,
gecko_spellcheck: true,
dialog_type: "modal",
paste_auto_cleanup_on_paste: true,
paste_convert_headers_to_strong: true,
paste_strip_class_attributes: "all"
};

Temel İçerik

Bu kısımda makale oluşturmak için yada makale yüzenlemek için gerekli olan alanları oluşturulmaktadır. Bu alanlar MakaleGrup view'ındakine benzer bie şekilde olşturulmaktadır.

<form method="post" action="@Url.Action(this.ViewContext.RouteData.Values["action"] as string, "Makale")">

<h3>Makale</h3>

<p><label for="refMakaleGrupId">Makale Grup</label><br />

@Html.DropDownList("RefMakaleGrupID")
<span></span></p>
<p><label for="baslik">Başlık</label><br />
@Html.TextBox("baslik", ViewData["baslik"], new { @maxlength = 256 })
<span></span></p>
<p><label for="ozet">Özet</label><br />
@Html.TextArea("ozet")
<span></span></p>
<p><label for="icerik">İçerik</label><br />
@Html.TextArea("icerik", new { style = "height: 500px" })
<span></span></p>
<h3>Veri Hakkında Bilgi</h3>
<p><label for="ulke">Ulke</label><br />
@Html.DropDownList("ulke")
<span></span></p>
<p><label for="ilce">İlçe</label><br />
@Html.TextBox("ilce", ViewData["ilce"], new { @maxlength = 256 })
<span></span></p>
<p><label for="sehir">Şehir</label><br />
@Html.TextBox("sehir", ViewData["sehir"], new { @maxlength = 256 })
<span></span></p>
<p><label for="yayinTarihi">Yayinlama Tarihi</label><br />
@Html.TextBox("yayinlamaTarihi")
<span></span></p>
<p><label for="yayinSonu">Yayınlama Sonu</label><br />
@Html.TextBox("yayinlamaSonu")
<span></span></p>

Şimdi tüm alanlar makale için gerekli sçenekleri barındıracak şekilde oluşturlmuş oldu. Aşağıdaki koduda yukarıdaki kodun bir altına yazarak bu sayfada sadece yönetici ve editörlerin düzenleme yapabileceği anlamına getirilmelidir.-

@if (Roles.IsUserInRole("Editor")) {
<h3>Seçenekler</h3>
<p><ul class="options">
<li>@Html.CheckBox("onay") <label for="onay">Yayınlanması için onay verildi</label></li>
<li>@Html.CheckBox("listeOnay") <label for="listeOnay">Listelenebilir</label></li>
<li>@Html.CheckBox("yorumaAcik") <label for="yorumaAcik">Yorum yapılabilir</label></li>
<li>@Html.CheckBox("yalnizcaUyeler") <label for="yalnizcaUyeler">Yalnızca üyeler okuyabilir</label></li>
</ul>
<span></span></p>
}
<hr />

Son olarak submit butonu eklenmelidir. Daha öncede oluşturduğumuz MakaleGrup view'ındaki gibi submit butonu isimlendirmesinde özel bir durum bulunmaktadır. Şöyle ki;

Makale eklemek ve makale güncelemek için tek bir view oluşturduğumuz için buton isimleride değişiklik göstermek zorundadır. Bu durumda buton isimlerini sayfada yapılacak olan işleme göre değiştirmeliyiz. Kodda budurumu aşağıdaki gibi kontrol edebiliriz.

@if(this.ViewContext.RouteData.Values["action"] as string == "MakaleDuzenle") {
<p><button type="submit" id="article-create-button">Makale Güncelle</button></p>
} else {
<p><button type="submit" id="article-create-button">Makale Ekle</button></p>
}
</form>

Scriptİçerik

Script içerikte master page için tiny_mce_src.js and managearticles.js yi eklemeye ihtiyacın vardır. Çünkü TinyMCE Rich Text Editore uygun kaynağı eklememiz gerekmeketedir.

@section ScriptContent {
<script type="text/javascript" src="/Content/Scripts/tiny_mce/tiny_mce_src.js"></script>
<script type="text/javascript" src="/Content/Scripts/yonet-makale.js"></script>
@if (IsPostBack) {
<script type="text/javascript">
ValidateArticle();
</script>
}

Yonet-makale.js

Bu ksımın ilk başlarında bilgi ve doğrulamak için codelar bululnur biz daha önce benzer açıklamayı Yonet-makalegrup.js. kısmında yapmıştık.

$("#baslik").focus(function () { ShowMessage(this, "Makalenizin içeriğini tanımlayan kısa bir başlık giriniz."); });
$("#ozet").focus(function () { ShowMessage(this, "(İsteğe bağlı) Ön görünüm için, özet içerik giriniz."); });
$("#icerik").focus(function () { ShowMessage(this, "Makalenizin içeriğini giriniz."); });
$("#ulke").focus(function () { ShowMessage(this, "(İsteğe bağlı) Ülke giriniz."); });
$("#ilce").focus(function () { ShowMessage(this, "(İsteğe bağlı) İlçe giriniz."); });
$("#sehir").focus(function() { ShowMessage(this, "(İsete bağlı) Şehir giriniz.."); });
$("#yayinTarihi").focus(function () { ShowMessage(this, "(İsteğe bağlı)Makalenizin yayınlanmasını istediğiniz tarihi giriniz. Eğer boş bırakırsanız bugün yayınlanır."); });
$("#yayinSonu").focus(function () { ShowMessage(this, "(İsteğe bağlı) Makalenizin yayından kaldırılmasını istediğiniz tarihi giriniz."); });
function ValidateTitle () {
return VerifyRequiredField("#baslik", "Lütfen bir değer giriniz");
}
function ValidateBody () {
return VerifyRequiredField("#icerik", "Lütfen bir değer giriniz");
}
function ValidateArticle () {
return ValidateTitle()
&& ValidateBody();
}
$("form.article-create").validate(ValidateArticle);

Yonet-Makale.js'in içeriğinin diğer yarısı TinyMCE editörü içindir. Bu rası dikkat edilmesi gereken, bir kısımdır. Çünkü bu js kodları olmazsa TinyMCE editörü kullanılamaz.

Öncelikle bu kodun ilk başında bodyEditor adında bir değişken oluşturulur. Çünkü içerik alanı bu değişken sayesinde yönetilecektir. Daha sonra bu işlemrin bir kısmı onClick ve Onchange olalayları ile bağlanmalıdır. Çünkü veride değişiklik olduğu vakit bunun textarea'nın içerisinde gözükmelidir. Bu adım çok önemlidir. Çünkü zengin text editör gerçekten bir iframe gibidir. Bu yüzden yapılan değişiklikler textarea'nın içine Html şeklinde olarak yazılırlar. Fakat kaydedilene kadar, bu html kodlarını içine aktarmaz. Yazılması gereken kod aşağıdaki gibidir.

var bodyEditor;
$(document).ready(function () {
bodyEditor = new tinymce.Editor("icerik", __editorConfig);
bodyEditor.onChange.add(function (ed) { bodyEditor.save(); });
bodyEditor.onClick.add(function(ed) { ShowMessage("#icerik", "Lütfen makale içeriğini yazınız"); });
bodyEditor.render();
});

Çünkü bodyEditor iframe gibi bir TinyMCE nesnesidir. Kullanıcı için zengin textBox ve input alanları mevcuttur. Bu alanların birbiri ile başarılı bir şekilde haberleşmesi gerekmektedir. Çünkü form alanlarında verecekleri yardımcı bilgiler duruma göre değişiklik gösterecektir. Bu yardımcı bilgilerin doğru çalışabilmesi için input alanları onChange rich TextBox ise onClick olayı ile bağlanmalıdır. Ayrıca bu sayede blur olayıda gerçekleşmeiş olur.

Gerekli olan js kodlarının devamı aşağıdaki gibidir.

// başka bir nesneye focus olduğunda mevcut bilgileri temizle.

$(":input")

.focus(function () { HideMessage("#icerik"); })

.blur(function () { HideMessage("#icerik"); });

MakaleSil.cshtml View

MakaleSil.cshtml sayfası makalegrupsil.cshtml sayfası ile yapı bakımından hemen hemen aynıdır. Yine makalesil view'ı makalegrupsil.cshtml sayfasında olduğu gibi veri tabanından herhangi bir veri silmek istenildiğinde sil butonuna tıklandığında “silmek istediğinizden eminmisin” şeklinde bir soru ile doğrudan bağlantılıdır. Eğer evet butonuna tıklarsak silmek istediğimiz veri ve bu veriye yapılmış olan yorumların tamamı silinecektir. Hayır butonuna tıklarsak veritabanında herhangi bir değişiklik olmadan bizi makalesil.cshtml sayfasına yönlendirecektir.

Şekil –22


Temel İçerik

Makalesil.cshtml'in temel içerik kısmı oldukça basittir. Bu form bir evet bir de hayır butonu ve birde bir mesaj penceresine sahiptir. Eğer Sil butonuna tıkladığınızda gerçekten veri tabanında böyle bir veri varsa karşımıza iki resideki gibi iki buton ve bir bilgi penceresi açılacaktır. Bu evet butonu silmek isteiğimizi onaylamak için hayır ise silmek istemimizden vazgeçttiğimizi belirtmek içindir.

@if (ViewData.Model != null) {
<form method="post" action="@Url.Action("MakaleSil", "Makale", new { makaleGrupID = ViewData.Model.MakaleID }) ">
<button type="submit" name="sil" value="evet" class="yes">Evet</button>
<button type="submit" name="sil" value="hayir">Hayır</button>
</form>
}

MakaleYorumitem.cshtml

MakaleYorumitem.cshtml kontrol dosyası, ~/Views/Shared/Makele konumunda yer alan diğer dosyalar ile birlikte oluşturulmuştur. Bu kontrol yorum nesnesinin belirtiklerini view'da göstermek için kullanılmaktadır.

Şekil –23


Bu wiew iki body ve header olamak üzre iki adet html elemanı içermektedir. Bu elemanlar code-behind'da aşağıdaki gibi gözükmektedir.

@model KarayelTasarim.Models.MakaleYorumlari
<div id="comment-@ViewData.Model.MakaleYorumID" class="comment">
<div>Bu yorum <span>@ViewData.Model.Ekleyen</span> tarafından @(DateTime.Now - ViewData.Model.EklemeTarihi).ToLongString() tarihinde eklendi</div>
<blockquote>@Model.Icerik </blockquote>
</div>

İhtiyacımız olan gerekli CSS kodları aşağıdaki gibidir.

MakaleYorumYonet.cshtml

Bu .cshtml dosyası ~/View/Makale/ klasörünün içerisinde bulunmaktadır. Bu sayfada bütün makalelerin tüm yorumları en yeniden en eskiye sıralanmış biçimde gösterilir. Ayrıca Editör veya admin olan kullanıcılar silme ve düzenleme işlemlerine izin verilir. Sayfada AJax dili sayesinde yorumların düzenlenmesine izin verilir. Bu sayfa makale grupları ve makaleler view'larından biraz farklıdır. Fakat yorumların listelendiği sayfanın görünüşü oldukça güzeldir.

Birkaç Java script ve Ajax kodu, yorumların içeriğini ve başlığını değiştirilebilmesini sağlamaktadır. Yorumların silinme işlemleri, içinde Ajax kullanılır. Zaten biz bu kısımların nasıl olması gerekdiğini Analiz bölümünde, karar vermiştik.

Yorum Silme İşlemi

Yorum silme scripti MakaleYorumYonet sayfasındasi tüm sil linkinin tıklanma olayı ise doğrudan bağlantılıdır. Bu linke tıkladığınız anda tıkladığınız yorumun Id'si silinmek üzere /makale/makalesil sayfasına gönderilir. Daha sonra server dan alınan bu link HtmlDom'dan veri tabanından silinir.

$(".remove-comment").click(function () {

var id = $(this).attr("meta:id");

$.post(

"/makale/YorumSil",

{ yorumID: id },

function (data) {

$("#comment-" + data.object.yorumId).next(".admin").fadeOut("slow", function () { $(this).remove() });

$("#comment-" + data.object.yorumId).fadeOut("slow", function () { $(this).remove() });

},

"json"

);

return false;

});

$(".remove-comment").click(function () {
var id = $(this).attr("meta:id");
$.post(
"/makale/YorumSil",
{ yorumID: id },
function (data) {
$("#comment-" + data.object.yorumId).next(".admin").fadeOut("slow", function () { $(this).remove() });
$("#comment-" + data.object.yorumId).fadeOut("slow", function () { $(this).remove() });
},
"json"
);
return false;
});

Yorum düzenleme işlemi aynı yorum silme işlemindeki gibidir. Bununla birlikte linke tıkladığınızda yorum başlığı ve içeriği gözükmez ve Yorumun başlığı ve gönderenin ismi gibi bilgileri direk formdan alırlar. .Eğer iptal dersek yapılan değişklikler kaydedilmez ve eğer güncelle dersek yapılan değişiklikleri veri tabanına kaydeilir.bu işlemlerin kod dökümü aşağıdaki gibidir.

$(".edit-comment").click(function () {
var id = $(this).attr("meta:id"),
comment = $("#comment-" + id),
bodyText = comment.find(".body").text(),
nameText = comment.find(".name").text();
// butun coukları sakla
comment.children().hide();
var commentText = "";
commentText += "<form><div class=\"comment-header field\"><label for=\"name-" + id + "\">Yorumlayan </label><br/><input type=\"text\" id=\"name-" + id + "\" class=\"edit-name\" value=\"" + nameText + "\" /></div>";
commentText += "<div class=\"field\"><label for=\"body-" + id + "\">Yorum İçeriği</label><br/><textarea class=\"edit-body\" id=\"body-" + id + "\">" + bodyText + "</textarea><br/><button type=\"button\" class=\"update\" meta:id=\"" + id + "\">Güncelle</button> <button type=\"button\" class=\"cancel\">Vazgeç</button></div></form>";
var commentForm = $(commentText);
// formu guncelle
commentForm.find(".update").click(function () {
var id = $(this).attr("meta:id");
var nameFormText = $(this).prevAll(".edit-name").val();
var bodyFormText = $(this).prevAll(".edit-body").val();
$.post(
"/makale/YorumDuzenle",
{ yorumId: id, adi: nameFormText, icerik: bodyFormText },
function (data) {
var comment = $("#comment-" + data.object.yorumId);
comment.children("form").remove();
comment.children(".body").text(data.object.body);
comment.children(".name").text(data.object.name);
comment.children().show();
},
"json"
);
});
// guncelleme işleminden vazgeç
commentForm.find(".cancel").click(function () {
$(this).parents(".comment").children(":hidden").show();
$(this).parents("form").remove();
});
// mevcut yoruma form ekle
comment.append(commentForm);
return false;
});

MakaleGrupIndex.cshtml View

Son kullanıcı için bu modulün ilk sayfasıdır. Ayrıca sitenin root dosyasında bulunur. Bu sayfanın tek hedefi kullanıcya makalelerin makale gruplarını hoş ve temiz bir formatta sunmaktır.

Index.cshtml View

Bu makaleYonet.cshtml'in sayfasının son kullanıcıya gösteriliş versiyonudur. Bu sayfa sadece yayınlnmış olan makaleleri gösterir.

MakaleGoruntule.cshtml View

Bu son kullanıcının makaleleri tüm ayrıntılarıyla görebileceiği bir ksımdır

(Yayınlanma tarihi, okunma sayısı, vb). Aşağıdaki resimde bu sayfanın ekran görüntüsü gösterilmektedir. Hoş ve sade bir görünündür.

Şekil –24


Resimin altında oylamayı ve oylamanın altında da yorumlar bulunmaktadır. En üstte ise makale ile ilgili bilgiler yer aldığı bir üst bilgi bloğu bulunmaktadır.

<form method="post" action="#">
<p>
<h3><label for="rating">Bu makaleye oy vermek ister misiniz?</label></h3>
<br />
<select name="rating" id="rating">
<option value="0">0 Yıldız</option>
<option value="1">1 Yıldız</option>
<option value="2">2 Yıldız</option>
<option value="3">3 Yıldız</option>
<option value="4">4 Yıldız</option>
<option value="5">5 Yıldız</option>
</select>
<button type="submit" id="rate-button">Oy</button>
</p>
</form>

MakaleGoruntule.cshtml sayfasında gösterilen makele için onaylı olan yorumlar da gösterilmelidir. Ve bunun gerekli olan .cshtml kodu aşağıdaki gibidir.

@if (ViewData.Model.YorumaAcik)
{
<div id="article-comments">
<h3>Yorumlar</h3>
@foreach (KarayelTasarim.Models.MakaleYorumlari yorum in ViewData.Model.MakaleYorumlaris) {
@Html.Partial("~/Views/Shared/Makale/MakaleYorumItem.cshtml", yorum)
}
</div>
<form method="post" action="#">
<input type="hidden" id="articleId" name="articleId" value="@ViewData.Model.MakaleID" />
<input type="hidden" id="commentId" name="commentId" value="" />
<p>
<label for="name">Adı</label><br />
@Html.TextBox("comment-name", null, new { @maxlength = 256 })
<span></span>
</p>
<p>
<label for="email">E-Mail</label><br />
@Html.TextBox("comment-email", null, new { @maxlength = 256 })
<span></span>
</p>
<p>
<label for="body">İçerik</label><br />
@Html.TextArea("comment-body", String.Empty)
<span></span>
</p>
<hr />
<p>
<button type="submit" id="comment-create-button">Yorum Ekle</button></p>
</form>
}

Makale Oylama

Bu kısımda yapılması gereken ilk şey java script kodu ile her nakalenin altında bulunan oy kullanabilmek için gerekli olan submit butonunu birbiriyle ilişkisinin kurumasıdır. Daha sonra kullanıcı bu butona her tıkladığında Ajax sayesinde gerekli olan bilgiler bu bölümün başında oluşturulan MakaleOranla action metoduna gönderilerek orada işlenir.

$("form.rate-article").submit(function () {
$.post(
"/makale/makaleOranla",
{  makaleId: $("#articleId").val(),
oran: $("#rating").val() },
MakaleOylamaBasarili,
"json"
);

Aşağıda yapılan oylamaya göre oluşan istatiksel durumun belirnebilmesi gereken kod parçacığı bulunmaktadır..

function MakaleOylamaBasarili (data) {
var value = data.object.averageRating;
var imagePosition = "50";
if (value <= 1.3)
imagePosition = "10";
else if (value <= 1.8)
imagePosition = "15";
else if (value <= 2.3)
imagePosition = "20";
else if (value <= 2.8)
imagePosition = "25";
else if (value <= 3.3)
imagePosition = "30";
else if (value <= 3.8)
imagePosition = "35";
else if (value <= 4.3)
imagePosition = "40";
else if (value <= 4.8)
imagePosition = "45";
$("#article-rating-value")
.replaceWith("<img src=\"/Content/images/stars" + imagePosition + ".gif\" alt=\"" + value + "\" />");
$("form.rate-article :input").attr("disabled", "true");
$("form.rate-article").append("Verdiğiniz oy değerlendirildi!");
}

Makale Ekleme

Oylama da olduğu gibi iki metodu bulunmaktadır. Birinci metot farklı zamanlarda verileri kaydetme diğeri ise geri dönüşü anında almaktır. Bu kısımda gerekli olan birkaç yer vardır. ancak bunların hep anlatılmayacaktır. Çünkü zaten bu javascript kodu gerekli olan form alanlarını içermektedir.

$("form.comment-create").submit(function () {
var valid = ValidateCommentName()
&& ValidateCommentEmail()
&& ValidateCommentBody();
if (valid) {
$.post(
"/makale/YorumEkle",
{ makaleId: $("#articleId").val(),
adi: $("#comment-name").val(),
email: $("#comment-email").val(),
icerik: $("#comment-body").val() },
CreateCommentSuccess,
"json"
);
}
// submite izin verme bu bir ajax isteği
return false;
});
The callback metodu yeni oluşturulan yorumların sayfada oluşturmak oluşturulan methodların sayfada listelenmesi için kullanılır eklenir.
function CreateCommentSuccess (data, textStatus) {
$(".new-comment").removeClass("new-comment").show("normal");
var commentText = "";
commentText += "<div id=\"comment-" + data.object.yorumID + "\" class=\"comment new-comment\">";
commentText += "<div class=\"comment-header\">Bu yorum " + data.object.adi + " tarafından 0 saniye önce yazıldı</div>";
commentText += "<blockquote>" + data.object.icerik + "</blockquote>";
commentText += "</div>";
var comment = $(commentText);
// icerik utusunu temizle
$("#comment-body").val("");
// diger yorumlara yorum ekle
comment
.hide()
.appendTo("#article-comments")
.slideDown("slow");
}

ÖZET

Bu bölümde karmaşık olan makale modulünü tamamlamış bulunmaktayız. Bu anlaşılması güç olan makale modulünü iyi anlamanız önemlidir. Çünkü diğer modulleri anlamanız oldukça kolay olacaktır. Yine bölümde module gerekli olan javascript kodları eklenmiş kodların ne işe yaradıkları anlatılmıştır.

Bu bölüm süresince aşağıdaki unsurlar yapılmıştır.

  • Yönetim bölümünde veri tabanındaki verileri yönetilebilme
  • Tarayıcılar için sayfalarca içerik yayınlayabilme silebilme
  • Üyelik sistemi ile makale modulü güvenlik açısından birbiri ile birleştirilmiştir

Bir sonraki bölümde her sitede bulunması artık zorunlu hale gelmiş olan kolayca silinebilen eklenebilen ve gösterile bilen anket yönetimi anlatılacaktır.

Bölüm 6 ilgili soru ve önerileriniz için yorum yazmayı unutmayınız. iyi çalışmalar dileriz.

Kod indir : Bölüm 6 dahil

Altıncı Bölüme Yardımlarından Dolayı İbrahim Uğur YILMAZ'a Teşekkür Ediyorum.

Yorumlar

İsim: uğur

Tarih: 21.12.2018 22:08:16

ASP.Net MVC KİTABI BÖLÜM 6 kaynak kodları silinmi makalenin gönderebilirmisiniz tşk

İsim:

Tarih: 2.03.2019 18:45:41

Yayıncı kuruluş kitabın internet üzerinde yayınlanmasını istemiyor.


Yorum Yaz

Yorumlarınız denetimden geçtikten sonra yayınlanmaktadır...