تعلم ASP.NET MVC


الدرس: لمحة عن Ajax


الصفحة السابقة
Ajax ليس تقنية للحصول على JavaScript نظيف.  في الواقع ، هو اختصار Asynchronous JavaScript And XML . إنها تقنية قديمة إلى حد ما أصبحت شائعة بمجرد أن بدأنا الحديث عن Web 2.0. مبدأ Ajax هو جعل تطبيقات الويب أكثر حداثة واستجابة من خلال تجنب إعادة تحميل الصفحة بأكملها بمجرد حدوث تغيير.

في الوقت الحالي ، لم نقم بأداء Ajax في تطبيق MVC الخاص بنا. عندما أدركنا واجهات العرض باستخدام النماذج على سبيل المثال ، لتقديمها ، اضطررنا لإرسال كل شيء إلى الخادم ، ثم أعاد عرض صفحة كاملة. إنها عملية بطيئة نسبيًا ، اعتمادًا على اتصالك بالإنترنت ، وهي ليست مزعجة عندما تكون الصفحة خفيفة للغاية ومحليًا ، ولكن يمكن أن تكون مشكلة بسرعة عندما يكون هناك تصميم مزدحم للغاية مع الكثير من الصور ، إلخ.
تتمثل فكرة Ajax في أنه بدلاً من إعادة تحميل صفحة معقدة تمامًا ، لا يمكننا سوى إعادة تحميل الأجزاء الصغيرة التي تهمنا. حسنًا ، في صفحة إنشاء مطعم ، ليس لديها اهتمام كبير ، ولكن من المنطقي على سبيل المثال في صفحة تجمع المحتوى ، مثل قارئ RSS .

وبالمثل ، قمنا بإجراء التحقق من قبل للتحقق من أن اسم المطعم لم يكن موجودًا بالفعل عندما حاولنا إنشاؤه. هذا تحقق لا يمكن إجراؤه إلا من جانب الخادم وبالتالي يتطلب إرسال الصفحة بالكامل مع ظهور رسالة خطأ محتملة في المقابل.
أليس من الجميل أن تكون قادرًا على "تعديل" هذا التحقق؟

Ajax مع jQuery


كإطار ويب حديث ، لا يمكن لـ ASP.NET MVC أن يغيب عن Ajax . وبالطبع تم اختيار jQuery لتطبيق ذلك على جانب المتصفح.

على سبيل المثال ، تخيل أننا نريد أن نقدم للمستخدم إمكانية تحديث جزء من صفحة النتائج ، وفي هذه الحالة تكون النتائج نفسها! صحيح أن هذه العملية لم تكن عملية. مرة واحدة في صفحة النتائج ، كان عليك إعادة عرض الصفحة لرؤية أي تغييرات. ماذا لو عرضنا إمكانية إعادة تحميل التغييرات بالضغط على رابط؟ والتغييرات فقط ، وليس بقية الصفحة بالطبع.
من أول الأشياء التي يجب القيام بها هو تضمين النص jQuery للقيام ب Ajax . هذا هو ~/Scripts/jquery.unobtrusive-ajax.js ، على سبيل المثال في التخطيط:

<script type="text/javascript" src="~/Scripts/jquery.unobtrusive-ajax.js"></script>
إذا لم يكن هذا البرنامج النصي موجودًا في الحل الخاص بك ، فيمكنك إضافته عبر nuget :
ASP.NET framework
أضف نصوص jQuery غير بارزة عبر Nuget
ثم استخدم مساعدي Ajax . على سبيل المثال ، هنا سنستخدم مساعد Ajax. ActionLink . هذا المساعد يجعل من الممكن استدعاء إجراء ، مثل زميله Html.ActionLink   ولكن الفرق يكمن في حقيقة أن الطلب تم في Ajax ويتم إعادة نتيجته في الصفحة في الموقع الذي اخترناه.
للتوضيح ، سيتعين علينا إعادة صياغة التعليمات البرمجية الخاصة بنا قليلاً ، وخاصة وحدة تحكم التصويت والعرض من AfficheResultat   أجل استخدام طريقة عرض جزئية. لذلك ، سنقوم باستبدال الصفيف في العرض AfficheResultat   عن طريق استدعاء عرض جزئي:

<p>
    Résultats du sondage :</p>
<div id="tableauResultat">
    @{
    Html.RenderAction("AfficheTableau", new { id = ViewBag.Id });
    }
</div>
<p>Vue normale : @DateTime.Now.ToLongTimeString()</p>
يجب علينا إنشاء هذا العرض الجزئي الشهير لـ TableArray :

@model  List<ChoixResto.Models.Resultats>

<table>
    <tr>
        <th>Nom</th>
        <th>Téléphone</th>
        <th>Nombre de votes</th>
    </tr>
    @foreach (var resto in Model)
        {
    <tr>
        <td>@resto.Nom</td>
        <td>@resto.Telephone</td>
        <td>@resto.NombreDeVotes</td>
    </tr>
}
</table>

<p>Vue partielle : @DateTime.Now.ToLongTimeString()</p>
كنت قد لاحظت أنني انتهزت الفرصة لإضافة الوقت في كل من واجهات العرض.
لنقم أيضًا بإنشاء الإجراء المرتبط به:

public ActionResult AfficheResultat(int id)
{
    if (!dal.ADejaVote(id, HttpContext.User.Identity.Name))
    {
        return RedirectToAction("Index", new { id = id });
    }
    ViewBag.Id = id;
    return View();
}

public ActionResult AfficheTableau(int id)
{
    List<Resultats> resultats = dal.ObtenirLesResultats(id);
    return PartialView(resultats.OrderByDescending(r => r.NombreDeVotes).ToList());
}
بالطبع ، من الأسهل إضافة إجراءات وحدة التحكم أولاً ثم العرض الجزئي.
من المهم تمرير معرف الاستطلاع بالطريقة التي تريدها. لقد اخترت تمريرها كمُدخل لأنني أجدها أكثر نظافة ، ولكن كان من الممكن أن نحافظ عليها فقط ViewBag  .
حسنًا ، في الوقت الحالي ، لم تتغير النتيجة. لدينا دائمًا نفس الشيء ، نستخدم طريقة عرض جزئية فقط.
من المثير للاهتمام هو أننا سنضيف الآن استدعاء Ajax في عرض DisplayResult :

<p>Résultats du sondage :</p>
<div id="tableauResultat">
    @{
    Html.RenderAction("AfficheTableau", new { id = ViewBag.Id });
    }
</div>
@Ajax.ActionLink("Actualiser le résultat", "AfficheTableau", new { id = ViewBag.Id}, new AjaxOptions
{
    InsertionMode = InsertionMode.Replace,
    UpdateTargetId = "tableauResultat",
    HttpMethod = "GET"
})
<p>Vue normale : @DateTime.Now.ToLongTimeString()</p>
الأمر بسيط للغاية مع هذا المساعد. نقوم بتمرير عنوان الرابط بالإضافة إلى الإجراء المطلوب الاتصال به. بالطبع ، هناك حمل زائد يأخذ وحدة التحكم كمُدخل إذا لزم الأمر. هناك ببساطة مُدخل نوع جديد AjaxOptions  . يمكننا أن نقول له كيفية التعامل مع طلب Ajax . هنا على سبيل المثال ، أخبره أنني أريد أن تؤدي نتيجة المكالمة إلى استبدال ( InsertionMode.Replace ) محتوى العلامة التي يكون معرفها tableauResultat  . سيتم إجراء المكالمة في GET .
ونحصل على هذا ، رابط بسيط في الصفحة:
ASP.NET framework
رابط في الصفحة ، لجعل AJAX
إذا قمت بالنقر فوقها ، يمكنك مشاهدة المحتوى الذي يتم تحديثه ، على وجه الخصوص من خلال ملاحظة تغير الوقت في العرض الجزئي بينما لم يتغير الوقت في العرض العادي. يوضح هذا أن التحديث كان جزئيًا فقط وأنه لم يتم إعادة تحميل الصفحة بالكامل.
إذا كان لديك ما يكفي لتحليل الطلبات من متصفحك ، فستتمكن من رؤية استدعاء Ajax . مثال مع IE 10 :
ASP.NET framework
طلب Ajax في المتصفح
لرؤية هذا مع IE 10 ، تحتاج إلى تنشيط أدوات المطورين F12 بالضغط على Network والنقر عليه لالتقاط الإطارات العابرة. لاحظ أن هذا التحليل متاح على جميع المتصفحات تقريبًا وفي أسوأ الأحوال يمكنك إضافة مكونات إضافية للقيام بذلك.
يمكنك النقر على الطلب والحصول على مزيد من المعلومات حوله ، مثل الرؤوس أو الرد:
ASP.NET framework
الاستجابة على طلب Ajax
يمكننا أن نرى أن الاستجابة لطلب Ajax هو جزء من HTML ، في هذه الحالة العلامة <table>   ومحتواها.
إذا نظرت إلى كود HTML الذي تم إنشاؤه بواسطة مساعد Ajax ، فهو رابط بسيط:
الاستجابة على طلب Ajax
يمكننا أن نرى أن الاستجابة لطلب Ajax هو جزء من HTML ، في هذه الحالة العلامة <table>   ومحتواها.

<a data-ajax="true" data-ajax-method="GET" data-ajax-mode="replace" data-ajax-update="#tableauResultat" href="/Vote/AfficheTableau/13">Actualiser le résultat</a>
باستثناء أن العلامة <a> مزينة بسمات تسمح لـ jQuery بالقيام بكل سحرها. إلى جانب ذلك ، إذا قمت بحذف ملف jQuery الذي قمت بإضافته في بداية الدرس ، فسترى أن هذا الرابط يعمل مثل الرابط الكلاسيكي الذي يعرض العرض.
لا يمكنك استخدام السمة [ChildActionOnly]   لتزيين الإجراء لأن طلب Ajax لم يعد يعمل.
وهنا لدينا Ajax الجميل ، نظيف للغاية ومشرق.
انتباه: إن حقيقة قطع العمل وإعادة دمجه ستجبرنا AfficheResultat   على تعديل اختبار لم يعد يمر ، وكتابة اختبار آخر لاختبار الإجراء الجزئي AfficheTableau  .
لذا قم بتعديل الاختبار AfficheResultat_AvecVote_RenvoieLesResultats   للحصول على:

 [TestMethod]
public void AfficheResultat_AvecVote_RenvoieLaVueParDefaut()
{
    dal.AjouterUtilisateur("Nico", "1234");
    dal.AjouterUtilisateur("Jérémie", "1234");
    dal.AjouterVote(idSondage, 1, 1);

    ViewResult view = (ViewResult)controleur.AfficheResultat(idSondage);
    Assert.AreEqual(string.Empty, view.ViewName);
}
ويضاف الاختبار التالي:

 [TestMethod]
public void AfficheTableau_RenvoieLeViewModel()
{
    dal.AjouterUtilisateur("Nico", "1234");
    dal.AjouterUtilisateur("Jérémie", "1234");
    dal.AjouterVote(idSondage, 1, 1);

    PartialViewResult view = (PartialViewResult)controleur.AfficheTableau(idSondage);

    List<Resultats> model = (List<Resultats>)view.Model;
    Assert.AreEqual(1, model.Count);
    Assert.AreEqual("Resto pinambour", model[0].Nom);
    Assert.AreEqual(1, model[0].NombreDeVotes);
    Assert.AreEqual("0102030405", model[0].Telephone);
}
لاحظ أننا نحصل على رد من إجراء وحدة التحكم PartialViewResult  .

معالجة الأخطاء


من المحتمل أن تفشل جميع طلبات Ajax غير المتزامنة: خطأ في النقل ، خطأ في الطلب ، عدم توفر مؤقت ، إلخ. باستثناء ذلك حاليًا ، يفشلون في الصمت. خذ على سبيل المثال السمة ChildActionOnly  . ربما حاولت إضافته إلى إجراء وحدة التحكم الخاصة بك لأنك لا تريد أن يتمكن أي شخص من الوصول إلى هذا المسار دون المرور عبر طريقة العرض الرئيسية. ولم تشاهد أي شيء باستثناء احتمال حدوث خطأ إذا قمت بتحليل الآثار الناتجة:
ASP.NET framework
خطأ في طلب Ajax
يمكن فعل شيء ما إذا فشل طلب Ajax . يسمح لك جميع مساعدي Ajax بتحديد اسم طريقة JavaScript للاتصال في حالة حدوث خطأ:

@Ajax.ActionLink("Actualiser le résultat", "AfficheTableau", new { id = ViewBag.Id}, new AjaxOptions
{
    InsertionMode = InsertionMode.Replace,
    UpdateTargetId = "tableauResultat",
    HttpMethod = "GET",
    OnFailure = "ErreurAfficheTableau"
})
هنا على سبيل المثال ، أريد استدعاء الطريقة ErreurAfficheTableau إذا فشل طلب Ajax على الإطلاق. بالطبع ، أحتاج إلى تعريف طريقة JavaScript هذه ، على سبيل المثال:

<script type="text/javascript">
    function ErreurAfficheTableau() {
        $("#tableauResultat").html("Une erreur s'est produite lors de la mise à jour, veuillez réessayer ...");
    }
</script>
وبالتالي ، ستعرض لنا المكالمة عن طريق الخطأ:
ASP.NET framework
معالجة خطأ طلب AJAX

التحديث الدوري


بدلاً من إجبار المستخدم على النقر على رابط لتحديث الأصوات ، لماذا لا تبسط حياته وتعرض عليه تحديثًا دوريًا؟
هنا ، إنه حقًا نقي وصعب الاستخدام لـ JavaScript و jQuery ، ولكن بهذه الطريقة سترى كيفية إجراء استدعاء Ajax قياسية مع jQuery وكيفية بدء مهمة دورية ، والتي تعمل كل 10 ثوانٍ.
المبدأ هو التأكد من إجراء مكالمة Ajax كل 10 ثوانٍ وتحديث وجهة نظرنا الجزئية. وفي الحقيقة ، إنها بسيطة للغاية.
احذف الجزء ب Ajax.ActionLink  .
والآن سنكتب JavaScript. ولبداية ، سنقوم بإعداد المهمة الدورية:

<script type="text/javascript">
    var timer;
    function ChargeVuePartielle() {
    }

    $(function () {
        timer = window.setInterval("ChargeVuePartielle()", 10000);
    });
</script>
باستخدام هذا ، ChargeVuePartielle سيتم استدعاء طريقة JavaScript كل 10 ثوانٍ (10000 مللي ثانية). يبقى فقط إجراء استدعلء Ajax لتحديث العلامة <div> التي تحتوي على النتائج. يتم ذلك مع jQuery :

function ChargeVuePartielle() {
    $.ajax({
        url: '@Url.Action("AfficheTableau", new {id = ViewBag.Id  })',
        type: 'GET',
        dataType: 'html',
        success: function (result) {
            $('#tableauResultat').html(result);
        }
    });
}
هنا ، أشير إلى أن طلب Ajax الخاص بي من النوع GET ويعيد HTML . نستخدم بالطبع المساعد  Url.Action   لإنشاء عنوان URL للعرض الجزئي الذي سيعرض HTML . إذا نجح الاستدعاء (مُدخل النجاح) ، فكل ما عليك فعله هو استبدال نتيجة علامة
بما تعيده الطريقة. لاحظ أنه من الممكن أيضًا القيام بشيء عندما تفشل الطريقة ، عبر مُدخل الخطأ.
الجانب السلبي لهذه الطريقة هو أنه سيكون هناك دعوة إلى إجراء تحكم كل 10 ثوانٍ حتى يتم إغلاق الصفحة ، مما قد يزيد من تحميل خادم الويب الخاص بنا. قد يكون من الجيد إيقاف التحديث الدوري بعد فترة محددة من عدم النشاط ، أو حتى استخدام إعلام الخادم وجيوب ويب مع SignalR ، ولكن هنا سأخرج تمامًا عن الموضوع ...

النماذج غير متزامنة


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

حسنًا ، من الممكن إرسال النماذج بشكل غير متزامن وتلقي رد يمكننا عرضه دون الحاجة إلى إعادة تحميل الصفحة بأكملها. شكرا لك Ajax .
على سبيل المثال ، تخيل أن لدينا الكثير من المطاعم ، مما يجعل إدارتها معقدة. يمكن أن نفكر في تقديم واجهة عرض تسمح لنا بالعثور على مطعم. حتى الآن ، كنا قد أنشأنا في البداية إجراء بحث في وحدة التحكم Restaurant   :

public ActionResult Recherche(RechercheViewModel rechercheViewModel)
{
    if (!string.IsNullOrWhiteSpace(rechercheViewModel.Recherche))
        rechercheViewModel.ListeDesRestos = dal.ObtientTousLesRestaurants().Where(r => r.Nom.IndexOf(rechercheViewModel.Recherche, StringComparison.CurrentCultureIgnoreCase) >= 0).ToList();
    else
        rechercheViewModel.ListeDesRestos = new List<Resto>();
    return View(rechercheViewModel);
}
مع نموذج عرض يكون:

public class RechercheViewModel
{
    public string Recherche { get; set; }
    public List<Resto> ListeDesRestos { get; set; }
}
ومنظر:

@model  ChoixResto.ViewModels.RechercheViewModel
@{
    ViewBag.Title = "Chercher un restaurant";
}

@using (Html.BeginForm("Recherche", "Restaurant", FormMethod.Get))
{
    @Html.TextBoxFor(m => m.Recherche);
    <input type="submit" value="Rechercher" />
    
    <p>Résultats de la recherche</p>
    if (Model.ListeDesRestos.Count == 0)
    {
        <p>Pas de résultat</p>
    }
    else
    {
        <table>
            <tr>
                <th>Nom</th>
                <th>Téléphone</th>
            </tr>
            @foreach (var resto in Model.ListeDesRestos)
            {
                <tr>
                    <td>@resto.Nom</td>
                    <td>@resto.Telephone</td>
                </tr>
            }
        </table>
    }
}
لاحظ بشكل عام أنه نظرًا لعدم وجود تعديل ولكن ببساطة الوصول إلى الموارد ، فمن المنطقي إنشاء نموذج باستخدام طريقة GET . لذلك عندما نصل إلى العرض أو إذا لم تكن هناك نتائج بحث ، فسيكون لدينا:
ASP.NET framework
نتيجة البحث بدون نتيجة
وإذا كانت هناك نتائج بحث ، فسيكون لدينا:
ASP.NET framework
نتيجة البحث مع النتائج
باختصار ، لا يوجد علم الصواريخ الذي لا تعرف كيف تقوم به بالفعل ...
ومع ذلك ، لقد أدركت أنه مع كل بحث ، قمنا بإعادة تحميل الصفحة بأكملها. ماذا لو قمنا بتعديل كل هذا؟
لهذا ، لدينا مساعد: Ajax.BeginForm الذي يحل محل المعروف Html.BeginForm  . ولكن قبل ذلك ، يجب علينا أولاً استخدام عرض جزئي. قم بإنشاء الإجراء ResultatsRecherche   وتعديله Recherche   ليكون:

public ActionResult Recherche(RechercheViewModel rechercheViewModel)
{
    return View(rechercheViewModel);
}

public ActionResult ResultatsRecherche(RechercheViewModel rechercheViewModel)
{
    if (!string.IsNullOrWhiteSpace(rechercheViewModel.Recherche))
        rechercheViewModel.ListeDesRestos = dal.ObtientTousLesRestaurants().Where(r => r.Nom.IndexOf(rechercheViewModel.Recherche, StringComparison.CurrentCultureIgnoreCase) >= 0).ToList();
    else
        rechercheViewModel.ListeDesRestos = new List<Resto>();
    return PartialView(rechercheViewModel);
}
يمكننا أيضًا التفكير في إعادة جميع المطاعم عندما تكون عبارة البحث فارغة. هذه هي الطريقة التي تريدها. 
ضع في عرض جزئي النتائج

@model  ChoixResto.ViewModels.RechercheViewModel
<p>Vue partielle : @DateTime.Now.ToLongTimeString()</p>
<p>Résultats de la recherche</p>
@if (Model.ListeDesRestos.Count == 0)
{
    <p>Pas de résultat</p>
}
else
{
    <table>
        <tr>
            <th>Nom</th>
            <th>Téléphone</th>
        </tr>
        @foreach (var resto in Model.ListeDesRestos)
        {
            <tr>
                <td>@resto.Nom</td>
                <td>@resto.Telephone</td>
            </tr>
        }
    </table>
}
وعرض البحث الرئيسي:

@model  ChoixResto.ViewModels.RechercheViewModel
@{
    ViewBag.Title = "Chercher un restaurant";
}

@using (Html.BeginForm("Recherche", "Restaurant", FormMethod.Get))
{
    @Html.TextBoxFor(m => m.Recherche);
    <input type="submit" value="Rechercher" />
    <p>Vue principale : @DateTime.Now.ToLongTimeString()</p>

    <div id="resultats">
        @{Html.RenderAction("ResultatsRecherche", new { rechercheViewModel = Model });
        }
    </div>
}
ونعم ، دائمًا في الساعات الأولى لرؤية أن إعادة الشحن تتم فقط بشكل جزئي. 
باستثناء ذلك في الوقت الحالي ، لم نقم بإضافة أي شيء. لذلك دعونا نستخدم المساعد الشهير:

@using (Ajax.BeginForm("ResultatsRecherche", new AjaxOptions
{
    HttpMethod = "GET",
    InsertionMode = InsertionMode.Replace,
    UpdateTargetId = "resultats",
}))
{
    @Html.TextBoxFor(m => m.Recherche);
    <input type="submit" value="Rechercher" />
    <p>Vue principale : @DateTime.Now.ToLongTimeString()</p>

    <div id="resultats">
        @{Html.RenderAction("ResultatsRecherche", new { rechercheViewModel = Model });
        }
    </div>
}
ها أنت ذا ، هذا كل ما في الأمر. يمكنك أن ترى أن طريقة GET قد مرت AjaxOptions  .
تذكر أنه يجب أن يكون ملف jquery.unobtrusive-ajax.js موجودًا ، ولكن نظرًا لأننا وضعناه في التخطيط ، فلا توجد مشكلة.
هل تريد إضافة رسالة خطأ عند فشل الطلب؟ إنه نفس المبدأ كما كان من قبل ، طريقة JavaScript صغيرة:

<script type="text/javascript">
    function ErreurRecherche() {
        $("#resultats").html("Une erreur s'est produite lors de la recherche, veuillez réessayer ...");
    }
</script>
مع اسم طريقة JavaScript في المساعد:

@using (Ajax.BeginForm("ResultatsRecherche", new AjaxOptions
{
    HttpMethod = "GET",
    InsertionMode = InsertionMode.Replace,
    UpdateTargetId = "resultats",
    OnFailure = "ErreurRecherche",
}))
ومع ذلك ، هناك شيء قليل مفقود ... رسوم متحركة تجعلنا ننتظر! نعم ، تخيل أن البحث طويل. من الجيد أن تبين للمستخدم أن الطلب قد أخذ في الاعتبار وأنه يجب عليه الانتظار. بشكل عام ، نستخدم صورة متحركة صغيرة تتحول ، أو شريط تقدم. أشجعك على إنشاء الرسوم المتحركة الخاصة بك عن طريق الذهاب إلى الموقع http://www.ajaxload.info/  وهو عملي جدًا لهذا الغرض. أضف صورتك في الحل الخاص بك ، على سبيل المثال في /Content/Images/ajax-loader.gif وأضف صورة مخفية بجوار الزر. ثم حدد فقط معرفها في خيارات ajax للمساعد بحيث يدير الرسوم المتحركة بنفسه:

@using (Ajax.BeginForm("ResultatsRecherche", new AjaxOptions
{
    HttpMethod = "GET",
    InsertionMode = InsertionMode.Replace,
    UpdateTargetId = "resultats",
    OnFailure = "ErreurRecherche",
    LoadingElementId = "chargement"
}))
{
    @Html.TextBoxFor(m => m.Recherche);
    <img id="chargement" src="~/Content/Images/ajax-loader.gif" style="display: none" alt="Chargement en cours..." />
    <input type="submit" value="Rechercher" />
    <p>Vue principale : @DateTime.Now.ToLongTimeString()</p>

    <div id="resultats">
        @{Html.RenderAction("ResultatsRecherche", new { rechercheViewModel = Model });
        }
    </div>
}
لإخفاء عنصر HTML ، نستخدم النمط display: none  .
لاحظ أن الصورة بها  id   "تحميل" وأنه هو نفس المعرف المستخدم في خاصية LoadingElementId   المساعد. وهذا ما يبدو عليه:
ASP.NET framework
صورة انتظار أثناء طلب AJAX
ملاحظة: بما أن بحثنا فائق الكفاءة ، لرؤية الرسوم المتحركة بشكل صحيح ، أضف القليل من Thread.Sleep(…)   الإجراء الخاص بك:

public ActionResult ResultatsRecherche(RechercheViewModel rechercheViewModel)
{
    if (!string.IsNullOrWhiteSpace(rechercheViewModel.Recherche))
    {
        rechercheViewModel.ListeDesRestos = dal.ObtientTousLesRestaurants().Where(r => r.Nom.IndexOf(rechercheViewModel.Recherche, StringComparison.CurrentCultureIgnoreCase) >= 0).ToList();
        Thread.Sleep(1500);
    }
    else
        rechercheViewModel.ListeDesRestos = new List<Resto>();
    return PartialView(rechercheViewModel);
}
بمجرد أن ترى أن هذه الرسوم المتحركة الجميلة تعمل ، لا تنس حذف الصورة Thread.Sleep غير المفيدة.

Ajax وJSON


من الشائع جدًا أن تعمل طلبات Ajax مع JSON بدلاً من HTML . ما أظهرته لك الآن هو تحديثات منطقة HTML . على وجه التقريب ، أسمي إجراء وحدة التحكم الذي يعيد HTML إلي بفضل عرض جزئي وهو HTML الذي أعرضه مباشرة في علامة <div>   أو أخرى.
يعمل هذا بشكل جيد ولكن لديه عيب في إرسال الكثير من المعلومات. يمكن أن يصبح تخطيط HTML / CSS مرهقًا بسرعة ، وبالتالي يمكن أن يكون هناك الكثير من البيانات التي ستمر من خلالها والتي قد تثقل محتوى إرجاع HTML ؛ وكلما كان أثقل ، كلما كان من المحتمل أن يكون طويلًا ... وكلما طال ... كلما زاد خطر إبطاء متصفحك وتقليل استخدام الموقع للمستخدمين.
وفقًا للاحتياجات ، قد يكون من المفيد العمل مع JSON ، وهو تنسيق يعمل بشكل جيد مع JavaScript . وبالتالي ، فإن البيانات هي التي تنتقل فقط ، و JavaScript هي التي تهتم بمعالجتها ووضعها في المكان الصحيح.
خذ على سبيل المثال البحث الذي قمنا به للتو. إنها حكاية جميلة ، لكن إعادة الجدول بأكمله مع ثلاثة مطاعم لا يزال يستغرق 509 بايت بينما البيانات في JSON فقط ستستغرق 186 بايت:

{"Recherche":"rest","ListeDesRestos":[{"Id":1,"Nom":"Resto pinambour","Telephone":"123"},{"Id":2,"Nom":"Resto pinière","Telephone":"456"},{"Id":3,"Nom":"Resto toro","Telephone":"789"}]}
بالطبع ، العرض التقديمي مفقود ، وهنا من السخف بعض الشيء أن تضطر إلى إعادة العرض التقديمي بأكمله باستخدام JavaScript .
ومع ذلك ، هناك بعض الأوقات عندما يكون من المناسب بشكل خاص إعادة JSON . لن نقوم بذلك ، ولكن تخيل أننا نريد إضافة الإكمال التلقائي إلى ملاحظة البحث في مربع النص الخاص بنا. هذا يعني أنه في كل مرة نضيف فيها حرفًا في مربع النص ، نقوم بتقديم طلب للعودة إلينا قائمة بجميع المطاعم التي تطابق هذا البحث. jQuery جيد جدًا في الإكمال التلقائي ويستخدم تنسيق بيانات JSON .

التحقق غير المتزامن


وهذا هو الحال أيضًا بالنسبة للتحقق غير المتزامن. لقد رأينا بالفعل الكثير من عمليات التحقق من جانب العميل ، ولكن هناك واحدة يمكننا تحسينها. تذكرون ؟ عندما نحاول إنشاء مطعم جديد ، هناك اختبار في وحدة التحكم يتحقق من أن اسم المطعم غير موجود بالفعل:

 [HttpPost]
public ActionResult CreerRestaurant(Resto resto)
{
    if (dal.RestaurantExiste(resto.Nom))
    {
        ModelState.AddModelError("Nom", "Ce nom de restaurant existe déjà");
        return View(resto);
    }
    if (!ModelState.IsValid)
        return View(resto);
    dal.CreerRestaurant(resto.Nom, resto.Telephone);
    return RedirectToAction("Index");
}
هذا التحقق هو بالضرورة التحقق من الخادم لأننا نبحث عن المطاعم الموجودة في قاعدة البيانات. لا يمكننا إجراء هذا التحقق من جانب العميل لأن هذا يتطلب تخزين جميع المطاعم في مكان ما في JavaScript ، وهو أمر غير ممكن.

يمكنك أن تتخيل أنه مع كل Ajax الذي رأيناه ، هناك حل للقيام بهذا التحقق بشكل غير متزامن ... وأنا أقول نعم!
يمكننا كتابة مدققنا المخصص بشكل جيد للغاية ، كما فعلنا بالفعل ، والذي من شأنه تقديم طلب Ajax مع jQuery لاستجواب وحدة تحكم تخبرنا ما إذا كان المطعم موجودًا بالفعل أم لا. موصوفة بهذه الطريقة ، لا تبدو معقدة للغاية. إذا كنت ترغب في القيام بذلك ، لا تتردد. 

باستثناء أن ... ASP.NET MVC يقدمها بالفعل كمعيار.
ما عليك سوى استخدام السمة Remote    على البيانات للتحقق ، في هذه الحالة اسم مطعمنا:

 [Table("Restos")]
public class Resto
{
    public int Id { get; set; }
    [Required(ErrorMessage = "Le nom du restaurant doit être saisi")]
    [Remote("VerifNomResto", "Restaurant", ErrorMessage="Ce nom de restaurant existe déjà")]
    public string Nom { get; set; }
    [Display(Name = "Téléphone")]
    [RegularExpression(@"^0[0-9]{9}$", ErrorMessage = "Le numéro de téléphone est incorrect")]
    public string Telephone { get; set; }
}
لاستخدامه ، يجب أن أشير إلى اسم الإجراء ( VerifNomResto ) ووحدة التحكم الخاصة به ( Restaurant ) التي ستعمل كطريقة للتحقق. يجب أن تُرجع هذه الطريقة JSON :

public JsonResult VerifNomResto(string Nom)
{
    bool resultat = !dal.RestaurantExiste(Nom);
    return Json(resultat, JsonRequestBehavior.AllowGet);
}
لذلك أعود صحيحًا إذا كان الاسم غير موجود وخطأ إذا كان موجودًا.
وهذا كل شيء. 
يبقى فقط لاختبار إذا كان يعمل ؛ انتقل إلى صفحة إضافة مطعم وأدخل اسم مطعم موجود بالفعل. لا حاجة لإرسال النموذج للتحقق من أنه يعمل ، عليك فقط أن تفقد التركيز في الحقل (على سبيل المثال بالضغط على مفتاح علامة التبويب) ويمكنك رؤية السحر يحدث. وللتأكد من أنه بالفعل طلب Ajax ، ما عليك سوى إلقاء نظرة على الطلبات:
ASP.NET framework
التحقق من صحة الخادم عبر Ajax
يمكنك رؤية الطلب الذي يذهب إلى GET ، مع نتائجه على وجه الخصوص إذا قمت بالنقر فوقه:
ASP.NET framework
تفاصيل التحقق من صحة Ajax غير المتزامن
ها أنت ذا ، أليس هذا رائعًا؟
يرجى ملاحظة أن هذا لا يعفيك من الاستمرار في إجراء التحقق من جانب الخادم ، حيث أنه من الممكن دائمًا للمستخدم إلغاء تنشيط JavaScript . لذا حافظ دائمًا على الاختبار في بداية إجراء وحدة التحكم.

 [HttpPost]
public ActionResult CreerRestaurant(Resto resto)
{
    if (dal.RestaurantExiste(resto.Nom))
    {
        ModelState.AddModelError("Nom", "Ce nom de restaurant existe déjà");
        return View(resto);
    }
    if (!ModelState.IsValid)
        return View(resto);
    dal.CreerRestaurant(resto.Nom, resto.Telephone);
    return RedirectToAction("Index");
}

تبسيط إعلان JavaScript مع الحزم(bundles)


لاستخدام كل Ajax الخاص بنا وجميع عمليات التحقق الخاصة بنا ، يجب عليك تضمين JavaScript ... أنت توافق معي ، ليس كل ذلك عمليًا ، ناهيك عن أننا نخاطر بنسيانه. حسنًا ، بفضل التنسيقات ، يمكننا التأكد من تضمين كل شيء مرة واحدة ولكن إذا كانت هناك بعض النصوص التي لا نريد تضمينها في كل مكان؟
هذا هو الحال عادة بالنسبة للتحديث الدوري للعرض الذي يعرض نتيجة التصويت. إذا أعلنت عن هذا النص البرمجي في التخطيط ، فسيحاول تحديث العرض الجزئي لجميع طرق العرض التي نمر بها ، وهذا ليس رائعًا.
لحسن الحظ ، لدينا القدرة على إنشاء مجموعات من البرامج النصية ، تسمى الحزم في المصطلحات ASP.NET MVC . على سبيل المثال ، يمكنني إنشاء حزمة تتضمن جميع النصوص البرمجية jQuery عن طريق إضافة هذا السطر من التعليمات البرمجية:

BundleTable.Bundles.Add(new ScriptBundle("~/toutjquery").Include("~/Scripts/jquery*"));
أعطي الاسم ~ / toutjquery للحزمة التي تتوافق مع إدراج كل شيء في دليل البرامج النصية والذي يبدأ بـ jquery . ثم يمكنني استخدام هذه الحزمة في العرض بالأمر التالي:

@Scripts.Render("~/toutjquery")
من الضروري أن تسبق اسم الحزمة بـ ~ / لتقليد عنوان URL نسبي.
وخلف ذلك ، سيتضمن العرض جميع JavaScript التالية:

<script src="/Scripts/jquery-1.10.2.js"></script>
<script src="/Scripts/jquery-ui-1.10.24.js"></script>
<script src="/Scripts/jquery.unobtrusive-ajax.js"></script>
<script src="/Scripts/jquery.validate.js"></script>
<script src="/Scripts/jquery.validate.unobtrusive.js"></script>
ما هو قوي هو أن الحزمة تضمنت فقط الإصدارات غير المصغرة من jQuery ولكنها أيضًا لم تتضمن الملفات اللازمة للإكمال التلقائي (التي تحتوي على التحسس فيه).
عندما أقوم بالنشر في الإنتاج ، لن تضعني الحزمة فقط الملفات المصغرة فقط ، ولكنها ستتأكد أيضًا من إنشاء ملف واحد فقط مع كل JavaScript لجميع الملفات لتحسين التحميل على جانب العميل (في الواقع ، ملف واحد يحتوي على كل شيء أسرع في التحميل من X ملفات منفصلة صغيرة). قد يتم أيضًا تخزين هذا الملف في ذاكرة التخزين المؤقت بواسطة المتصفح.
لمشاهدته ، ابحث عن السطر التالي في web.config :

<compilation debug="true" targetFramework="4.5" />
وانتقل debug  إلى false  :
<compilation debug="false" targetFramework="4.5" />
يمكنك الآن أن ترى أنه أنتج سطرًا واحدًا لتضمين جميع البرامج النصية ، مثل:

<script src="/toutjquery?v=dqaNVLUlc90HzXHC-4_8M298sQDRyzNY3B4cOzQAAh41"></script>
إذا حاولت عرضه ، فسيكون لديك ملف JavaScript مصغر واحد غير مفهوم:

 (function(n,t){function yu(n){var t=wt[n]={};return i.each(n.split(h),function(n,i){t[i]=!0}),t}function ui[...],n(function(){r.unobtrusive.parse(document)})}(jQuery)
لحسن الحظ ، أنا لا أريكم كل شيء .
يمكنك الآن الرجوع إلى وضع التصحيح في web.config .
إذا حاولت إنشاء تطبيق MVC غير فارغ ، فيمكنك أن ترى أن Visual Studio كان يولد الكثير من الأشياء لنا. ومن بين كل هذه الملفات ، يوجد ملف يسمى BundleConfig.cs الذي تم إنشاؤه بواسطة Visual Studio في مجلد App_Start . إذا كنت تتعمق في ذلك ، يمكنك أن تدرك أن هناك بالفعل الكثير من الحزم التي تم تكوينها وأنك ستكون قادرًا على إعادة الاستخدام:

public static void RegisterBundles(BundleCollection bundles)
{
    bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
                "~/Scripts/jquery-{version}.js"));

    bundles.Add(new ScriptBundle("~/bundles/jqueryui").Include(
                "~/Scripts/jquery-ui-{version}.js"));

    bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
                "~/Scripts/jquery.unobtrusive*",
                "~/Scripts/jquery.validate*"));

 
   bundles.Add(new ScriptBundle("~/bundles/modernizr").Include(
                "~/Scripts/modernizr-*"));

    bundles.Add(new StyleBundle("~/Content/css").Include("~/Content/site.css"));

    bundles.Add(new StyleBundle("~/Content/themes/base/css").Include(
                "~/Content/themes/base/jquery.ui.core.css",
                "~/Content/themes/base/jquery.ui.resizable.css",
                "~/Content/themes/base/jquery.ui.selectable.css",
                "~/Content/themes/base/jquery.ui.accordion.css",
                "~/Content/themes/base/jquery.ui.autocomplete.css",
                "~/Content/themes/base/jquery.ui.button.css",
                "~/Content/themes/base/jquery.ui.dialog.css",
                "~/Content/themes/base/jquery.ui.slider.css",
                "~/Content/themes/base/jquery.ui.tabs.css",
                "~/Content/themes/base/jquery.ui.datepicker.css",
                "~/Content/themes/base/jquery.ui.progressbar.css",
                "~/Content/themes/base/jquery.ui.theme.css"));
}
لاحظ أنه يمكنك حتى تجميع ملفات CSS . في ذلك الوقت ، سيكون عليك استخدام المساعد:

@Styles.Render("~/Content/css")

باختصار


  • يجب على أي تطبيق ويب حديث يحترم نفسه الاستفادة من قوة Ajax .
  • يسمح لك Ajax بتنفيذ طلبات غير متزامنة لاسترداد البيانات وتحديث أجزاء من الصفحات وإرسال النماذج وما إلى ذلك.
  • Ajax يعمل بشكل جيد مع JSON .
  • من الممكن إجراء عمليات تحقق غير متزامنة مع السمة [Remote]  .
  • تستخدم الحزم لتبسيط إعلان ملفات JavaScript لتضمينها.