ASP.NET AJAX 4 : Exemple d’utilisation

8. June 2009 by Davy.Houareau

Nous allons aborder dans cet article un exemple d’utilisation de l’ASP.NET AJAX 4. Cet exemple consiste en l’affichage de produits en fonction de la catégorie sélectionnée. Tout en avançant, nous allons nous attarder sur le fonctionnement de ce nouvel aspect d’ASP.NET AJAX.

Le but de cette nouvelle approche de l’AJAX avec l’ASP.NET est de faire en sorte que le serveur se concentre plus sur l’aspect « donnée » que sur l’aspect « présentation ». En effet, il est possible de faire un site web qui interagit avec une base de données sans aucun contrôle serveur très facilement. C’est sur ce modèle que notre exemple d’utilisation portera (Client « pur » AJAX). On avait l’habitude d’utiliser un script manager couplé à un update panel pour faire de l’AJAX avec nos contrôles serveur et cette technique de rendement partiel nous rendait déjà la tâche assez facile puisqu’on avait de l’AJAX sans patauger dans le JAVASCRIPT. Maintenant, on peut faire de l’AJAX tout aussi simplement sans script manager et sans update panel. Nous verrons ce que sont les nouveaux contrôles client « DataView » et « DataContext »

1. Préparatifs (Exposition de la base de données)

Dans cet exemple nous allons utiliser un ADO.NET Data Service pour interagir avec la base de données, mais il est possible d’utiliser un ASMX ou encore WCF. Les possibilités sont multiples à conditions que le service soit compatible JSON (JavaScript Object Notation -> un format d’échange de données). Commençons par créer un nouveau projet « ASP.NET Web Application » puis ajoutons un ADO.NET Entity Data Model qui pointe sur la base de données que nous intéresse (ici Northwind). Appelons le, ADOEntityDataModel.

Maintenant nous allons pouvoir exposer cet Entity Data Model via un ADO.NET Data Service que nous appellerons MyWebDataService. Puis nous pourrons modifier MyWebDataService.svc pour pouvoir lui associer l’Entity Data Model.

Il faut modifier l’héritage en rajoutant le nom de classe de la source de données. Ici NorthwindEntities. Par défaut c’est le [nom_de_la_base_de_données+Entities]. Vous trouverez ce nom dans le fichier designer de l’Entity Data Model. Notre Entity Data Model est maintenant associé au service mais nous n’avons pas défini ce qui était exposé et de quelle manière. Pour cela nous utiliserons config.SetEntitySetAccessRule("*", EntitySetRights.All);. « * » pour dire que tout est visible et EntitySetRights.All pour autoriser la lecture et l’écriture.

Ce qui donne le code ci-dessous :

public class MyWebDataService : DataService<NorthwindEntities>

    {

        // This method is called only once to initialize service-wide policies.

        public static void InitializeService(IDataServiceConfiguration config)

        {

            config.SetEntitySetAccessRule("*", EntitySetRights.All);

        }

    }

Certes pour notre exemple la sécurité n’est pas optimale mais nous voici avec une base de données exposée assez simplement. Il ne nous reste plus qu’a nous concentrer sur l’ASP.NET AJAX 4 :).

2. Utilisation

Puisque notre exemple porte sur un client « pur » AJAX, supprimons le fichier Default.aspx et ajoutons un simple fichier html que nous nommerons categories.htm. Pour pouvoir utiliser ASP.NET AJAX 4 nous avons besoin de quelques fichiers JavaScript que vous pouvez trouver sur CODEPLEX.

3 Fichiers sont nécessaires:

  • MicrosoftAjax.js (base obligatoire)
  • MicrosoftAjaxAdoNet.js (on utilise de l’ADO.NET)
  • MicrosoftAjaxTemplates.js (pour avoir des templates où nous afficherons les données)

Ajoutons donc un répertoire « Scripts » et nos 3 fichiers JavaScript puis incluons-les dans notre page categories.htm.

Ce n’est pas tout, il nous faut aussi ajouter deux namespaces:

  • xmlns:sys="javascript:Sys"
  • xmlns:dataview="javascript:Sys.UI.DataView" (nous verrons un peu plus tard le Dataview)
  • sys:activate="*" (activer tous les éléments de la page pour le support d’attributs sys, On l’utilisera pour la sélection)

Notre page categories.html ressemble donc à ceci :

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >

<head>

    <title>Categories</title>

    <link type="text/javascript" href="Content/Scripts/MicrosoftAjax.js" />

    <link type="text/javascript" href="Content/Scripts/MicrosoftAjaxAdoNet.js" />

    <link type="text/javascript" href="Content/Scripts/MicrosoftAjaxTemplates.debug.js" />

</head>

<body xmlns:sys="javascript:Sys"

      xmlns:dataview="javascript:Sys.UI.DataView"

      sys:activate="*">

</body>

</html>

Maintenant, nous sommes prêts à aborder le template client.

Grâce à ASP.NET AJAX 4, presque n’importe quelle balise html peut devenir un template dans le lequel on pourra faire du binding. Pour qu’une balise soit reconnue en tant que template, il faut qu’elle possède l’attribut class="sys-template". Ce nom est une convention et doit être utilisé simplement parce que le moteur de rendu cherchera ce nom de classe pour manipuler le template. Il est conseillé de définir cette classe dans le CSS en tant que display:none;. Lors de l’affichage, ce style sera modifié automatiquement afin de voir le résultat.

Pour notre exemple, notre template sera une balise tbody.

    <table cellspacing="0">

        <thead>

            <tr><th colspan="2">Categories</th></tr>

            <tr><th>Name</th><th>Description</th></tr>

        </thead>

        <tbody class="sys-template">

        </tbody>

    </table>

.sys-template

{

    display: none;

}

Une fois la balise reconnue en tant que template, il ne reste plus qu’à faire du binding et il est possible d’en faire n’importe où à l’intérieur du template. Il existe deux écritures possibles : une courte, une longue. L’écriture courte se contente de rendre la valeur de la propriété de l’objet telle quelle et elle se présente de cette façon : {{ MyProperty }}. Ce type de binding se fait dans un seul sens et une seule fois (one-time binding). En ce qui concerne l’écriture longue, l’équivalent de {{ MyProperty }} est : {binding MyProperty, mode=oneWay}. L’écriture longue permet de faire du binding bidirectionnelle et d’utiliser une fonction pour « convertir » le rendu de la Valeur. Pour faire du bidirectionnel, il suffit de { binding MyProperty }. Quand on parle ici de binding bidirectionnelle, c’est au sein du même contexte.

Le template fourni également des pseudo-colonnes prédéfinies qui permettent d’accéder à des valeurs bien utiles comme $index, $dataitem, $id, $element.

  • $index : l’index de l’élément courant. (pratique un style alternatif)
  • $dataitem : l’élément courant
  • $id("ID") : créer ou accède à un identifiant unique pour l’élément en court. La valeur sera le nom spécifié + l’index (ici « ID3 » par exemple)
  • $element : récupère la balise dans laquelle ce mot clé est spécifié (ex :<div>{{$element}}</div>retournera la balise div).
C’est le bon moment pour aborder les deux nouveaux contrôles client que nous apporte ASP.NET AJAX 4 : le DataView et le DataContext.

Le DataContext est un proxy qui va communiquer avec un service sachant utiliser des données sous forme de JSON. C’est lui qui fera la liaison entre le client et le service.

Voici comment le déclarer :

<script type="text/javascript">

        var dataContext = $create(

            Sys.Data.AdoNetDataContext, { serviceUri: "MyWebDataService.svc" });

</script>

Vu que nous utilisons ADO.NET nous sommes obligés de déclarer notre DataContext de cette façon avec Sys.Data.AdoNetDataContext.

Le DataView, quant à lui, doit être associé à un template. Il peut traiter une collection d’éléments en répliquant l’instance de son template pour chaque élément de la collection. Il peut être utilisé pour un affichage sous forme de détail ou de liste. Il possède pas mal de points important pour sa configuration. Nous ne verrons que ceux dont nous aurons besoin.

Pour notre exemple voici à quoi doit ressembler notre balise tbody :

<tbody class="sys-template"

               sys:attach="dataview"

               dataview:sys-key="master"

               dataview:dataprovider="{{dataContext}}"

               dataview:autofetch="true"

               dataview:fetchoperation="Categories"

               dataview:selecteditemclass="rowSelected"

               dataview:fetchparameters="{{ {$expand: 'Products'} }}"

               dataview:initialselectedindex="0">

</tbody>

Quelques explications s’imposent non ?

  • sys:attach="dataview" : permet de déclarer le DataView
  • dataview:sys-key="master" : permet d’identifier le DataView (ici notre DataView s’appelle master)
  • dataprovider="{{dataContext}}" : permet de binder le DataView au DataContext déclaré plus haut.
  • dataview:autofetch="true" : récupérer les données au chargement de la page.
  • dataview:fetchoperation="Categories" : La fonction du service à appeler pour récupérer les données
  • dataview:selecteditemclass="rowSelected" : style pour la ligne sélectionnée.
  • dataview:fetchparameters="{{ {$expand: 'Products'} }}" : fetchparameters pour passer des paramètres à la requête et ici $expand permet de récupérer les éléments de la propriété de navigation « Products » de l’Entity Set « Categories » (Ce qui nous servira pour afficher les produits des catégories plus tard).
  • dataview:initialselectedindex="0" : Présélectionner un élément par défaut.

Il nous manque maintenant le binding. Vu que nous n’avons pas besoin ici de binding bidirectionnel, nous utiliserons l’écriture courte.

Voici à quoi notre binding ressemble :

<tr sys:command="select" class:alternaterow="{{ $index % 2 != 0 }}">

    <td>

        {{ CategoryName }}

    </td>

    <td>

        {{ Description }}

    </td>

</tr>

Notez la présence deux attributs « spéciaux » :

  • sys:command="select" : permet la sélection de l’élément.
  • class:alternaterow="{{ $index % 2 != 0 }}" : petite astuce pour avoir un style alternatif. Le style ici sera alternaterow.

N’oublions pas de rajouter ces classes dans le style :

.rowSelected

{

    color:Red;

}

.alternaterow

{

    background-color:#A3B8FF;

}

Il ne nous reste plus qu’a nous occuper de l’affichage des produits. Là aussi, il nous faut utiliser un DataView que nous lierons au premier.

Voici le DataView pour l’affichage des produits :

<table cellspacing="0">

        <thead>

            <tr>

                <th colspan="2">

                    Products

                </th>

            </tr>

            <tr>

                <th>

                    Name

                </th>

                <th>

                    Price

                </th>

            </tr>

        </thead>

        <tbody id="product-template" class="sys-template" sys:attach="dataview" dataview:data="{binding selectedData.Products, source={{master}} }">

            <tr>

                <td>

                    {binding ProductName}

                </td>

                <td>

                    {binding UnitPrice}

                </td>

            </tr>

        </tbody>

    </table>

Ici, la seule nouveauté c’est : dataview:data="{binding selectedData.Products, source={{master}} }" : Tout simplement pour indiquer que les données qui vont être utilisées par ce DataView proviennent de l’élément sélectionné dans le DataView « master ».

Et nous voici au résultat tant attendu :

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">

<head>

    <title>Categories</title>

    <link href="Style/style.css" rel="stylesheet" type="text/css" />

    <script src="Scripts/MicrosoftAjax.js" type="text/javascript"></script>

    <script src="Scripts/MicrosoftAjaxTemplates.js" type="text/javascript"></script>

    <script src="Scripts/MicrosoftAjaxAdoNet.js" type="text/javascript"></script>

    <script type="text/javascript">

        var dataContext = $create(Sys.Data.AdoNetDataContext, { serviceUri: "MyWebDataService.svc" });

    </script>

    <style type="text/css">

        .sys-template

        {

            display: none;

        }

        .rowSelected

        {

            color:Red;

        }

        .alternaterow

        {

             background-color:#A3B8FF;

        }

    </style>

</head>

<body xmlns:sys="javascript:Sys"

      xmlns:dataview="javascript:Sys.UI.DataView"

      sys:activate="*">

       

    <table cellspacing="0">

        <thead>

            <tr>

                <th colspan="2">

                    Categories

                </th>

            </tr>

            <tr>

                <th>

                    Name

                </th>

                <th>

                    Description

                </th>

            </tr>

        </thead>

        <tbody class="sys-template"

               sys:attach="dataview"

               dataview:sys-key="master"

               dataview:dataprovider="{{dataContext}}"

               dataview:autofetch="true"

               dataview:fetchoperation="Categories"

               dataview:selecteditemclass="rowSelected"

               dataview:fetchparameters="{{ {$expand: 'Products'} }}"

               dataview:initialselectedindex="0">

            <tr sys:command="select" class:alternaterow="{{ $index % 2 != 0 }}">

                <td>

                    {{ CategoryName }}

                </td>

                <td>

                    {{ Description }}

                </td>

            </tr>

        </tbody>

    </table>

    <table cellspacing="0">

        <thead>

            <tr>

                <th colspan="2">

                    Products

                </th>

            </tr>

            <tr>

                <th>

                    Name

                </th>

                <th>

                    Price

                </th>

            </tr>

        </thead>

        <tbody id="product-template" class="sys-template" sys:attach="dataview" dataview:data="{binding selectedData.Products, source={{master}} }">

            <tr>

                <td>

                    {binding ProductName}

                </td>

                <td>

                    {binding UnitPrice}

                </td>

            </tr>

        </tbody>

    </table>

</body>

</html>

3.Conclusion

Comme vous avez pu le constater, nous avons pu réaliser un client « pure » AJAX en écrivant deux lignes de JAVASCRIPT grâce a ASP.NET AJA 4 . Evidement nous avons abordé un exemple précis mais cette nouvelle façon de faire de l’AJAX offre beaucoup d’autres possibilités d’utilisation.

ADO.NET, ASP.NET AJAX