4. Bir eylemin modeli
ASP.NET ve MVC uygulamalarının mimarisine geri dönelim:
![]() |
Önceki bölümde, [1] isteğini, onu işleyecek olan denetleyiciye ve eyleme ([2a]) yönlendiren süreci inceledik; bu mekanizmaya yönlendirme denir. Ayrıca, bir eylemin tarayıcıya verebileceği farklı yanıtları da ele aldık. Şu ana kadar, kendilerine sunulan isteği kullanmayan eylemleri inceledik. Bir [1] isteği, ASP.NET ve MVC tarafından [2a]'e bir şablon biçiminde sunulan çeşitli bilgileri beraberinde taşır. Bu terim, eylem tarafından üretilen bir V [2c] görünümünün M şablonu ile karıştırılmamalıdır:
![]() |
- Müşterinin HTTP isteği, [1] olarak gelir;
- [2] aşamasında, istekte yer alan bilgiler [3] eylem şablonuna dönüştürülür; bu, genellikle (ancak zorunlu olarak değil) [4] eylemine girdi olarak hizmet edecek bir sınıftır;
- [4]'te eylem, bu şablondan yola çıkarak bir yanıt oluşturacaktır. Bu yanıtın iki bileşeni olacaktır: bir V görünümü ([6]) ve bu görünümün M şablonu ([5]);
- V [6] görünümü, müşteriye yönelik HTTP yanıtını oluşturmak için kendi M modeli olan [5]'i kullanacaktır.
MVC modelinde, [4] eylemi C'nin (denetleyici) bir parçasıdır; [5] görünüm modeli M'dir ve [6] görünümü V'dir.
Bu bölümde, doğası gereği karakter dizileri olan istek tarafından taşınan bilgiler ile çeşitli türlerde özelliklere sahip bir sınıf olabilen eylem modeli arasındaki bağlantı mekanizmaları incelenmektedir.
4.1. Eylem parametrelerinin başlatılması
Mevcut çözüme, temel proje olan MVC'e yeni bir proje olan ASP.NET'i ekliyoruz:
![]() |
![]() |
- [2] olarak yeni projenin adını belirledik;
- [3, 4]'te, temel proje olarak ASP.NET ve MVC'i seçiyoruz;
- [5]'te, yeni proje.
Yeni projeyi, çözümün başlangıç projesi yapacağız.
3.1. paragrafta yapıldığı gibi, [First] [1] adlı bir denetleyici oluşturuyoruz:
![]() |
Bu denetleyicide, aşağıdaki [Action01] eylemini oluşturacağız:
using System.Web.Mvc;
namespace Exemple_02.Controllers
{
public class FirstController : Controller
{
// Eylem01
public ContentResult Action01(string nom)
{
return Content(string.Format("Contrôleur=First, Action=Action01, nom={0}", nom));
}
}
}
Yenilik 8. satırda yer almaktadır: [Action01] yöntemi bir parametreye sahiptir. Bu bölümde, bir eylemin parametrelerini başlatmanın farklı yolları ele alınacaktır. Yukarıdaki [nom] parametresi, sırasıyla aşağıdaki değerlerle başlatılır:
Request.Form["nom"] | POST komutu tarafından gönderilen [nom] adlı bir parametre |
RouteData.Values["nom"] | URL adlı bir öğe, [nom] |
Request.QueryString["nom"] | GET komutu tarafından gönderilen, [nom] adlı bir parametre |
Request.Files["nom"] | [nom] adlı bir dosya yüklendi |
Bu farklı durumları inceleyelim. Tarayıcıda doğrudan URL [/First/Action01?nom=someone] adresini gidelim. Aşağıdaki yanıtı alırız:
![]() |
Tarayıcıdan gelen HTTP isteği şöyleydi:
- 1. satır: İstek, GET şeklindedir. İstenen URL, [nom] parametresini içerir. Sunucu tarafında, istek aşağıdaki imzaya sahip [Action01] eylemine ulaşır:
public ContentResult Action01(string nom)
"nom" parametresine bir değer atamak için, ASP.NET MVC, sırasıyla ve sırayla Request.Form["nom"], RouteData.Values["nom"], Request.QueryString["nom"], Request.Files["nom"] değerlerini sırayla dener. Bir değer bulur bulmaz durur. GET'in URL'inde yer alan [nom] parametresi, çerçeve tarafından Request.QueryString["nom"]'e yerleştirilmiştir. [Action01]'teki [nom] parametresi, bu [someone] değeriyle başlatılacaktır. Ardından [Action01]'teki kod çalıştırılır:
return Content(string.Format("Contrôleur=First, Action=Action01, nom={0}", nom), "text/plain", Encoding.UTF8);
Bu kod, istemciye gönderilen yanıtı sağlar:
![]() |
Not: Parametre bağlama mekanizması büyük/küçük harf duyarlı değildir. Dolayısıyla, eylemimiz şu şekilde tanımlanmışsa:
public ContentResult Action01(string NOM)
ve aktarılan parametre [?NoM=zébulon] ise, eşleştirme başarıyla gerçekleşecektir. [NOM] parametresi, [Action01]'ten [zébulon] değerini alacaktır.
Şimdi, POST ile aynı URL'i talep edelim. Bunun için [Advanced Rest Client] uygulamasını kullanıyoruz:
![]() |
- [1]'e dönüştürürken, istenen URL;
- [2]'te, POST komutu kullanılacak;
- [3]'te, POST'in parametreleri.
Bu isteği gönderelim ve HTTP günlüklerine bakalım. HTTP isteği şu şekildedir:
![]() |
- [1]'te, POST;
- [2]'te, POST'in parametreleri yer alıyor. Teknik olarak, bu parametreler, başlıkların sonunu belirten boş satırdan sonra HTTP başlıklarının arkasına gönderilmiştir;
- [3]'te ise alınan yanıt yer almaktadır. POST'ten [nom] parametresi doğru bir şekilde alınmaktadır. Request.Form["nom"], RouteData.Values["nom"], Request.QueryString["nom"], Request.Files["nom"] değerleri arasında ilk denenen değer işe yaradı.
Şimdi, [App_Start/RouteConfig] dosyasındaki varsayılan rotayı değiştirelim. Şu anda bu rota şu şekildedir:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
Bunu şu şekilde değiştirelim:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{nom}",
defaults: new { controller = "Home", action = "Index", nom = UrlParameter.Optional }
);
- 3. satırda, bir rotanın üçüncü öğesine [nom] adını verdik;
- 4. satırda, bu öğe isteğe bağlı olarak tanımlanmıştır.
Şimdi uygulamayı yeniden derleyelim ve URL [/First/Action01/zébulon]'i doğrudan tarayıcıda isteyelim. Aşağıdaki yanıtı alıyoruz:
![]() |
"name" parametresi için denenen değerler arasında Request.Form["nom"], RouteData.Values["nom"], Request.QueryString["nom"], Request.Files["nom"] değerleri arasında ikinci değer işe yaradı.
Aynı sorguyu POST ve [Advanced Rest Client] ile yapalım:
![]() |
- [1]'te, yolun {nom} öğesine bir değer verdik;
- [2]'te, gönderilen isteğe [nom] parametresi eklenir;
- alınan yanıt [3] şeklindedir.
[nom] parametresi için denenmiş değerler arasında Request.Form["nom"], RouteData.Values["nom"], Request.QueryString["nom"], Request.Files["nom"] değerlerinden ikisi, yani ilk ikisi uygun çıktı. İlk değer kullanıldı.
4.2. Eylemin parametrelerinin geçerliliğini kontrol etme
Bir eylemde [p] adlı bir parametre varsa, ASP.NET ve MVC, bu parametreye Request.Form["p"], RouteData.Values["p"], Request.QueryString["p"], Request.Files["p"] değerlerinden birini atamaya çalışacaktır. İlk üç değer karakter dizileridir. [p] parametresinin türü [string] değilse, sorunlar ortaya çıkabilir.
Şu yeni eylemi oluşturalım:
// Eylem02
public ContentResult Action02(int age)
{
string texte = string.Format("Contrôleur={0}, Action={1}, âge={2}", RouteData.Values["controller"], RouteData.Values["action"],age);
return Content(texte, "text/plain", Encoding.UTF8);
}
- 2. satırda, [Action02] eylemi, int türünde [age] adlı bir parametre kabul eder. Alınan karakter dizisinin int türüne dönüştürülebilir olması gerekir.
URL [http://localhost:55483/First/Action02?age=21] komutunu çalıştıralım. Aşağıdaki sayfa görüntülenir:
![]() |
Şimdi URL ve [http://localhost:55483/First/Action02?age=21x] değerlerini talep edelim. Aşağıdaki sayfa karşımıza çıkar:
![]() |
Bu sefer bir hata sayfası aldık. Bu durumda sunucu tarafından gönderilen HTTP başlıklarına bakmak ilginçtir:
- 1. satır: Sunucu, [500 Internal Server Error] koduyla yanıt verdi ve bu hatanın olası nedenlerini açıklamak için 12438 baytlık (5. satır) bir HTML sayfası (3. satır) gönderdi.
Şimdi şu [Action03] eylemini oluşturalım:
// Eylem03
public ContentResult Action03(int? age)
{
...
}
[Action03], [Action02] ile aynıdır; tek fark, [age] parametresinin türünün int? olarak değiştirilmiş olmasıdır; bu, tamsayı veya null anlamına gelir.
Şimdi URL ve [http://localhost:55483/First/Action03?age=21x]'i isteyelim. Aşağıdaki sayfa karşımıza çıkar:
![]() |
ASP.NET, MVC'i [21x]'i int türüne dönüştürmeyi başaramadı. Bunun üzerine, int? türünün izin verdiği şekilde [age] parametresine null değerini atadı. Ancak, parametrenin sorgudan bir değer alıp almadığını öğrenmek mümkündür.
Aşağıdaki yeni [Action04] eylemini oluşturuyoruz:
// Eylem04
public ContentResult Action04(int? age)
{
bool valide = ModelState.IsValid;
string texte = string.Format("Contrôleur={0}, Action={1}, âge={2}, valide={3}", RouteData.Values["controller"], RouteData.Values["action"], age, valide);
return Content(texte, "text/plain", Encoding.UTF8);
}
- 2. satır: [int?] türü korunmuştur. Bu, özellikle sorgunun [age] parametresini sağlamamasını sağlar; bu parametreye null değeri atanır;
- 4. satır: Eylem modelinin geçerli olup olmadığı kontrol edilir. Eylem modeli, tüm parametrelerinin birleşiminden oluşur; buradaki örnek [age]'tir. Model, tüm parametreler istekten bir değer alabilmişse veya parametrenin türü izin veriyorsa null değerini almışsa geçerlidir;
- 5. satır: [valide] değişkeninin değeri, müşteriye gönderilen metne eklenir.
URL ve [http://localhost:55483/First/Action04?age=21x] değerlerini talep edelim. Aşağıdaki sayfa görüntülenir:
![]() |
ASP.NET MVC, [21x]'i int türüne dönüştürmeyi başaramadı. Bunun üzerine, int türü izin verdiği üzere [age] parametresine null değerini atadı. Ancak, [valide] değerinin de gösterdiği gibi, dönüştürme hataları meydana geldi.
Başarısız bir dönüştürmeyle ilişkili bir hata mesajı alınabilir. Şu yeni eylemi inceleyelim:
// Eylem05
public ContentResult Action05(int? age)
{
string erreurs = getErrorMessagesFor(ModelState);
string texte = string.Format("Contrôleur={0}, Action={1}, âge={2}, valide={3}, erreurs={4}", RouteData.Values["controller"], RouteData.Values["action"], age, ModelState.IsValid, erreurs);
return Content(texte, "text/plain", Encoding.UTF8);
}
Yenilik 4. satırda yer alıyor. Burada, eylemin model durumunu aktardığımız özel bir yöntem olan [getErrorMessagesFor] çağrılıyor. Bu yöntem, meydana gelen tüm hataların mesajlarını bir araya getiren bir karakter dizisi döndürüyor. Bu yöntem şu şekildedir:
private string getErrorMessagesFor(ModelStateDictionary état)
{
List<String> erreurs = new List<String>();
string messages = string.Empty;
if (!état.IsValid)
{
foreach (ModelState modelState in état.Values)
{
foreach (ModelError error in modelState.Errors)
{
erreurs.Add(getErrorMessageFor(error));
}
}
foreach (string message in erreurs)
{
messages += string.Format("[{0}]", message);
}
}
return messages;
}
- 1. satır: Yönteme aktarılan [ModelState] parametresinin türü [ModelStateDictionary]'tir;
- 3. satır: başlangıçta boş olan bir hata mesajları listesi;
- 5. satır: Parametre olarak geçirilen durumun geçerli olup olmadığı kontrol edilir. Geçerli değilse, tüm hata mesajları tek bir karakter dizisi halinde birleştirilir;
- 7. satır: [ModelStateDictionary] türünün, [ModelState] türlerinden oluşan bir koleksiyon olan [Values] özelliği vardır. Modelin her bir öğesi için bir [ModelState] bulunur. Örneğin:
- ModelState["age"]: [age] parametresi için eylem modelinin durumu,
- ModelState["age"].Errors: bu parametreye ait hata koleksiyonu. Hatalar [ModelError],
- ModelState["age"] türündedir.Errors[i].ErrorMessage: şablondaki [age] parametresi için olası i numaralı hata mesajı
- ModelState["age"].Errors[i].Exception: [age] parametresine ilişkin hata koleksiyonundaki i numaralı hata istisnası,
- ModelState["age"].Errors[i].Exception.InnerException: Bu istisnanın nedeni,
- ModelState["age"].Errors[i].Exception.InnerException.Message: istisnanın nedenine ilişkin mesaj;
- 9. satır: belirli bir [ModelState]'in [Errors] koleksiyonu taranır;
- 11. satır: belirli bir [ModelError] nesnesinden hata mesajı alınır ve 3. satırdaki hata mesajları listesine eklenir;
- 14-17. satırlar: Hata mesajları listesindeki öğeler tek bir karakter dizisi halinde birleştirilir.
11. satırdaki [getErrorMessageFor] yöntemi şu şekildedir:
private string getErrorMessageFor(ModelError error)
{
if (error.ErrorMessage != null && error.ErrorMessage.Trim() != string.Empty)
{
return error.ErrorMessage;
}
if (error.Exception != null && error.Exception.InnerException == null && error.Exception.Message != string.Empty)
{
return error.Exception.Message;
}
if (error.Exception != null && error.Exception.InnerException != null && error.Exception.InnerException.Message != string.Empty)
{
return error.Exception.InnerException.Message;
}
return string.Empty;
}
- 1. satır: Eylem şablonundaki öğelerden birinde meydana gelen bir hatayı kapsayan [ModelError] türü alınır. Hata mesajı üç farklı yerden aranır:
- [ModelError].ErrorMessage dosyasında, 3-6. satırlar;
- [ModelError].Exception.Message dosyasında, 7-10. satırlar;
- [ModelError].Exception.InnerException.Message dosyasında, 11-14. satırlarda;
Testler sırasında, hata mesajının model öğesinin türüne göre bu üç yerde bulunduğu gözlemlenir. Model öğesiyle ilişkili hata mesajını kesin olarak elde etmeyi sağlayan bir kural olmalı, ancak ben bunu bilmiyorum. Bu nedenle, onu bulabileceğim farklı yerlerde ve belirli bir sırayla arıyorum. Boş olmayan bir mesaj bulunur bulunmaz, bu mesaj döndürülür.
URL [http://localhost:55483/First/Action05?age=21x]'i sorgulayalım. Aşağıdaki sayfa elde edilir:
![]() |
4.3. Birden fazla parametreli eylem
Şu yeni eylemi ele alalım:
// Eylem06
public ContentResult Action06(double? poids, int? age)
{
string erreurs = getErrorMessagesFor(ModelState);
string texte = string.Format("Contrôleur={0}, Action={1}, poids={2}, âge={3}, valide={4}, erreurs={5}", RouteData.Values["controller"], RouteData.Values["action"], poids, age, ModelState.IsValid, erreurs);
return Content(texte, "text/plain", Encoding.UTF8);
}
- 2. satır: [poids] ve [age] olmak üzere iki parametre var.
Daha önce açıklanan kurallar artık bu iki parametreye de uygulanır. İşte birkaç yürütme örneği:
![]() |
![]() |
4.4. Bir sınıfı eylem şablonu olarak kullanma
Bir eylemin şablonu olacak bir sınıf tanımlayalım. Bunu [Models] [1] klasörüne yerleştiriyoruz.
![]() |
Kodu şu şekilde olacaktır:
namespace Exemple_02.Models
{
public class ActionModel01
{
public double? Poids { get; set; }
public int? Age { get; set; }
}
}
Sınıfımızın otomatik özellikleri, daha önce incelediğimiz [Poids] ve [Age] parametreleridir. Bu sınıf, [Action07] eyleminin giriş parametresi olacaktır:
// Eylem07
public ContentResult Action07(ActionModel01 modèle)
{
string erreurs = getErrorMessagesFor(ModelState);
string texte = string.Format("Contrôleur={0}, Action={1}, poids={2}, âge={3}, valide={4}, erreurs={5}", RouteData.Values["controller"], RouteData.Values["action"], modèle.Poids, modèle.Age, ModelState.IsValid, erreurs);
return Content(texte, "text/plain", Encoding.UTF8);
}
- 2. satır: Eylemin modeli, [ActionModel01] türünde bir örnektir.
Daha önce verdiğimiz aynı iki örneği tekrar ele alalım:
![]() |
![]() |
Parametrelerin eşleştirilmesinde büyük/küçük harf duyarlılığı olmadığına dikkat edin. İstek parametreleri [age] ve [poids] idi. Bu parametreler, [ModelAction01] sınıfının [Age] ve [Poids] özelliklerini doldurdu.
Ayrıca, şimdiye kadar HTTP ve [GET] sorgularını kullandık. [POST] sorgularının da aynı davranış sergilediğini gösterelim. Bunun için tekrar [Advanced Rest Client] uygulamasını kullanalım:
![]() |
- [1]'te, istenen URL;
- [2]'e dönüştürülürken, bu işlem POST komutuyla gerçekleştirilecektir;
- [3]'te, POST'in parametreleri.
GET ile aynı yanıt elde edilir:
![]()
4.5. Geçerlilik kısıtlamaları olan eylem modeli - 1
Önceki modelle:
namespace Exemple_02.Models
{
public class ActionModel01
{
public double? Poids { get; set; }
public int? Age { get; set; }
}
}
[poids] ve [age] parametreleri istekte bulunmayabilir. Bu durumda, [Poids] ve [Age] özelliklerine [null] değeri atanır ve herhangi bir hata bildirilmez. Şablonu şu şekilde dönüştürmek istenebilir:
namespace Exemple_02.Models
{
public class ActionModel01
{
public double Poids { get; set; }
public int Age { get; set; }
}
}
5. ve 6. satırlarda, [Poids] ve [Age] özellikleri artık [null] değerine sahip olamaz. [poids] ve [age] parametreleri sorguda bulunmadığında bu yeni şablonla ne olacağına bir bakalım.
![]() |
Herhangi bir hata oluşmadı ve [Poids] ile [Age] özellikleri başlangıç değerlerini korudu: 0. ASP.NET MVC:
- new ActionModel01 komutuyla modelin bir örneği oluşturuldu. İşte bu noktada [Poids] ve [Age] özelliklerine 0 değeri atandı;
- bu iki özelliğe herhangi bir değer atanmamıştır, çünkü bu isimlerdeki hiçbir parametre bulunmamaktaydı.
İlk model, bir parametrenin bulunmadığını kontrol etmemizi sağlar: bu durumda ilgili özelliğin değeri [null] olur. İkinci model ise bunu sağlamaz. Parametrelerin basit türünden başka doğrulama kısıtlamaları da eklemek mümkündür. Şimdi bunları tanıtacağız.
Aşağıdaki yeni eylem modelini ele alalım:
![]() |
using System.ComponentModel.DataAnnotations;
namespace Exemple_02.Models
{
public class ActionModel02
{
[Required]
[Range(1, 200)]
public double? Poids { get; set; }
[Required]
[Range(1, 150)]
public int? Age { get; set; }
}
}
- 6. satır: [Poids] alanının zorunlu olduğunu belirtir;
- 7. satır: [Poids] alanının [1,200] aralığında olması gerektiğini belirtir;
- 9. satır: [Age] alanının zorunlu olduğunu belirtir;
- 7. satır: [Age] alanının [1,150] aralığında olması gerektiğini belirtir;
Bu şablonu kullanan eylem, aşağıdaki [Action08] eylemi olacaktır:
// Eylem08
public ContentResult Action08(ActionModel02 modèle)
{
string erreurs = getErrorMessagesFor(ModelState);
string texte = string.Format("Contrôleur={0}, Action={1}, poids={2}, âge={3}, valide={4}, erreurs={5}", RouteData.Values["controller"], RouteData.Values["action"], modèle.Poids, modèle.Age, ModelState.IsValid, erreurs);
return Content(texte, "text/plain", Encoding.UTF8);
}
- 2. satır: eylem, [ActionModel02] şablonunun bir örneğini alır;
Birkaç test yapalım:
![]() |
![]() |
![]() |
![]() |
Hatalar doğru bir şekilde tespit edildi. Şimdi modeli şu şekilde geliştirelim:
using System.ComponentModel.DataAnnotations;
namespace Exemple_02.Models
{
public class ActionModel02
{
[Required]
[Range(1, 200)]
public double Poids { get; set; }
[Required]
[Range(1, 150)]
public int Age { get; set; }
}
}
8. ve 11. satırlarda, özellikler artık [null] değerini alamaz. Derleyelim ve parametreler olmadan testi tekrar yapalım:
![]() |
Parametrelerin olmaması nedeniyle, [Poids] ve [Age] özellikleri, modelin örneklendirilmesi sırasında aldıkları değeri (0) korumuştur. Ardından doğrulama işlemi gerçekleşir. [Required] özniteliği bu durumda karşılanmış olur. Yukarıdaki hata mesajının [Range] özniteliğine ait olduğu görülmektedir. Dolayısıyla, bir parametrenin varlığını doğrulamak için ilgili özelliğin nullable olması, yani null değerini alabilmesi gerekir.
Başlangıçtaki [ActionModel02] modeline geri dönelim ve modeli bir [ActionModel02] örneği ile [DateTime] ve nullable türlerinden oluşan bir eylemi ele alalım:
// Eylem09
public ContentResult Action09(ActionModel02 modèle, DateTime? date)
{
string erreurs = getErrorMessagesFor(ModelState);
string texte = string.Format("Contrôleur={0}, Action={1}, poids={2}, âge={3}, date={4}, valide={5}, erreurs={6}", RouteData.Values["controller"], RouteData.Values["action"], modèle.Poids, modèle.Age, date, ModelState.IsValid, erreurs);
return Content(texte, "text/plain", Encoding.UTF8);
}
Birkaç test yapalım:
![]() |
Eyleme herhangi bir parametre aktarılmadı. [Required] öznitelikleri, [Poids] ve [Age] özelliklerinin işlevini yerine getirdi. Tarih ise null değerini aldı ve herhangi bir hata bildirilmedi.
Şimdi geçersiz parametreler aktarıyoruz:
![]() |
Şimdi geçerli değerler aktarıyoruz:
![]() |
Diğer geçerlilik kısıtlamalarını inceleyelim. Yeni eylem modeli şöyledir:
![]() |
using System.ComponentModel.DataAnnotations;
namespace Exemple_02.Models
{
public class ActionModel03
{
[Required(ErrorMessage = "Le paramètre email est requis")]
[EmailAddress(ErrorMessage = "Le paramètre email n'a pas un format valide")]
public string Email { get; set; }
[Required(ErrorMessage = "Le paramètre jour est requis")]
[RegularExpression(@"^\d{1,2}$", ErrorMessage = "Le paramètre jour doit avoir 1 ou 2 chiffres")]
public string Jour { get; set; }
[Required(ErrorMessage = "Le paramètre info1 est requis")]
[MaxLength(4, ErrorMessage = "Le paramètre info1 ne peut avoir plus de 4 caractères")]
public string Info1 { get; set; }
[Required(ErrorMessage = "Le paramètre info2 est requis")]
[MinLength(2, ErrorMessage = "Le paramètre info2 ne peut avoir moins de 2 caractères")]
public string Info2 { get; set; }
[Required(ErrorMessage = "Le paramètre info3 est requis")]
[MinLength(4, ErrorMessage = "Le paramètre info3 doit avoir 4 caractères exactement")]
[MaxLength(4, ErrorMessage = "Le paramètre info3 doit avoir 4 caractères exactement")]
public string Info3 { get; set; }
}
}
- 6. satır: [Required] özniteliği; bu sefer, kendimiz belirlediğimiz bir hata mesajı var;
- 7. satır: [EMailAddress] özniteliği, [Email] alanının geçerli bir e-posta adresi içermesini gerektirir;
- 11. satır: [RegularExpression] özniteliği, [Jour] alanının bir veya iki basamaklı bir sayı dizisi içermesini gerektirir. İlk parametre, alanın doğrulaması gereken düzenli ifadedir;
- 15. satır: [MaxLength] özniteliği, [Info1] alanının en fazla 4 karakter içermesini gerektirir;
- 19. satır: [MinLength] özniteliği, [Info2] alanının en az 2 karakter içermesini gerektirir;
- 23-24. satırlar: [MaxLength] ve [MinLength] özniteliklerinin birleşimi, [Info3] alanının tam olarak 4 karakterden oluşmasını gerektirir;
[Action10] eylemi şu şablonu kullanacaktır:
// Eylem10
public ContentResult Action10(ActionModel03 modèle)
{
string erreurs = getErrorMessagesFor(ModelState);
string texte = string.Format("email={0}, jour={1}, info1={2}, info2={3}, info3={4}, erreurs={5}",
modèle.Email, modèle.Jour, modèle.Info1, modèle.Info2, modèle.Info3, erreurs);
return Content(texte, "text/plain", Encoding.UTF8);
}
Bu eylemle birkaç test yapalım.
Öncelikle parametre olmadan:
![]() |
Ardından geçersiz parametrelerle:
![]() |
Ardından geçerli parametrelerle:
![]() |
4.6. Geçerlilik kısıtlamaları içeren eylem modeli - 2
Diğer bütünlük kısıtlamalarını sunuyoruz. Yeni eylem modeli, aşağıdaki [ActionModel04] sınıfı olacaktır:
![]() |
using System.ComponentModel.DataAnnotations;
namespace Exemple_02.Models
{
public class ActionModel04
{
[Required(ErrorMessage="Le paramètre url est requis")]
[Url(ErrorMessage="URL invalide")]
public string Url { get; set; }
[Required(ErrorMessage = "Le paramètre info1 est requis")]
public string Info1 { get; set; }
[Required(ErrorMessage = "Le paramètre info2 est requis")]
[Compare("Info1",ErrorMessage="Les paramètres info1 et info2 doivent être identiques")]
public string Info2 { get; set; }
[Required(ErrorMessage = "Le paramètre cc est requis")]
[CreditCard(ErrorMessage = "Le paramètre cc n'est pas un n° de carte de crédit valide")]
public string Cc { get; set; }
}
}
- 8. satır: açıklamalı alanın geçerli bir URL olması gerektiğini belirtir;
- 13. satır: [Info1] ve [Info2] özelliklerinin aynı değere sahip olmasını gerektirir;
- 16. satır: İşaretlenen alanın geçerli bir kredi kartı numarası olmasını gerektirir.
Bu şablonu kullanan eylem şu şekilde olacaktır:
// Eylem11
public ContentResult Action11(ActionModel04 modèle)
{
string erreurs = getErrorMessagesFor(ModelState);
string texte = string.Format("URL={0}, Info1={1}, Info2={2}, CC={3},erreurs={4}",
modèle.Url, modèle.Info1, modèle.Info2, modèle.Cc, erreurs);
return Content(texte, "text/plain", Encoding.UTF8);
}
[Action11] eylemini test etmek için [Advanced Rest Client] uygulamasını kullanıyoruz:
![]() |
- [1]'te, [Action11] eyleminin URL'i;
- [2]'e dönüştürürken, bu URL, POST ile birlikte istenecektir;
- [3]'te, [Form] sekmesi seçilir;
- [4]'te, beklenen dört parametrenin değerleri girilir. Bu başlatma işlemi, [ARC] tarafından sunulan bir kolaylıktır. Gerçekte gönderilen parametreler, [Raw] ve [5] sekmelerinde görülebilir;
![]() |
- [6]'te, POST'in parametreleri.
Bu sorgu için şu yanıt alınır:
![]() |
Geçersiz parametreler girelim:
![]() |
Bunun üzerine şu yanıtı alıyoruz:
4.7. Geçerlilik kısıtlamaları içeren eylem modeli - 3
Bazen mevcut bütünlük kısıtlamaları yeterli olmaz. Bu durumda kendimiz kısıtlamalar oluşturabiliriz. Özellikle [IValidatableObject] arayüzünü uygulayan bir model kullanabiliriz. Bu durumda, bu arayüzün [Validate] yöntemine kendi model doğrulamalarımızı ekleriz. Bir örneğe bakalım. Eylemin yeni modeli, aşağıdaki [ActionModel05] sınıfı olacaktır:
![]() |
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace Exemple_02.Models
{
public class ActionModel05 : IValidatableObject
{
[Required(ErrorMessage = "Le paramètre taux est requis")]
public double? Taux { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
List<ValidationResult> résultats = new List<ValidationResult>();
bool ok = Taux < 4.2 || Taux > 6.7;
if (!ok)
{
résultats.Add(new ValidationResult("Le paramètre taux doit être < 4.2 ou > 6.7", new string[] { "Taux" }));
}
return résultats;
}
}
}
- 6. satır: model, [IValidatableObject] arayüzünü uygular;
- 10. satır: Bu arayüzün [Validate] yöntemi. Bu yöntem, [ValidationResult] türünde bir öğe koleksiyonu döndürür. Bu tür, bildirilmek istenen hataları kapsüller;
- 9. satır: Geçerli bir oran, <4,2 veya >6,7 olan bir orandır;
- 12. satır: [ValidationResult] türünde boş bir liste oluşturulur;
- 13. satır: [Taux] özelliğinin geçerliliği kontrol edilir;
- satır 14-17: [Taux] özelliği geçersizse, sonuç listesine [ValidationResult] türünde bir öğe eklenir. İlk parametre bir hata mesajıdır. İkinci parametre (isteğe bağlı) ise bu hatayla ilgili özelliklerin bir koleksiyonudur.
Bu şablonu kullanan eylem şu şekilde olacaktır:
// Eylem12
public ContentResult Action12(ActionModel05 modèle)
{
string erreurs = getErrorMessagesFor(ModelState);
string texte = string.Format("taux={0}, erreurs={1}", modèle.Taux, erreurs);
return Content(texte, "text/plain", Encoding.UTF8);
}
İşte bir yürütme örneği:
![]() |
4.8. Tablo veya Liste türü eylem şablonu
Aşağıdaki [Action13] eylemini ele alalım:
// Eylem13
public ContentResult Action13(string[] data)
{
string strData = "";
if (data != null && data.Length != 0)
{
strData = string.Join(",", data);
}
string texte = string.Format("data=[{0}]", strData);
return Content(texte, "text/plain", Encoding.UTF8);
}
- 2. satır: Eylem şablonu, [string] adlı bir tablodan oluşur. Bu şablon, [data] adlı bir parametreyi almamızı sağlar; bu parametre, [?data=data1&data=data2&data=data3] gibi sorgu parametrelerinde birden fazla kez bulunabilir. İsteğin farklı [data] parametreleri, eylem modelinin [data] tablosuna eklenecektir. Bu durum, çoklu seçim listelerinde görülür. Tarayıcı, kullanıcı tarafından seçilen farklı değerleri aynı parametre adıyla gönderir.
İşte bir örnek:
![]() |
Şablon aynı zamanda bir liste de olabilir:
// Eylem14
public ContentResult Action14(List<int> data)
{
string erreurs = getErrorMessagesFor(ModelState);
string strData = "";
if (data != null && data.Count != 0)
{
strData = string.Join(",", data);
}
string texte = string.Format("data=[{0}], erreurs=[{1}]", strData, erreurs);
return Content(texte, "text/plain", Encoding.UTF8);
}
Burada şablon, tamsayılar listesidir (2. satır). İşte ilk çalıştırma sonucu:
![]() |
ve ikinci bir çalıştırma:
![]() |
4.9. Bir eylem modelinin filtrelenmesi
Bazen bir şablonumuz vardır, ancak HTTP isteği tarafından şablonun yalnızca belirli öğelerinin başlatılmasını isteriz. Aşağıdaki [ActionModel06] eylem şablonunu ele alalım:
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;
namespace Exemple_02.Models
{
[Bind(Exclude = "Info2")]
public class ActionModel06
{
[Required(ErrorMessage = "Le paramètre [info1] est requis")]
public string Info1 { get; set; }
public string Info2 { get; set; }
}
}
- 9-10. satırlar: [info1] parametresi zorunludur;
- 6. satır: 12. satırdaki [info2] parametresi, HTTP isteğinin şablonuyla olan bağlantısından hariç tutulmuştur.
Eylem şu şekilde olacaktır: [Action15]:
// Eylem15
public ContentResult Action15(ActionModel06 modèle)
{
string erreurs = getErrorMessagesFor(ModelState);
string texte = string.Format("valide={0}, info1={1}, info2={2}, erreurs={3}", ModelState.IsValid, modèle.Info1, modèle.Info2, erreurs);
return Content(texte, "text/plain", Encoding.UTF8);
}
İşte bir yürütme örneği:
![]() |
- [1]'te: [info2] parametresi URL'e aktarılır;
- [2]'te: eylem modelinin [Info2] özelliği boş kalmıştır.
4.10. Veri bağlama modelini genişletme
Bir eylemin yürütme mimarisine geri dönelim:
![]() |
Eylem sınıfı, istemcinin isteğinin başında örneklenir ve isteğin sonunda yok edilir. Bu nedenle, tekrar tekrar çağrılsa bile iki istek arasında veri depolamak için kullanılamaz. İki tür veri depolamak istenebilir:
- web uygulamasının tüm kullanıcıları tarafından paylaşılan veriler. Bunlar genellikle salt okunur verilerdir. Bu veri paylaşımını gerçekleştirmek için üç dosya kullanılır:
- [Web.Config]: uygulamanın yapılandırma dosyası
- [Global.asax, Global.asax.cs]: Uygulamanın ömrü boyunca var olan ve "küresel uygulama sınıfı" olarak adlandırılan bir sınıfın yanı sıra, aynı uygulamanın belirli olayları için işleyicilerin tanımlanmasına olanak tanır.
Küresel uygulama sınıfı, tüm kullanıcıların tüm isteklerinde kullanılabilecek verilerin tanımlanmasına olanak tanır.
- Aynı istemcinin istekleri tarafından paylaşılan veriler. Bu veriler, “Session” adı verilen bir nesnede saklanır. Bu durumda, istemcinin belleği “istemci oturumu” olarak adlandırılır. Bir istemcinin tüm istekleri bu oturuma erişebilir. Bu oturumda bilgi depolayabilir ve okuyabilirler.
![]() |
Yukarıda, bir eylemin erişebildiği bellek türlerini göstermekteyiz:
- çoğu zaman salt okunur veriler içeren ve tüm kullanıcılar tarafından erişilebilen uygulama belleği;
- okuma/yazma verileri içeren ve aynı kullanıcının ardışık istekleri tarafından erişilebilen belirli bir kullanıcının belleği veya oturumu;
- Yukarıda gösterilmese de, bir istek belleği veya istek bağlamı da mevcuttur. Bir kullanıcının isteği, birbirini izleyen birden fazla eylem tarafından işlenebilir. İstek bağlamı, eylem 1'in eylem 2'ye bilgi aktarmasını sağlar.
Bu farklı bellekleri ortaya koyan ilk örneği inceleyelim:
Öncelikle, [Exemple-02] projesindeki [Web.config] dosyasını şu şekilde değiştiriyoruz:
<appSettings>
<add key="webpages:Version" value="2.0.0.0" />
...
<add key="infoAppli1" value="infoAppli1"/>
</appSettings>
[infoAppli1] anahtarına [infoAppli1] değerini atayan 4. satırı ekliyoruz. Bu, [Application] kapsamlı verimiz olacak: tüm kullanıcıların tüm sorguları bu veriye erişebilecek.
Ardından, [Global.asax] dosyasındaki [Application_Start] yöntemini değiştiriyoruz. Bu yöntem, uygulamanın başlatılması sırasında yalnızca bir kez yürütülür. İşte burada [Web.config] dosyasını kullanmamız gerekiyor:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
// uygulama başlatma
Application["infoAppli1"] = ConfigurationManager.AppSettings["infoAppli1"];
}
10. satırı ekliyoruz. Bu satır iki şey yapar:
- [System.Configuration.ConfigurationManager] sınıfı aracılığıyla [Web.config] dosyasındaki [infoAppli1] anahtarının değerini alır;
- bunu, [infoAppli1] anahtarıyla ilişkilendirilmiş [HttpApplication.Application] sözlüğüne kaydeder. Tüm eylemler bu sözlüğe erişebilir.
Aynı [Gloabal.asax] dosyasına aşağıdaki [Session_Start] yöntemi eklenir:
protected void Session_Start()
{
// sayaç başlatma
Session["compteur"] = 0;
}
[Session_Start] yöntemi, her yeni kullanıcı için yürütülür. Yeni kullanıcı nedir? Bir kullanıcı, bir oturum jetonu ile "izlenir". Bu jeton:
- web sunucusu tarafından oluşturulur ve kullanıcıya gönderilen ilk yanıtın HTTP başlıklarında yeni kullanıcıya iletilir;
- kullanıcının tarayıcısı tarafından yaptığı her yeni istekle birlikte geri gönderilir. Bu, sunucunun kullanıcıyı tanımasını ve kullanıcı oturumu olarak adlandırılan bir belleği yönetmesini sağlar.
Web sunucusu, kullanıcı kendisine oturum jetonu göndermediğinde yeni bir kullanıcıyla karşı karşıya olduğunu anlar. Sunucu bu durumda kullanıcı için bir oturum jetonu oluşturur.
Yukarıdaki 4. satırda, kullanıcının oturumuna, bu kullanıcının her isteğinde artırılacak bir sayaç eklenir. Bu, bir kullanıcıyla ilişkili belleği gösterir. [Session] sınıfı bir sözlük gibi kullanılır (4. satır).
Bunu yaptıktan sonra, aşağıdaki [Action16] eylemini yazıyoruz:
// Eylem16
public ContentResult Action16()
{
// isteğin bağlamı alınır HTTP
HttpContextBase contexte = ControllerContext.HttpContext;
// Uygulama kapsamındaki bilgileri alınır
string infoAppli1 = contexte.Application["infoAppli1"] as string;
// ve Oturum kapsamındaki bilgileri
int? compteur = contexte.Session["compteur"] as int?;
compteur++;
contexte.Session["compteur"] = compteur;
// Müşteriye yanıt
string texte = string.Format("infoAppli1={0}, compteur={1}", infoAppli1, compteur);
return Content(texte, "text/plain", Encoding.UTF8);
}
- 5. satır: İşlenmekte olan HTTP isteğinin bağlamını alırız. Bu bağlam, [Application] ve [Session] kapsamındaki verilere erişimimizi sağlayacaktır;
- 7. satır: [Application] kapsamındaki bilgileri alırız;
- 9. satır: oturumdaki sayaç alınır;
- 10-11. satırlar: Sayaç artırıldıktan sonra oturuma geri yazılır;
- 13-14. satırlar: her iki bilgi de müşteriye gönderilir.
İşte bazı yürütme örnekleri:
[Action16] ilk olarak [1] olarak istenir, ardından sayfa iki kez [F5] olarak yenilenir ve son olarak [2] olarak gönderilir:
![]() |
[2]'te, istemci toplamda üç istek gönderdi. Her seferinde, bir önceki istekle güncellenen sayacı alabildi.
İkinci bir kullanıcıyı simüle etmek için, aynı URL'i istemek üzere ikinci bir tarayıcı kullanıyoruz:
![]() |
[3]'te, ikinci kullanıcı [Application]'in menzil bilgisini doğru bir şekilde alıyor, ancak kendi menzil sayacına ([Session]) sahip.
[Action16] eyleminin koduna geri dönelim:
// Eylem16
public ContentResult Action16()
{
// HTTP isteğinin bağlamı alınır
HttpContextBase contexte = ControllerContext.HttpContext;
// Uygulama kapsamındaki bilgileri alıyoruz
string infoAppli1 = contexte.Application["infoAppli1"] as string;
// ve Oturum kapsamındaki bilgileri
int? compteur = contexte.Session["compteur"] as int?;
compteur++;
contexte.Session["compteur"] = compteur;
// Müşteriye yanıt
string texte = string.Format("infoAppli1={0}, compteur={1}", infoAppli1, compteur);
return Content(texte, "text/plain", Encoding.UTF8);
}
ASP.NET MVC çerçevesinin amaçlarından biri, denetleyicileri ve eylemleri web sunucusu olmadan izole bir şekilde test edilebilir hale getirmektir. Ancak 5. satırda görüldüğü gibi, HTTP isteğinin bağlamı, [Application] ve [Session] kapsamlarındaki bilgileri almak için gereklidir. [Application] ve [Session] kapsamlarındaki verileri parametre olarak alacak yeni bir [Action17] eylemi oluşturmayı öneriyoruz:
// Eylem17
public ContentResult Action17(ApplicationModel applicationData, SessionModel sessionData)
{
// Uygulama kapsamındaki bilgiler alınır
string infoAppli1 = applicationData.InfoAppli1;
// ve Oturum kapsamındaki bilgileri
int compteur = sessionData.Compteur++;
// müşteriye verilen yanıt
string texte = string.Format("infoAppli1={0}, compteur={1}", infoAppli1, compteur);
return Content(texte, "text/plain", Encoding.UTF8);
}
Artık kod, HTTP isteğine bağlı değildir. Dolayısıyla, bir web sunucusundan bağımsız olarak test edilebilir.
Bunu nasıl yapacağımıza bir göz atalım. Öncelikle, sırasıyla [Application] ve [Session] kapsamındaki verileri kapsülleyecek olan [ApplicationModel] ve [SessionModel] sınıflarını oluşturmamız gerekiyor. Bunlar şunlardır:
![]() |
namespace Exemple_02.Models
{
public class ApplicationModel
{
public string InfoAppli1 { get; set; }
}
}
namespace Exemple_02.Models
{
public class SessionModel
{
public int Compteur { get; set; }
public SessionModel()
{
Compteur = 0;
}
}
}
Ardından, [Global.asax] dosyasındaki [Application_Start] ve [Session_Start] yöntemlerini değiştirmemiz gerekiyor:
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
// uygulama başlatma - durum 1
Application["infoAppli1"] = ConfigurationManager.AppSettings["infoAppli1"];
// uygulama başlatma - durum 2
ApplicationModel data=new ApplicationModel();
data.InfoAppli1=ConfigurationManager.AppSettings["infoAppli1"];
Application["data"] = data;
}
protected void Session_Start()
{
// sayaç başlatma - durum 1
Session["compteur"] = 0;
// sayaç başlatma - durum 2
Session["data"] = new SessionModel();
}
}
- 14. satır: [ApplicationModel]'in bir örneği oluşturulur;
- 15. satır: bu örnek başlatılır;
- 16. satır: ve [Application] sözlüğüne, [data] anahtarıyla ilişkilendirilerek eklenir. [Application], 1. satırdaki [HttpApplication] sınıfının bir özelliğidir;
- 24. satır: [SessionModel] sınıfından bir örnek oluşturulur ve [Session] sözlüğüne yerleştirilir; bu örnek, [data] anahtarıyla ilişkilendirilir. [Session], 1. satırdaki [HttpApplication] sınıfının bir özelliğidir;
Şimdiye kadar gördüklerimize göre, imza
public ContentResult Action17(ApplicationModel applicationData, SessionModel sessionData)
imzası, eylem tarafından işlenen HTTP isteğinin [applicationData] ve [sessionData] adlı parametreleri içermesi gerektiği anlamına gelir. Ancak durum böyle olmayacaktır. Bir eylem, parametre olarak
- [ApplicationModel] türünde bir parametre aldığında, [Application] kapsamlı ve [data] anahtarlı verinin kendisine sağlanması için yeni bir veri bağlama modeli oluşturmalıyız;
- [SessionModel], [Session] kapsam verisi ve [data] anahtar verisi ona sağlanmalıdır.
Bunun için [IModelBinder] arayüzünü uygulayan sınıflar oluşturulması gerekir.
Öncelikle, [Exemple-02] projesinde [Infrastructure] adlı bir klasör oluşturuyoruz:
![]() |
Bu klasörün içine aşağıdaki [ApplicationModelBinder] sınıfını oluşturuyoruz:
using System.Web.Mvc;
namespace Exemple_02.Infrastructure
{
public class ApplicationModelBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
// [Application] kapsamındaki veriler döndürülür
return controllerContext.RequestContext.HttpContext.Application["data"];
}
}
}
- 5. satır: Sınıf, [IModelBinder] arayüzünü uygular. Kodunu anlamak için, bir eylemin [ApplicationModel] türünde bir parametreye sahip olduğu her seferinde bu sınıfın çağrılacağını bilmek gerekir. [ApplicationModel] --> [ApplicationModelBinder] bağlantısı, uygulamanın başlatılması sırasında [Global.asax] sınıfının [Application_Start] yönteminde kurulacaktır;
- 7. satır: [IModelBinder] arayüzünün tek yöntemi;
- 7. satır: [ControllerContext] türündeki parametre, işlenmekte olan HTTP sorgusuna erişim sağlar;
- 7. satır: [ModelBindingContext] türündeki parametre, oluşturulacak modelle ilgili bilgilere erişim sağlar; burada bu, [ApplicationModel] türüdür;
- 7. satır: [BindModel]'in sonucu, ilişkili parametreye atanacak nesnedir; burada bu, [ApplicationModel] türündeki bir parametredir;
- 10. satır: Kapsam nesnesini [Application] ve anahtar nesnesini [data] olarak tanımlıyoruz.
[SessionModelBinder] sınıfı da aynı şemayı izler:
using System.Web.Mvc;
namespace Exemple_02.Infrastructure
{
public class SessionModelBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
// [Session] kapsamındaki veriler aktarılıyor
return controllerContext.HttpContext.Session["data"];
}
}
}
Geriye kalan tek şey, her bir [XModel] modelini kendi binder ve [XModelBinder]'iyle eşleştirmektir. Bu işlem, [Global.asax]'in [Application_Start] yönteminde gerçekleştirilir:
protected void Application_Start()
{
....
// uygulama başlatma - durum 2
ApplicationModel data=new ApplicationModel();
data.InfoAppli1=ConfigurationManager.AppSettings["infoAppli1"];
Application["data"] = data;
// model bağlayıcıları
ModelBinders.Binders.Add(typeof(ApplicationModel), new ApplicationModelBinder());
ModelBinders.Binders.Add(typeof(SessionModel), new SessionModelBinder());
}
- 9. satır: Bir eylemin [ApplicationModel] türünde bir parametresi olduğunda, [ApplicationModelBinder.Bind] yöntemi çağrılır. Bu yöntemin, [data] anahtarına bağlı [Application] kapsamındaki veriyi döndürdüğü bilinmektedir;
- 10. satır: [SessionModel] türü için de durum aynıdır.
[Action17] eylemine geri dönelim:
// Eylem17
public ContentResult Action17(ApplicationModel applicationData, SessionModel sessionData)
{
// Uygulama kapsamındaki bilgileri alıyoruz
string infoAppli1 = applicationData.InfoAppli1;
// ve Oturum kapsamındaki bilgileri
sessionData.Compteur++;
int compteur = sessionData.Compteur;
// müşteriye yanıt
string texte = string.Format("infoAppli1={0}, compteur={1}", infoAppli1, compteur);
return Content(texte, "text/plain", Encoding.UTF8);
}
- 2. satır: [Action17] çağrıldığında,
- ilk parametre olarak: [data] anahtarına bağlı [Application] kapsam verisini,
- ikinci parametre olarak: [data] anahtarına bağlı [Session] kapsam verisi;
Bu iki veri, istenilen kadar karmaşık olabilir ve biri [Application] kapsamındaki tüm verileri, diğeri ise [Session] kapsamındaki tüm verileri içerebilir.
Aşağıda, [Action17] eyleminin yürütülmesine ilişkin bir örnek verilmiştir:
![]() |
4.11. Eylem şablonunun geç bağlanması
Aşağıdaki [Action12] eylemini yazdık:
// Eylem12
public ContentResult Action12(ActionModel05 modèle)
{
string erreurs = getErrorMessagesFor(ModelState);
string texte = string.Format("taux={0}, erreurs={1}", modèle.Taux, erreurs);
return Content(texte, "text/plain", Encoding.UTF8);
}
Gizli bir şekilde, ASP.NET MVC:
- parametresiz yapıcıyı kullanarak [ActionModel05] türünde bir örnek oluşturur;
- [ActionModel05]'in özelliklerinden biriyle aynı ada (büyük/küçük harf duyarlı değildir) sahip istek bilgileriyle başlatır.
Bazen bu davranış bizim için uygun olmayabilir. Özellikle, eylem modelinin belirli bir oluşturucusunu kullanmak istediğimizde bu durum söz konusudur. Bu durumda şu şekilde ilerleyebiliriz:
// Eylem18
public ContentResult Action18()
{
ActionModel05 modèle = new ActionModel05();
TryUpdateModel(modèle);
string erreurs = getErrorMessagesFor(ModelState);
string texte = string.Format("taux={0}, erreurs={1}", modèle.Taux, erreurs);
return Content(texte, "text/plain", Encoding.UTF8);
}
- 2. satır: Eylem artık parametre almaz. Dolayısıyla otomatik veri bağlama da artık gerçekleşmez;
- 4. satır: Eylem modelinin bir örneğini kendimiz oluşturuyoruz. İşte burada farklı bir oluşturucu kullanabiliriz;
- satır 5: modeli istek bilgileriyle başlatıyoruz. Bu işi ASP.NET MVC yapıyor. Modeli bir parametre olarak verilmiş olsaydı yapacağı şekilde yapıyor;
- 6. satır: Artık [Action12] eylemindeki durumla aynı durumdayız.
İşte bir yürütme örneği:
![]() |
4.12. Conclusion
ASP.NET MVC uygulamasının mimarisine geri dönelim:
![]() |
Bir [1] isteği, ASP.NET ve MVC'in [2a]'e eylem olarak sunduğu çeşitli bilgileri, bizim "eylem modeli" olarak adlandırdığımız bir model biçiminde taşır.
![]() |
- Müşterinin HTTP isteği, [1]'e ulaşır;
- [2]'te, istekte yer alan bilgiler [3] eylem şablonuna dönüştürülür;
- [4] aşamasında, eylem bu şablondan yola çıkarak bir yanıt oluşturacaktır. Bu yanıtın iki bileşeni olacaktır: bir V görünümü ([6]) ve bu görünümün M şablonu ([5]);
- V [6] görünümü, müşteriye yönelik HTTP yanıtını oluşturmak için kendi M modeli olan [5]'i kullanacaktır.
MVC modelinde, [4] eylemi C'nin (denetleyici) bir parçasıdır; [5] görünüm modeli M'dir ve [6] görünümü ise V'dir.
Bu bölümde, doğası gereği karakter dizileri olan istek tarafından taşınan bilgiler ile çeşitli türlerdeki özelliklere sahip bir sınıf olabilen eylem modeli arasındaki bağlantı mekanizmaları incelenmiştir. Ayrıca, eyleme sunulan modelin geçerliliğinin doğrulanmasının mümkün olduğunu da gördük. Son olarak, bu modeli [Session] ve [Application] kapsamındaki verilere nasıl genişletebileceğimizi inceledik.
Şimdi, [1] isteğinin işleme zincirinin son aşamasına odaklanacağız: [6] görünümünün ve bunun modeli olan [5]'in oluşturulması. Bu iki öğe, [4] eylemi tarafından üretilir.
























































