تعلم ASP.NET MVC


الدرس: استخدام وحدات التحكم


الصفحة السابقة
هيا ، تحقق من وحدات التحكم. لقد تحدثنا بالفعل عن ذلك مسبقًا ، ولديهم نفس الدور الذي نراه في القطارات ، وهم هنا للسيطرة!
وحدة التحكم في قلب MVC ، تجعل الرابط بين العرض والنموذج ؛ هو الذي يدير أفعال المستخدم.
يفسر طلب HTTP الوارد ويختار طريقة العرض ليتم عرضها في المستعرض.
أنت تعرف بالفعل الكثير عن وحدة التحكم بفضل تفسيراتي السابقة ، ولكن لا تزال هناك أشياء لاكتشافها. لذا دعنا نذهب. 

تذكيرات وتوضيحات


يمكن رؤية وحدة التحكم كنقطة دخول للطلب لأنه هو الذي سيعالج النموذج ومن سيختار طريقة العرض لعرضها. لقد رأينا أنه في الواقع ، هناك وسيط قبل معالجة وحدة التحكم للطلب ، هذه هي آلية التوجيه التي تسمح لك بتحويل عنوان URL إلى إجراء وحدة تحكم. سنرى لاحقًا أنه لا يزال من الممكن وضع وسطاء آخرين.
تبقى الحقيقة أن أي إجراء يقوم به المستخدم عبر متصفح الإنترنت الخاص به يتم تحويله إلى إجراء تحكم. يتم وضع وحدات التحكم عن طريق الاتفاقية في دليل /Controllers، ولكن هذا ليس في الواقع التزامًا. أي فئة ترث من الفئة الأساسية Controller   مؤهلة لحالة جهاز التحكم.
رأينا في الفصل الخاص بآراء كيفية إضافة وحدة تحكم تتيح لنا الترحيب بمستخدمي الموقع. كانت وحدة تحكم AccueilController . كان يحتوي على طريقة Index () التي تم استنساخها عندما يتصفح المستخدم الموقع عبر عناوين URL :
  • /
  • /Accueil
  • /Accueil/Index
لقد قمنا بالكثير من الاختبارات في وحدة التحكم هذه ، ولكنها في الواقع ليست مثيرة للاهتمام للغاية لأنه في التطبيق النهائي ، لن تفعل شيئًا تقريبًا باستثناء استدعاء الطريقة View()  ، مما يسمح لها بعرض طريقة العرض الافتراضية لـ الإجراء Index  ، الذي يسمى عادة Index.cshtml . كل هذه المراجعات. لذا احذف لي كل التعليمات البرمجية الزائدة فقط ضع:

public class AccueilController : Controller
{
    public ActionResult Index()
    {
        return View();
    }
}
سننظر في وحدات تحكم أكثر تعقيدًا قليلاً فقط لبدء فعل أشياء لطيفة.
لهذا ، سننشئ وحدة تحكم جديدة ، والتي ستسمح لنا بإدارة المطاعم. دعنا نسميه RestaurantController  . لإنشاء هذه الفئة ، تذكر ، عليك فقط النقر بزر الماوس الأيمن على دليل وحدات التحكم والقيام بإضافة <- وحدة تحكم. يفتح مربع الحوار ، مما يسمح لنا باختيار نوع وحدة التحكم وإدخال اسم وحدة التحكم:
ASP.NET framework
إضافة وحدة تحكم
يمكنك أن ترى أن هناك العديد من الخيارات عند إضافة وحدة تحكم. في الوقت الحالي ، سنترك وحدة تحكم MVC فارغة. ولكن إذا كنت فضوليًا قليلًا وتنظر إلى العناصر الأخرى ، فسترى أنها يمكن أن تجعل حياتنا أسهل. ولكن في وقت لاحق فقط ، سنفعل كل شيء الآن من الألف إلى الياء.
كالعادة ، ينشئ Visual Studio فئة وحدة التحكم:

public class RestaurantController : Controller
{
    //
    // GET: /Restaurant/

    public ActionResult Index()
    {
        return View();
    }

}
كما تعلم بالفعل ، يجب أن تستمد وحدة التحكم بالضرورة من الفئة الأساسية Controller  . في الواقع ، لكي تكون مؤهلاً للحصول على حالة وحدة التحكم ، يجب على الفئة تنفيذ الواجهة فقط IController  ، ولكن من الأسهل أن ترث من فئة وحدة التحكم ، والتي تنفذ بالفعل IController   والتي توفر لنا أيضًا العديد من الطرق المفيدة مثل الأساليب الشهيرة  View()   و  PartialView()   التي شهدناها سابقا.
ستلاحظ أيضًا أن Visual Studio يولد تعليقًا لنا ، والذي أحذفه بشكل عام لزيادة إمكانية قراءة الكود. يخبرنا أن إجراء وحدة التحكم يمكن الوصول إليه عبر طريقة GET لبروتوكول HTTP ، عبر المسار. /Restaurant/لقد عرفنا ذلك بالفعل ، ولكن من الجيد أن نتذكر أن الوصول إلى عنوان URL /Restaurant يقدم بالفعل طلب HTTP من النوع GET الذي يعمل على إنشاء وحدة التحكم Restaurant   واستدعاء طريقته Index  .
GET هي الطريقة الافتراضية. سنرى لاحقًا كيفية التعامل مع طلبات POST .
سنستفيد من طريقة index هذه لإنشاء قائمة من المطاعم وعرضها على طريقة عرض تحمل نفس الاسم. لذلك ، ستقوم وحدة التحكم باستدعاء نموذجنا عبر طبقة الوصول إلى البيانات التي أنشأناها ثم إرسال النموذج مرة أخرى للعرض. مما سيعطي:

public ActionResult Index()
{
    using (IDal dal = new Dal())
    {
        List<Resto> listeDesRestaurants = dal.ObtientTousLesRestaurants();
        return View(listeDesRestaurants);
    }
}
هذا ما يجب علينا القيام به. من ناحية أخرى ، في الوقت الحالي ليس لدينا بيانات في الأساس ؛ لا مطاعم ، لا مستخدمين ، لا شيء!
لتسهيل عملنا ، سنقوم بتهيئة قاعدة بياناتنا مؤقتًا ببعض قيم البدء. يشبه إلى حد ما ما فعلناه في اختباراتنا حيث اخترنا إعادة تعيين قاعدة البيانات قبل كل تشغيل اختبار باستخدام هذا الأمر:

IDatabaseInitializer<BddContext> init = new DropCreateDatabaseAlways<BddContext>();
Database.SetInitializer(init);
init.InitializeDatabase(new BddContext());
هنا ، ما نريد القيام به هو أنه في كل مرة نبدأ فيها تطبيق الويب لدينا ، لدينا بعض البيانات البسيطة التي يتم التحكم فيها.
للقيام بذلك ، سنمر من خلال مُهيئ مخصص. يكفي كتابة فئة DropCreateDatabaseAlways   استخدمناه بالفعل واستبدال طريقته Seed   التي ستسمح لنا بتنفيذ تعبئة البيانات. لذا أضف هذه الفئة على سبيل المثال في دليل الموديلات:

public class InitChoixResto : DropCreateDatabaseAlways<BddContext>
{
    protected override void Seed(BddContext context)
    {
        context.Restos.Add(new Resto { Id = 1, Nom = "Resto pinambour", Telephone = "123" });
        context.Restos.Add(new Resto { Id = 2, Nom = "Resto pinière", Telephone = "456" });
        context.Restos.Add(new Resto { Id = 3, Nom = "Resto toro", Telephone = "789" });

        base.Seed(context);
    }
}
هنا ، مع هذا على سبيل المثال ، سيكون لدي ثلاثة مطاعم في قاعدة بياناتي في كل مرة يبدأ فيها تطبيق الويب.
يبقى لي فقط أن أتصل بهذه الفئة من Global.asax.cs :

public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();
        RouteConfig.RegisterRoutes(RouteTable.Routes);

        IDatabaseInitializer<BddContext> init = new InitChoixResto();
        Database.SetInitializer(init);
        init.InitializeDatabase(new BddContext());
    }
}
بعد القيام بذلك ، سوف نكون قادرين على العبث بهدوء على طلبنا.
بعد ذلك ، دعنا ننشئ عرضًا بسيطًا وبشعًا يسرد المطاعم ببساطة. لإنشائه بسرعة ، يمكنك بالطبع النقر بزر الماوس الأيمن في إجراء وحدة التحكم ، ثم "إضافة عرض" . سيتم كتابة العرض بقوة مع قائمة من Resto   :

@model  List<ChoixResto.Models.Resto>
لم أستخدم نموذج-عرض(view-model) هنا لأن نموذجي كافٍ لما أريد القيام به ، ولكن كان بإمكاننا إنشاء نموذج.
سيكون العرض الكامل:

@model  List
@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Liste des restaurants</title>
    <style type="text/css">
        table {
            border-collapse: collapse;
        }

        td, th {
            border: 1px solid black;
        }
    </style>
</head>
<body>
    <table>
        <tr>
            <th>Nom</th>
            <th>Téléphone</th>
            <th>Modifier</th>
        </tr>
        @foreach (var resto in Model)
        {
        <tr>
            <td>@resto.Nom</td>
            <td>@resto.Telephone</td>
            <td>@Html.ActionLink("Modifier " + resto.Nom, "ModifierRestaurant", new { id = resto.Id })</td>
        </tr>
        }
    </table>
</body>
</html>
وسيكون لدينا:
ASP.NET framework
قائمة المطاعم
لا شيء خاص. الدقة الوحيدة هي استخدام مساعد Html.ActionLink الذي يولد رابطًا إلى الإجراء ModifierRestaurant  ، ويمرره كمُدخل id   للمطعم.  يشبه HTML الناتج:

<a href="/Restaurant/ModifierRestaurant/1">Modifier Resto pinambour</a>
ملاحظة: من الممكن التأكد من أن عمل جهاز التحكم ليس له نفس اسم أسلوب الفئة. على سبيل المثال ، يمكننا استبدال:

public ActionResult Index()
{
    return View();
}
بواسطة:

 [ActionName("Index")]
public ActionResult LeNomQueJeVeux()
{
    return View();
}
في الواقع ، هذا مفيد بشكل خاص عندما نريد تحديد طريقتين بنفس التوقيع في وحدة التحكم ، واحدة للتعامل مع طلب GET والأخرى للتعامل مع طلب POST ، سنعود إلى هذا.

تمرير المُدخلات إلى وحدة التحكم


كما نعلم بالفعل ، ووفقًا لتعريف المسار الافتراضي ، سيؤدي تصفح عنوان URL /Restaurant/ModifierRestaurant/1 إلى إنشاء وحدة تحكم المطعم ، واستدعاء الطريقة ModifierRestaurant   ، ووضع القيمة 1 في المُدخل المسمى id  .
حسنًا ، بالضرورة ، في الوقت الحالي ، لا يمكن أن يعمل هذا لأنه ليس لدينا طريقة ModifierRestaurant  . لا يهم ، فقط أضفه:

public ActionResult ModifierRestaurant()
{
    return View();
}
بالتزامن مع ذلك ، سيكون عليك إنشاء العرض ModifierRestaurant   الذي يتوافق معها.
بالطبع ، كما قرأت بالفعل الجزء السابق ، ستخبرني أن جهاز التحكم الخاص بي غير مكتمل لأنه لا يسمح باستعادة قيمة المعرف ، في هذه الحالة 1. هل هناك مُدخل مفقودة معرف في توقيع الطريقة ModifierRestaurant  ؟
 لا! يمكننا استرداد المعرف لأنه لدينا حق الوصول إلى URL :

public ActionResult ModifierRestaurant()
{
    string id = Request.Url.AbsolutePath.Split('/').Last();
    ViewBag.Id = id;
    return View();
}
نستخدم خاصية Url للكائن Request للوصول إلى URL . ثم القليل من الاختراق على URL وأحصل على المعرف. ثم أقوم بوضعها ViewBag حتى أتمكن من عرضها من العرض مع:

@ViewBag.Id
ولكن هناك ، لا أعلمك شيئا ...
ستقول لي أنها ليست رهيبة كتقنية ... وسوف تكون على حق! نحن بصدد إعادة عمل نظام التوجيه (وعلى الأقل جيدة!). ولكن يجب أن تعرف أن الكائن الذي يمثل الطلب يمكن الوصول إليه من وحدة التحكم الخاصة بنا وأنه يمكننا استخدامه كما نراه مناسبًا. هذا هو الشيء Request  .
حسنًا ، بالتأكيد ، هناك طريقة أفضل لاسترداد هذا المعرّف ، وأنت تعرفها. يمكننا استرداد قيمته باستخدام مُدخل يسمى id في إجراء وحدة التحكم ، على سبيل المثال:

public ActionResult ModifierRestaurant(string id)
{
    ViewBag.Id = id;
    return View();
}
لاحظ أن هذا المعرف رقمي بالضرورة في حالتنا ، يمكنك استبدال النوع string بالنوع int :

public ActionResult ModifierRestaurant(int id)
{
    ViewBag.Id = id;
    return View();
}
تلقائيًا ، تحاول آلية التوجيه لـ ASP.NET MVC تحويل المُدخل إلى النوع المناسب. إذا لم تنجح ، فستكون لديك قيمة صفرية ، كما هو الحال مع المسار /Restaurant/ModifierRestaurant/Nicolas . سيظهر لك أيضًا خطأ لأن العدد الصحيح إلزامي ، ولا يمكن تعيين القيمة على صفر. في هذه الحالة ، يمكنك استبدال استخدام واحد int   باستخدام int   لاغية. سيسمح هذا على سبيل المثال بالرجوع إلى طريقة عرض خاصة إذا لم تكن هناك قيمة في العدد الصحيح:

public ActionResult ModifierRestaurant(int? id)
{
    if (id.HasValue)
    {
        ViewBag.Id = id;
        return View();
    }
    else
        return View("Error");
}
ملاحظة: عرض الخطأ غير موجود في حلنا. تذكر ، لقد أنشأنا واحدة من نفس النوع في الجزء السابق. يمكنك إضافته في الدليل / Views / Shared .
لا أعرف إذا كنت تتذكر ، فقد قلنا سابقًا أن المسار /Restaurant/ModifyRestaurant/1 كان يعادل /Restaurant/ModifierRestaurant?id=1 . إذا حاولت الانتقال إلى عنوان URL الجديد هذا ، فسترى أننا نقوم باسترداد المعرف. إنه بالطبع بفضل آلية التوجيه التي تحلل سلسلة الاستعلام والتي تحدد الحقول في مُدخلات الإجراء.
لكن! يمكننا أيضًا فعل الشيء نفسه وتفسير عناصر سلسلة الاستعلام بأنفسنا. للقيام بذلك ، قم بتغيير رمز إجراء وحدة التحكم ليكون لديك:

public ActionResult ModifierRestaurant()
{
    string idStr = Request.QueryString["id"];
    int id;
    if (int.TryParse(idStr, out id))
    {
        ViewBag.Id = id;
        return View();
    }
    else
        return View("Error");
}
نعم ، لا يزال كائن طلب يسمح لنا بالوصول إلى سلسلة الاستعلام وفي هذه الحالة يمكننا الوصول إلى مُدخل المعرف باستخدام Request.QueryString["id"]  . ستلاحظ أنه ليس لدينا معرف في مُدخلات الإجراء.
حسنًا ، الطريقة السابقة ما زالت الأفضل. ولكن هذا يظهر لك الاحتمالات التي تقدمها سلسلة الاستعلام. هذا يسمح على وجه الخصوص بتمرير العديد من المُدخلات دون لمس نظام التوجيه بالضرورة. وبالتالي ، يمكننا الانتقال إلى URL  /Restaurant/ModifierRestaurant?id=1&val=3 واسترداد المُدخلين. بينما سيكون ذلك مستحيلًا مع /Restaurant/ModifierRestaurant/1/3
 لا بأس بوضع معرف المطعم في ViewBag ، ولكنه محدود قليلاً. بالطبع ، نحن مهتمون بالوصول إلى النموذج لاسترداد المطعم من معرفه:

public ActionResult ModifierRestaurant(int? id)
{
    if (id.HasValue)
    {
        using (IDal dal = new Dal())
        {
            Resto restaurant = dal.ObtientTousLesRestaurants().FirstOrDefault(r => r.Id == id.Value);
            if (restaurant == null)
                return View("Error");
            return View(restaurant);
        }
    }
    else
        return View("Error");
}
بمجرد الحصول على هذا المطعم ، يمكننا تمريره كنموذج للبصر. الهدف بالطبع هو تعديل العرض بحيث يتيح لنا إمكانية تعديل هذا المطعم. أنت تعرف بالفعل كيف تفعل كل شيء لأننا رأينا في الفصل السابق ، علينا أن نستعمل مساعدي HTML . بدون القيام بشيء جميل جدًا ، يمكننا الحصول على:

@using (Html.BeginForm())
{
    <fieldset>
        <legend>Modifier un restaurant</legend>

        <div>
            @Html.LabelFor(model => model.Nom)
            @Html.TextBoxFor(model => model.Nom)
        </div>
        <div>
            @Html.LabelFor(model => model.Telephone)
            @Html.TextBoxFor(model => model.Telephone)
        </div>
        <br />
        <input type="submit" value="Modifier" />
    </fieldset>
}
نجد ما يكفي لإنشاء علامة النموذج ، ثم تسمية ومربع نص لاسم المطعم وهاتفه ، دون نسيان الزر لإرسال النموذج. يعطي :
ASP.NET framework
نموذج تعديل المطعم
وهنا تبدأ الأشياء في أن تصبح مثيرة للاهتمام ... سنتعلم كيفية استرداد قيم النموذج. منذ الوقت الذي أتحدث فيه عن ذلك ، حان الوقت. 
أول شيء يجب ملاحظته هو أنه من خلال مساعدنا ، Html.BeginForm   ننشئ علامة يشير نشاطها إلى إجراء ModifierRestaurant   وحدة التحكم الخاصة بنا. في الواقع ، فإن HTML الذي تم إنشاؤه هو:

<form action="/Restaurant/ModifierRestaurant/1" method="post">
سيكون لهذا تأثير استدعاء طريقة ModifierRestaurant   التحكم الخاصة بنا ، عندما نضغط على زر تعديل. أسهل طريقة لإقناع نفسك بهذا هي وضع نقطة توقف في طريقة التحكم وإيجاد أننا نقوم بعمل جيد عندما نصل إلى الصفحة (طريقة GET ) وعندما نرسل النموذج (طريقة POST ) . باستثناء ذلك فجأة ، سنفعل نفس الشيء بالضبط في كلتا الحالتين ، أي لعرض المطعم من معرفه ، الموجود في مُدخل وحدة التحكم. نحتاج إلى طريقة لتحديد ما إذا كنا في حالة وظيفة بريدية حتى نتمكن من إجراء التغييرات المناسبة.
الطريقة التي سأقدمها في البداية ليست الأفضل ولكن سيكون لها ميزة جعلك على دراية جيدة بكيفية عمل نموذج الويب.
ماذا لو استخدمنا الكائن الذي يمثل الطلب؟ هناك بالتأكيد معلومات هناك ... لا شيء أبسط ، يمكننا الوصول إلى نوع الطريقة عبر الخاصية HttpMethod   وعناصر النموذج بفضل الخاصية Form   :

public ActionResult ModifierRestaurant(int? id)
{
    if (id.HasValue)
    {
        using (IDal dal = new Dal())
        {
            if (Request.HttpMethod == "POST")
            {
                string nouveauNom = Request.Form["Nom"];
                string nouveauTelephone = Request.Form["Telephone"];
                dal.ModifierRestaurant(id.Value, nouveauNom, nouveauTelephone);
            }

            Resto restaurant = dal.ObtientTousLesRestaurants().FirstOrDefault(r => r.Id == id.Value);
            if (restaurant == null)
                return View("Error");
            return View(restaurant);
        }
    }
    else
        return View("Error");
}
قم بتعديل القيم في النموذج ، أرسل كل هذا ويمكننا أن نرى أن التغيير فعال بالفعل:
ASP.NET framework
تعديل المطعم من البيانات المنشورة من النموذج
ستفهم أننا نصل إلى عناصر النموذج عبر اسم عنصر تحكم HTML الموجود في النموذج. نظرًا لأن لدينا هذه العلامة للاسم:

<input data-val="true" data-val-required="Le champ Nom est requis." id="Nom" name="Nom" type="text" value="Resto pinambour" />
يجب علينا تمرير "الاسم(Nom)" كمُدخل لكائن Form  الطلب ، مثل ما هو موجود في سمة الاسم لعنصر تحكم HTML .
ممتاز. 
ماذا لو أخبرتك أنه يمكننا تبسيط طريقة التحكم الخاصة بنا؟ نعم ، لأن if الكبيرة في الوسط لمعرفة ما إذا كنا في POST ، ووحدة الوصول إلى كل عنصر تحكم في النموذج ... يبدو في التسعينات ...
الخبر الجيد الأول هو أن ASP.NET MVC قادر على تحويل قيم كائن النموذج تلقائيًا إلى مُدخلات وحدة التحكم التي تحمل نفس الاسم. لذلك يمكننا إضافة مُدخلين في توقيع عملنا للحصول على:

public ActionResult ModifierRestaurant(int? id, string nom, string telephone)
{
    if (id.HasValue)
    {
        using (IDal dal = new Dal())
        {
            if (Request.HttpMethod == "POST")
            {
                dal.ModifierRestaurant(id.Value, nom, telephone);
            }

            Resto restaurant = dal.ObtientTousLesRestaurants().FirstOrDefault(r => r.Id == id.Value);
            if (restaurant == null)
                return View("Error");
            return View(restaurant);
        }
    }
    else
        return View("Error");
}
وهكذا، المُدخلات nom   و telephone   سيتم تلقائيا ملؤها بالقيم الجيدة متى سيتم استدعاء الإجراء POST . من ناحية أخرى ، ستكون قيمتها بالطبع null   عندما سيتم استدعاء الإجراء في GET . لاحظ أنه من الممكن تسمية الاسم والهاتف بدون أحرف كبيرة لأن الحالة ليست مهمة.
مع هذا التعديل ، أصبح الكود أكثر وضوحًا.
ولكن ماذا لو أخبرتك أنه يمكننا تحديد طريقتين مختلفتين للتحكم في إجراءات GET و POST؟ سيكون من الأفضل! انظر إلى هذا:

public ActionResult ModifierRestaurant(int? id)
{
    if (id.HasValue)
    {
        using (IDal dal = new Dal())
        {
            Resto restaurant = dal.ObtientTousLesRestaurants().FirstOrDefault(r => r.Id == id.Value);
            if (restaurant == null)
                return View("Error");
            return View(restaurant);
        }
    }
    else
        return View("Error");
}

[HttpPost]
public ActionResult ModifierRestaurant(int? id, string nom, string telephone)
{
    if (id.HasValue)
    {
        using (IDal dal = new Dal())
        {
            dal.ModifierRestaurant(id.Value, nom, telephone);
            return RedirectToAction("Index");
        }
    }
    else
        return View("Error");
}
بفضل السمة HttpPost   التي تسمح بتقييد الإجراء لإدارة طلبات HTTP فقط من نوع POST . لذا ، قمنا بقطع إجرائينا GET و POST إلى طريقتين مختلفتين يقوم كل منهما بما يجب عليهما القيام به.
ستلاحظ أنه في نهاية طريقة التحكم المقابلة لـ POST ، أستخدم الطريقة RedirectToAction   التي تسمح لي بإعادة تنفيذ إجراء Index  من أجل إعادة وضع نفسي مباشرة في قائمة المطاعم بمجرد اكتمال التعديل.

ربط النموذج


ماذا؟ هل ما زال بإمكاننا التبسيط؟ لا!
شاهد هذا الإصدار الجديد من الإجراء في إصدار POST :

 [HttpPost]
public ActionResult ModifierRestaurant(Resto resto)
{
    using (IDal dal = new Dal())
    {
        dal.ModifierRestaurant(resto.Id, resto.Nom, resto.Telephone);
        return RedirectToAction("Index");
    }
}
بالكاد يمكن أن يكون أبسط ... انظر إلى مُدخلات الطريقة ... يقوم ASP.NET MVC بما يسمى ربط النموذج هنا. هذا يعني أنه بفضل الحقول المختلفة التي يتم تمريرها إلى الاستعلام ، فإنه قادر على إعادة بناء نموذجنا ، في هذه الحالة نسخة من الفئة Resto  .
في الواقع ، المُدخلid   الذي يتم تمريره في عنوان URL يسير بشكل جيد في الموقع Resto.Id  . وبالمثل ، يتم Nom   استدعاء عنصر تحكم النموذج بنفس الطريقة تمامًا مثل الخاصية Resto.Nom  . ونفس الشيء بالنسبة للمجال Telephone ...
يتعرف ASP.NET MVC على أن الخصائص لها نفس أسماء حقول النموذج. ثم يقوم بعمل رابط بيانات بين الاثنين ، مما يجعل من الممكن إنشاء كائن Resto من جميع عناصر الاستعلام.
لذا فإن هذا النموذج الملزم هو بصراحة شيء أنيق سيساهم بشكل كبير في خفة ASP.NET MVC. سنستمر في ممارستها وسوف ترى كل قوتها.