Présentation des services web ASP.NET AJAX
par Scott Cate
Les services web font partie intégrante du .NET Framework qui fournit une solution multiplateforme pour échanger des données entre des systèmes distribués. Bien que les services Web soient normalement utilisés pour permettre à différents systèmes d’exploitation, modèles objet et langages de programmation d’envoyer et de recevoir des données, ils peuvent également être utilisés pour injecter dynamiquement des données dans une page AJAX ASP.NET ou envoyer des données d’une page à un système back-end. Tout cela peut être fait sans recourir à des opérations de publication.
Appel de services web avec ASP.NET AJAX
Dan Wahlin
Les services web font partie intégrante du .NET Framework qui fournit une solution multiplateforme pour échanger des données entre des systèmes distribués. Bien que les services Web soient normalement utilisés pour permettre à différents systèmes d’exploitation, modèles objet et langages de programmation d’envoyer et de recevoir des données, ils peuvent également être utilisés pour injecter dynamiquement des données dans une page AJAX ASP.NET ou envoyer des données d’une page à un système back-end. Tout cela peut être fait sans recourir à des opérations de publication.
Bien que le contrôle ASP.NET AJAX UpdatePanel offre un moyen simple d’activer n’importe quelle page ASP.NET, il peut arriver que vous deviez accéder dynamiquement aux données sur le serveur sans utiliser de UpdatePanel. Dans cet article, vous allez découvrir comment procéder en créant et en consommant des services web dans ASP.NET pages AJAX.
Cet article se concentre sur les fonctionnalités disponibles dans les extensions AJAX de base ASP.NET ainsi qu’un contrôle activé par le service web dans le kit de ressources AJAX ASP.NET appelé AutoCompleteExtender. Les rubriques abordées incluent la définition des services web compatibles AJAX, la création de proxys clients et l’appel de services web avec JavaScript. Vous verrez également comment les appels de service web peuvent être effectués directement vers ASP.NET méthodes de page.
Web Services Configuration
Lorsqu’un projet de site web est créé avec Visual Studio 2008, le fichier web.config comporte un certain nombre d’ajouts qui peuvent être inconnus des utilisateurs des versions précédentes de Visual Studio. Certaines de ces modifications mappent le préfixe « asp » à ASP.NET contrôles AJAX afin qu’ils puissent être utilisés dans les pages, tandis que d’autres définissent httpHandlers et HttpModules requis. La liste 1 affiche les modifications apportées à l’élément <httpHandlers>
dans web.config qui affecte les appels de service web. Le gestionnaire HTTP par défaut utilisé pour traiter les appels .asmx est supprimé et remplacé par une classe ScriptHandlerFactory située dans l’assembly System.Web.Extensions.dll. System.Web.Extensions.dll contient toutes les fonctionnalités principales utilisées par ASP.NET AJAX.
Liste 1. configuration du gestionnaire de service web AJAX ASP.NET
<httpHandlers>
<remove verb="*" path="*.asmx"/>
<add verb="*" path="*.asmx" validate="false"
type="System.Web.Script.Services.ScriptHandlerFactory,
System.Web.Extensions, Version=1.0.61025.0, Culture=neutral,
PublicKeyToken=31bf3856ad364e35"/>
</httpHandlers>
Ce remplacement de HttpHandler est effectué afin d’autoriser l’envoi d’appels JSON (JavaScript Object Notation) à partir de ASP.NET pages AJAX vers les services web .NET à l’aide d’un proxy de service web JavaScript. ASP.NET AJAX envoie des messages JSON aux services Web par opposition aux appels SOAP (Simple Object Access Protocol) standard associés aux services Web. Cela entraîne des messages de demande et de réponse plus petits dans l’ensemble. Il permet également un traitement côté client plus efficace des données, car la bibliothèque JavaScript AJAX ASP.NET est optimisée pour fonctionner avec des objets JSON. La liste 2 et la liste 3 affichent des exemples de messages de demande et de réponse de service web sérialisés au format JSON. Le message de demande indiqué dans Listing 2 transmet un paramètre de pays avec la valeur « Belgique » tandis que le message de réponse dans Listing 3 transmet un tableau d’objets Customer et leurs propriétés associées.
Liste 2. Message de demande de service web sérialisé au format JSON
{"country":"Belgium"}
> [! REMARQUE] Le nom de l’opération est défini dans le cadre de l’URL du service web ; de plus, les messages de demande ne sont pas toujours envoyés via JSON. Les services web peuvent utiliser l’attribut ScriptMethod avec le paramètre UseHttpGet défini sur true, ce qui entraîne le passage de paramètres via les paramètres de chaîne de requête.
Liste 3. Message de réponse de service web sérialisé au format JSON
[{"__type":"Model.Customer","Country":"Belgium","CompanyName":"Maison
Dewey","CustomerID":"MAISD","ContactName":"Catherine
Dewey"},{"__type":"Model.Customer","Country":"Belgium","CompanyName":"Suprêmes
délices","CustomerID":"SUPRD","ContactName":"Pascale
Cartrain"}]
Dans la section suivante, vous allez voir comment créer des services Web capables de gérer les messages de requête JSON et de répondre avec des types simples et complexes.
Création de services web compatibles AJAX
L’infrastructure AJAX ASP.NET fournit plusieurs façons d’appeler des services web. Vous pouvez utiliser le contrôle AutoCompleteExtender (disponible dans le kit de ressources ASP.NET AJAX) ou JavaScript. Toutefois, avant d’appeler un service, vous devez l’activer avec AJAX afin qu’il puisse être appelé par le code de script client.
Que vous ne soyez pas ou non nouveau dans ASP.NET services web, vous trouverez qu’il est simple de créer et d’activer les services AJAX. Le .NET Framework a pris en charge la création de services web ASP.NET depuis sa version initiale en 2002 et les extensions AJAX ASP.NET fournissent des fonctionnalités AJAX supplémentaires qui s’appuient sur l’ensemble par défaut de fonctionnalités du .NET Framework. Visual Studio .NET 2008 Beta 2 prend en charge la création de fichiers de service web .asmx et dérive automatiquement le code associé en plus des classes de la classe System.Web.Services.WebService. Lorsque vous ajoutez des méthodes à la classe, vous devez appliquer l’attribut WebMethod pour qu’il soit appelé par les consommateurs du service Web.
La liste 4 montre un exemple d’application de l’attribut WebMethod à une méthode nommée GetCustomersByCountry().
Liste 4. Utilisation de l’attribut WebMethod dans un service web
[WebMethod]
public Customer[] GetCustomersByCountry(string country)
{
return Biz.BAL.GetCustomersByCountry(country);
}
La méthode GetCustomersByCountry() accepte un paramètre de pays et retourne un tableau d’objets Customer. La valeur de pays passée dans la méthode est transférée à une classe de couche métier qui appelle à son tour une classe de couche de données pour récupérer les données de la base de données, remplir les propriétés de l’objet Customer avec des données et retourner le tableau.
Utilisation de l’attribut ScriptService
Lors de l’ajout de l’attribut WebMethod, la méthode GetCustomersByCountry() doit être appelée par les clients qui envoient des messages SOAP standard au service web, mais elle n’autorise pas les appels JSON à effectuer à partir d’ASP.NET applications AJAX prêtes à l’emploi. Pour autoriser les appels JSON à effectuer, vous devez appliquer l’attribut de l’extension ScriptService
AJAX ASP.NET à la classe de service web. Cela permet à un service web d’envoyer des messages de réponse mis en forme à l’aide de JSON et permet au script côté client d’appeler un service en envoyant des messages JSON.
La liste 5 montre un exemple d’application de l’attribut ScriptService à une classe de service web nommée CustomersService.
Liste 5. Utilisation de l’attribut ScriptService pour activer un service web
[System.Web.Script.Services.ScriptService]
[WebService(Namespace = "http://xmlforasp.net")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class CustomersService : System.Web.Services.WebService
{
[WebMethod]
public Customer[] GetCustomersByCountry(string country)
{
return Biz.BAL.GetCustomersByCountry(country);
}
}
L’attribut ScriptService agit comme un marqueur qui indique qu’il peut être appelé à partir du code de script AJAX. Elle ne gère pas réellement les tâches de sérialisation ou de désérialisation JSON qui se produisent en arrière-plan. ScriptHandlerFactory (configuré dans web.config) et d’autres classes associées effectuent la majeure partie du traitement JSON.
Utilisation de l’attribut ScriptMethod
L’attribut ScriptService est le seul attribut ASP.NET AJAX qui doit être défini dans un service web .NET afin qu’il soit utilisé par ASP.NET pages AJAX. Toutefois, un autre attribut nommé ScriptMethod peut également être appliqué directement aux méthodes web dans un service. ScriptMethod définit trois propriétés, notamment UseHttpGet
, ResponseFormat
et XmlSerializeString
. La modification des valeurs de ces propriétés peut être utile dans les cas où le type de requête accepté par une méthode web doit être modifié en GET, lorsqu’une méthode Web doit retourner des données XML brutes sous la forme d’un ou d’un XmlDocument
objet ou XmlElement
lorsque les données retournées à partir d’un service doivent toujours être sérialisées en tant que XML au lieu de JSON.
La propriété UseHttpGet peut être utilisée lorsqu’une méthode web doit accepter des requêtes GET par opposition aux requêtes POST. Les requêtes sont envoyées à l’aide d’une URL avec des paramètres d’entrée de méthode web convertis en paramètres QueryString. La propriété UseHttpGet a la valeur false par défaut et doit être définie true
uniquement sur le moment où les opérations sont connues pour être sécurisées et lorsque les données sensibles ne sont pas passées à un service Web. La liste 6 montre un exemple d’utilisation de l’attribut ScriptMethod avec la propriété UseHttpGet.
Liste 6. Utilisation de l’attribut ScriptMethod avec la propriété UseHttpGet.
[WebMethod]
[ScriptMethod(UseHttpGet = true)]
public string HttpGetEcho(string input)
{
return input;
}
Voici un exemple d’en-têtes envoyés lorsque la méthode web HttpGetEcho affichée dans la liste 6 est appelée :
GET /CustomerViewer/DemoService.asmx/HttpGetEcho?input=%22Input Value%22 HTTP/1.1
En plus d’autoriser les méthodes web à accepter les requêtes HTTP GET, l’attribut ScriptMethod peut également être utilisé lorsque les réponses XML doivent être retournées à partir d’un service plutôt que JSON. Par exemple, un service web peut récupérer un flux RSS à partir d’un site distant et le retourner en tant qu’objet XmlDocument ou XmlElement. Le traitement des données XML peut ensuite se produire sur le client.
La liste 7 montre un exemple d’utilisation de la propriété ResponseFormat pour spécifier que les données XML doivent être retournées à partir d’une méthode web.
Liste 7. Utilisation de l’attribut ScriptMethod avec la propriété ResponseFormat.
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Xml)]
public XmlElement GetRssFeed(string url)
{
XmlDocument doc = new XmlDocument();
doc.Load(url);
return doc.DocumentElement;
}
La propriété ResponseFormat peut également être utilisée avec la propriété XmlSerializeString. La propriété XmlSerializeString a une valeur par défaut false, ce qui signifie que tous les types de retour, sauf les chaînes retournées à partir d’une méthode Web, sont sérialisées en tant que XML lorsque la ResponseFormat
propriété est définie ResponseFormat.Xml
sur . Lorsqu’il XmlSerializeString
est défini true
sur , tous les types retournés à partir d’une méthode web sont sérialisés en tant que XML, y compris les types de chaînes. Si la propriété ResponseFormat a une valeur de ResponseFormat.Json
la propriété XmlSerializeString est ignorée.
La liste 8 montre un exemple d’utilisation de la propriété XmlSerializeString pour forcer la sérialisation des chaînes en tant que XML.
Liste 8. Utilisation de l’attribut ScriptMethod avec la propriété XmlSerializeString
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Xml,XmlSerializeString=true)]
public string GetXmlString(string input)
{
return input;
}
La valeur retournée à partir de l’appel de la méthode web GetXmlString indiquée dans La liste 8 s’affiche ensuite :
<?xml version="1.0"?>
<string>Test</string>
Bien que le format JSON par défaut réduit la taille globale des messages de requête et de réponse et soit plus facilement consommé par ASP.NET clients AJAX de manière inter-navigateur, les propriétés ResponseFormat et XmlSerializeString peuvent être utilisées lorsque les applications clientes telles qu’Internet Explorer 5 ou une version ultérieure s’attendent à ce que les données XML soient retournées à partir d’une méthode Web.
Utilisation de types complexes
La liste 5 a montré un exemple de renvoi d’un type complexe nommé Customer à partir d’un service web. La classe Customer définit plusieurs types simples différents en interne en tant que propriétés telles que FirstName et LastName. Les types complexes utilisés comme paramètre d’entrée ou type de retour sur une méthode web compatible AJAX sont automatiquement sérialisés en JSON avant d’être envoyés côté client. Toutefois, les types complexes imbriqués (ceux définis en interne dans un autre type) ne sont pas mis à la disposition du client en tant qu’objets autonomes par défaut.
Dans les cas où un type complexe imbriqué utilisé par un service web doit également être utilisé dans une page cliente, l’attribut ASP.NET AJAX GenerateScriptType peut être ajouté au service web. Par exemple, la classe CustomerDetails indiquée dans Listing 9 contient les propriétés Address et Gender qui représentent des types complexes imbriqués.
Liste 9. La classe CustomerDetails présentée ici contient deux types complexes imbriqués.
public class CustomerDetails : Customer
{
public CustomerDetails()
{
}
Address _Address;
Gender _Gender = Gender.Unknown;
public Address Address
{
get { return _Address; }
set { _Address = value; }
}
public Gender Gender
{
get { return _Gender; }
set { _Gender = value; }
}
}
Les objets Address et Gender définis dans la classe CustomerDetails indiquée dans la liste 9 ne seront pas automatiquement mis à disposition pour une utilisation côté client via JavaScript, car ils sont des types imbriqués (Address est une classe et Gender est une énumération). Dans les cas où un type imbriqué utilisé dans un service web doit être disponible côté client, l’attribut GenerateScriptType mentionné précédemment peut être utilisé (voir Listing 10). Cet attribut peut être ajouté plusieurs fois dans les cas où différents types complexes imbriqués sont retournés à partir d’un service. Elle peut être appliquée directement à la classe de service Web ou aux méthodes web spécifiques.
Liste 10. Utilisation de l’attribut GenerateScriptService pour définir des types imbriqués qui doivent être disponibles pour le client.
[System.Web.Script.Services.ScriptService]
[System.Web.Script.Services.GenerateScriptType(typeof(Address))]
[System.Web.Script.Services.GenerateScriptType(typeof(Gender))]
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class NestedComplexTypeService : System.Web.Services.WebService
{
//Web Methods
}
En appliquant l’attribut GenerateScriptType
au service web, les types Address and Gender sont automatiquement mis à disposition pour une utilisation par ASP.NET code JavaScript AJAX côté client. Un exemple de JavaScript généré et envoyé automatiquement au client en ajoutant l’attribut GenerateScriptType sur un service web est affiché dans La liste 11. Vous verrez comment utiliser des types complexes imbriqués plus loin dans l’article.
Liste 11. Types complexes imbriqués mis à la disposition d’une page ASP.NET AJAX.
if (typeof(Model.Address) === 'undefined')
{
Model.Address=gtc("Model.Address");
Model.Address.registerClass('Model.Address');
}
Model.Gender = function() { throw Error.invalidOperation(); }
Model.Gender.prototype = {Unknown: 0,Male: 1,Female: 2}
Model.Gender.registerEnum('Model.Gender', true);
Maintenant que vous avez vu comment créer des services Web et les rendre accessibles à ASP.NET pages AJAX, examinons comment créer et utiliser des proxys JavaScript afin que les données puissent être récupérées ou envoyées aux services Web.
Création de proxys JavaScript
L’appel d’un service web standard (.NET ou d’une autre plateforme) implique généralement la création d’un objet proxy qui vous protège contre la complexité de l’envoi de messages de requête et de réponse SOAP. Avec ASP.NET appels de service web AJAX, des proxys JavaScript peuvent être créés et utilisés pour appeler facilement des services sans vous soucier de la sérialisation et de la désérialisation des messages JSON. Les proxys JavaScript peuvent être générés automatiquement à l’aide du contrôle ASP.NET AJAX ScriptManager.
La création d’un proxy JavaScript qui peut appeler des services Web est effectuée à l’aide de la propriété Services de ScriptManager. Cette propriété vous permet de définir un ou plusieurs services qu’une page AJAX ASP.NET peut appeler de manière asynchrone pour envoyer ou recevoir des données sans nécessiter d’opérations de publication. Vous définissez un service à l’aide du contrôle ASP.NET AJAX ServiceReference
et de l’affectation de l’URL du service web à la propriété du Path
contrôle. La liste 12 montre un exemple de référencement d’un service nommé CustomersService.asmx.
<asp:ScriptManager ID="ScriptManager1" runat="server">
<Services>
<asp:ServiceReference Path="~/CustomersService.asmx" />
</Services>
</asp:ScriptManager>
Liste 12. Définition d’un service web utilisé dans une page AJAX ASP.NET.
L’ajout d’une référence à CustomersService.asmx par le biais du contrôle ScriptManager entraîne la génération dynamique d’un proxy JavaScript et référencé par la page. Le proxy est incorporé à l’aide de la balise de <script> et chargé dynamiquement en appelant le fichier CustomersService.asmx et en ajoutant /js à la fin de celui-ci. L’exemple suivant montre comment le proxy JavaScript est incorporé dans la page lorsque le débogage est désactivé dans web.config :
<script src="CustomersService.asmx/js" type="text/javascript"></script>
> [! REMARQUE] Si vous souhaitez voir le code de proxy JavaScript réel généré, vous pouvez taper l’URL vers le service web .NET souhaité dans la zone d’adresse d’Internet Explorer et ajouter /js à la fin de celui-ci.
Si le débogage est activé dans web.config, une version de débogage du proxy JavaScript est incorporée dans la page, comme indiqué ci-dessous :
<script src="CustomersService.asmx/jsdebug" type="text/javascript"></script>
Le proxy JavaScript créé par ScriptManager peut également être incorporé directement dans la page plutôt que référencé à l’aide de l’attributrc de la <balise de script> . Pour ce faire, définissez la propriété InlineScript du contrôle ServiceReference sur true (la valeur par défaut est false). Cela peut être utile lorsqu’un proxy n’est pas partagé sur plusieurs pages et que vous souhaitez réduire le nombre d’appels réseau effectués au serveur. Lorsque InlineScript est défini sur true, le script proxy ne sera pas mis en cache par le navigateur. Par conséquent, la valeur par défaut false est recommandée dans les cas où le proxy est utilisé par plusieurs pages dans une application AJAX ASP.NET. Voici un exemple d’utilisation de la propriété InlineScript :
<asp:ServiceReference InlineScript="true" Path="~/CustomersService.asmx"/>
Utilisation de proxys JavaScript
Une fois qu’un service web est référencé par une page AJAX ASP.NET à l’aide du contrôle ScriptManager, un appel peut être effectué au service Web et les données retournées peuvent être gérées à l’aide de fonctions de rappel. Un service web est appelé en référençant son espace de noms (le cas échéant), le nom de la classe et le nom de la méthode web. Tous les paramètres passés au service web peuvent être définis avec une fonction de rappel qui gère les données retournées.
Un exemple d’utilisation d’un proxy JavaScript pour appeler une méthode web nommée GetCustomersByCountry() est illustré dans La liste 13. La fonction GetCustomersByCountry() est appelée lorsqu’un utilisateur final clique sur un bouton sur la page.
Liste 13. Appel d’un service web avec un proxy JavaScript.
function GetCustomerByCountry()
{
var country = $get("txtCountry").value;
InterfaceTraining.CustomersService.GetCustomersByCountry(country, OnWSRequestComplete);
}
function OnWSRequestComplete(results)
{
if (results != null)
{
CreateCustomersTable(results);
GetMap(results);
}
}
Cet appel fait référence à l’espace de noms InterfaceTraining, à la classe CustomersService et à la méthode web GetCustomersByCountry définie dans le service. Il transmet une valeur de pays obtenue à partir d’une zone de texte ainsi qu’une fonction de rappel nommée OnWSRequestComplete qui doit être appelée lorsque l’appel de service web asynchrone retourne. OnWSRequestComplete gère le tableau d’objets Customer retournés par le service et les convertit en une table affichée dans la page. La sortie générée à partir de l’appel est illustrée dans la figure 1.
Figure 1 : Liaison de données obtenues en effectuant un appel AJAX asynchrone à un service web. (Cliquez pour afficher l’image de taille complète)
Les proxys JavaScript peuvent également effectuer des appels unidirectionnel vers des services Web dans les cas où une méthode web doit être appelée, mais le proxy ne doit pas attendre une réponse. Par exemple, vous pouvez appeler un service web pour démarrer un processus tel qu’un flux de travail, mais pas attendre une valeur de retour du service. Dans les cas où un appel unidirectionnel doit être effectué vers un service, la fonction de rappel indiquée dans la liste 13 peut simplement être omise. Étant donné qu’aucune fonction de rappel n’est définie, l’objet proxy n’attend pas que le service Web retourne des données.
Gestion des erreurs
Les rappels asynchrones vers les services Web peuvent rencontrer différents types d’erreurs, tels que le réseau en cours de panne, le service Web étant indisponible ou une exception retournée. Heureusement, les objets proxy JavaScript générés par ScriptManager permettent à plusieurs rappels d’être définis pour gérer les erreurs et les échecs en plus du rappel de réussite indiqué précédemment. Une fonction de rappel d’erreur peut être définie immédiatement après la fonction de rappel standard dans l’appel à la méthode Web, comme indiqué dans la liste 14.
Liste 14. Définition d’une fonction de rappel d’erreur et affichage d’erreurs.
function GetCustomersByCountry()
{
var country = $get("txtCountry").value;
InterfaceTraining.CustomersService.GetCustomersByCountry(country,
OnWSRequestComplete, OnWSRequestFailed);
}
function OnWSRequestFailed(error)
{
alert("Stack Trace: " + error.get_stackTrace() + "/r/n" +
"Error: " + error.get_message() + "/r/n" +
"Status Code: " + error.get_statusCode() + "/r/n" +
"Exception Type: " + error.get_exceptionType() + "/r/n" +
"Timed Out: " + error.get_timedOut());
}
Toutes les erreurs qui se produisent lorsque le service web est appelé déclenchent la fonction de rappel OnWSRequestFailed() à appeler qui accepte un objet représentant l’erreur en tant que paramètre. L’objet d’erreur expose plusieurs fonctions différentes pour déterminer la cause de l’erreur, ainsi que si l’appel a expiré ou non. La liste 14 montre un exemple d’utilisation des différentes fonctions d’erreur et de la figure 2 montre un exemple de sortie générée par les fonctions.
Figure 2 : Sortie générée en appelant ASP.NET fonctions d’erreur AJAX. (Cliquez pour afficher l’image de taille complète)
Gestion des données XML retournées à partir d’un service web
Précédemment, vous avez vu comment une méthode web pouvait retourner des données XML brutes à l’aide de l’attribut ScriptMethod, ainsi que sa propriété ResponseFormat. Lorsque ResponseFormat est défini sur ResponseFormat.Xml, les données retournées par le service web sont sérialisées en tant que XML plutôt que JSON. Cela peut être utile lorsque les données XML doivent être transmises directement au client pour le traitement à l’aide de JavaScript ou XSLT. À l’heure actuelle, Internet Explorer 5 ou version ultérieure fournit le meilleur modèle objet côté client pour l’analyse et le filtrage des données XML en raison de sa prise en charge intégrée de MSXML.
La récupération de données XML à partir d’un service web n’est pas différente de la récupération d’autres types de données. Commencez par appeler le proxy JavaScript pour appeler la fonction appropriée et définir une fonction de rappel. Une fois l’appel retourné, vous pouvez traiter les données dans la fonction de rappel.
La liste 15 montre un exemple d’appel d’une méthode web nommée GetRssFeed() qui retourne un objet XmlElement. GetRssFeed() accepte un paramètre unique représentant l’URL du flux RSS à récupérer.
Liste 15. Utilisation des données XML retournées à partir d’un service web.
function GetRss()
{
InterfaceTraining.DemoService.GetRssFeed(
"https://blogs.interfacett.com/dan-wahlins-blog/rss.xml",
OnWSRequestComplete);
}
function OnWSRequestComplete(result)
{
if (document.all) //Filter for IE DOM since other browsers are limited
{
var items = result.selectNodes("//item");
for (var i=0;i<items.length;i++)
{
var title = items[i].selectSingleNode("title").text;
var href = items[i].selectSingleNode("link").text;
$get("divOutput").innerHTML +=
"<a href='" + href + "'>" + title + "</a><br/>";
}
}
else
{
$get("divOutput").innerHTML = "RSS only available in IE5+";
}
}
Cet exemple transmet une URL à un flux RSS et traite les données XML retournées dans la fonction OnWSRequestComplete(). OnWSRequestComplete() vérifie d’abord si le navigateur est Internet Explorer pour savoir si l’analyseur MSXML est disponible ou non. Si c’est le cas, une instruction XPath est utilisée pour localiser toutes les <balises d’élément> dans le flux RSS. Chaque élément est ensuite itéré et les balises de titre> et <de lien> associées <sont situées et traitées pour afficher les données de chaque élément. La figure 3 montre un exemple de sortie générée à partir d’un appel AJAX ASP.NET via un proxy JavaScript vers la méthode web GetRssFeed().
Gestion des types complexes
Les types complexes acceptés ou retournés par un service web sont automatiquement exposés via un proxy JavaScript. Toutefois, les types complexes imbriqués ne sont pas directement accessibles côté client, sauf si l’attribut GenerateScriptType est appliqué au service comme indiqué précédemment. Pourquoi voulez-vous utiliser un type complexe imbriqué côté client ?
Pour répondre à cette question, supposons qu’une page ASP.NET AJAX affiche les données client et permet aux utilisateurs finaux de mettre à jour l’adresse d’un client. Si le service Web spécifie que le type d’adresse (type complexe défini dans une classe CustomerDetails) peut être envoyé au client, le processus de mise à jour peut être divisé en fonctions distinctes pour une meilleure réutilisation du code.
Figure 3 : Sortie de la création à partir de l’appel d’un service Web qui retourne des données RSS. (Cliquez pour afficher l’image de taille complète)
La liste 16 montre un exemple de code côté client qui appelle un objet Address défini dans un espace de noms Model, le remplit avec des données mises à jour et l’affecte à la propriété Address d’un objet CustomerDetails. L’objet CustomerDetails est ensuite transmis au service Web pour traitement.
Liste 16. Utilisation de types complexes imbriqués
function UpdateAddress()
{
var cust = new Model.CustomerDetails();
cust.CustomerID = $get("hidCustomerID").value;
cust.Address = CreateAddress();
InterfaceTraining.DemoService.UpdateAddress(cust,OnWSUpdateComplete);
}
function CreateAddress()
{
var addr = new Model.Address();
addr.Street = $get("txtStreet").value;
addr.City = $get("txtCity").value;
addr.State = $get("txtState").value;
return addr;
}
function OnWSUpdateComplete(result)
{
alert("Update " + ((result)?"succeeded":"failed")+ "!");
}
Création et utilisation de méthodes de page
Les services web offrent un excellent moyen d’exposer des services réutilisables à divers clients, notamment ASP.NET pages AJAX. Toutefois, il peut arriver qu’une page ait besoin de récupérer des données qui ne seront jamais utilisées ou partagées par d’autres pages. Dans ce cas, la création d’un fichier .asmx pour permettre à la page d’accéder aux données peut sembler excessive, car le service n’est utilisé que par une seule page.
ASP.NET AJAX fournit un autre mécanisme permettant d’effectuer des appels de type service web sans créer de fichiers .asmx autonomes. Cette opération est effectuée à l’aide d’une technique appelée « méthodes de page ». Les méthodes de page sont des méthodes statiques (partagées dans VB.NET) incorporées directement dans une page ou un fichier de code à côté de laquelle l’attribut WebMethod est appliqué. En appliquant l’attribut WebMethod, ils peuvent être appelés à l’aide d’un objet JavaScript spécial nommé PageMethods qui est créé dynamiquement au moment de l’exécution. L’objet PageMethods agit comme un proxy qui vous protège du processus de sérialisation/désérialisation JSON. Notez que pour utiliser l’objet PageMethods, vous devez définir la propriété EnablePageMethods de ScriptManager sur true.
<asp:ScriptManager ID="ScriptManager1" runat="server" EnablePageMethods="true">
</asp:ScriptManager>
La liste 17 montre un exemple de définition de deux méthodes de page dans une classe de code ASP.NET à côté du code. Ces méthodes récupèrent des données à partir d’une classe de couche métier située dans le dossier App_Code du site web.
Liste 17. Définition des méthodes de page.
[WebMethod]
public static Customer[] GetCustomersByCountry(string country)
{
return Biz.BAL.GetCustomersByCountry(country);
}
[WebMethod]
public static Customer[] GetCustomersByID(string id)
{
return Biz.BAL.GetCustomersByID(id);
}
Lorsque ScriptManager détecte la présence de méthodes web dans la page, il génère une référence dynamique à l’objet PageMethods mentionné précédemment. L’appel d’une méthode web est effectué en référençant la classe PageMethods suivie du nom de la méthode et de toutes les données de paramètre nécessaires qui doivent être passées. La liste 18 montre des exemples d’appel des deux méthodes de page présentées précédemment.
Liste 18. Appel de méthodes de page avec l’objet JavaScript PageMethods.
function GetCustomerByCountry()
{
var country = $get("txtCountry").value;
PageMethods.GetCustomersByCountry(country, OnWSRequestComplete);
}
function GetCustomerByID()
{
var custID = $get("txtCustomerID").value;
PageMethods.GetCustomersByID(custID, OnWSRequestComplete);
}
function OnWSRequestComplete(results)
{
var searchResults = $get("searchResults");
searchResults.control.set_data(results);
if (results != null) GetMap(results[0].Country,results);
}
L’utilisation de l’objet PageMethods est très similaire à l’utilisation d’un objet proxy JavaScript. Vous spécifiez tout d’abord toutes les données de paramètre qui doivent être passées à la méthode de page, puis définissez la fonction de rappel qui doit être appelée lorsque l’appel asynchrone retourne. Un rappel d’échec peut également être spécifié (reportez-vous à la liste 14 pour obtenir un exemple de gestion des échecs).
AutoCompleteExtender et ASP.NET AJAX Toolkit
Le ASP.NET AJAX Toolkit (disponible à partir de https://github.com/DevExpress/AjaxControlToolkit) propose plusieurs contrôles qui peuvent être utilisés pour accéder aux services Web. Plus précisément, le kit de ressources contient un contrôle utile nommé AutoCompleteExtender
qui peut être utilisé pour appeler des services Web et afficher des données dans des pages sans écrire du code JavaScript du tout.
Le contrôle AutoCompleteExtender peut être utilisé pour étendre les fonctionnalités existantes d’une zone de texte et aider les utilisateurs à localiser plus facilement les données qu’ils recherchent. À mesure qu’ils entrent dans une zone de texte, le contrôle peut être utilisé pour interroger un service Web et affiche les résultats sous la zone de texte dynamiquement. La figure 4 montre un exemple d’utilisation du contrôle AutoCompleteExtender pour afficher les ID client d’une application de support. À mesure que l’utilisateur tape des caractères différents dans la zone de texte, différents éléments sont affichés ci-dessous en fonction de leur entrée. Les utilisateurs peuvent ensuite sélectionner l’ID client souhaité.
L’utilisation de l’autocompleteExtender dans une page AJAX ASP.NET nécessite que l’assembly AjaxControlToolkit.dll soit ajouté au dossier bin du site web. Une fois l’assembly de kit de ressources ajouté, vous souhaiterez le référencer dans web.config afin que les contrôles qu’il contient soient disponibles pour toutes les pages d’une application. Pour ce faire, ajoutez la balise suivante dans la balise de contrôles> web.config <:
<add namespace="AjaxControlToolkit" assembly="AjaxControlToolkit" tagPrefix="ajaxToolkit"/>
Dans les cas où vous n’avez besoin que d’utiliser le contrôle dans une page spécifique, vous pouvez le référencer en ajoutant la directive Référence en haut d’une page, comme indiqué ensuite plutôt que de mettre à jour web.config :
<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit"
TagPrefix="ajaxToolkit" %>
Figure 4 : Utilisation du contrôle AutoCompleteExtender. (Cliquez pour afficher l’image de taille complète)
Une fois que le site web a été configuré pour utiliser le kit de ressources AJAX ASP.NET, un contrôle AutoCompleteExtender peut être ajouté à la page, comme vous ajouteriez un contrôle de serveur ASP.NET standard. La liste 19 montre un exemple d’utilisation du contrôle pour appeler un service web.
Liste 19. Utilisation du contrôle AutoCompleteExtender ASP.NET AJAX Toolkit.
<ajaxToolkit:AutoCompleteExtender ID="extTxtCustomerID" runat="server"
MinimumPrefixLength="1" ServiceMethod="GetCustomerIDs"
ServicePath="~/CustomersService.asmx"
TargetControlID="txtCustomerID" />
AutoCompleteExtender a plusieurs propriétés différentes, notamment l’ID standard et les propriétés d’exécution trouvées sur les contrôles serveur. En plus de cela, il vous permet de définir le nombre de caractères qu’un utilisateur final tape avant que le service Web ne soit interrogé pour les données. La propriété MinimumPrefixLength indiquée dans Listing 19 entraîne l’appel du service chaque fois qu’un caractère est tapé dans la zone de texte. Vous devez définir cette valeur avec soin, car chaque fois que l’utilisateur tape un caractère, le service Web est appelé pour rechercher des valeurs qui correspondent aux caractères de la zone de texte. Le service web à appeler ainsi que la méthode web cible sont définis à l’aide des propriétés ServicePath et ServiceMethod respectivement. Enfin, la propriété TargetControlID identifie la zone de texte à laquelle raccorder le contrôle AutoCompleteExtender.
Le service web appelé doit avoir l’attribut ScriptService appliqué comme indiqué précédemment et la méthode web cible doit accepter deux paramètres nommés prefixText et count. Le paramètre prefixText représente les caractères tapés par l’utilisateur final et le paramètre count représente le nombre d’éléments à retourner (la valeur par défaut est 10). Listing 20 montre un exemple de méthode web GetCustomerIDs appelée par le contrôle AutoCompleteExtender présenté précédemment dans Listing 19. La méthode web appelle une méthode de couche métier qui appelle à son tour une méthode de couche de données qui gère le filtrage des données et retourne les résultats correspondants. Le code de la méthode de couche de données est affiché dans La liste 21.
Liste 20. Filtrage des données envoyées à partir du contrôle AutoCompleteExtender.
[WebMethod]
public string[] GetCustomerIDs(string prefixText, int count)
{
return Biz.BAL.GetCustomerIDs(prefixText, count);
}
Liste 21. Filtrage des résultats en fonction de l’entrée de l’utilisateur final.
public static string[] GetCustomerIDs(string prefixText, int count)
{
//Customer IDs cached in _CustomerIDs field to improve performance
if (_CustomerIDs == null)
{
List<string> ids = new List<string>();
//SQL text used for simplicity...recommend using sprocs
string sql = "SELECT CustomerID FROM Customers";
DbConnection conn = GetDBConnection();
conn.Open();
DbCommand cmd = conn.CreateCommand();
cmd.CommandText = sql;
DbDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
ids.Add(reader["CustomerID"].ToString());
}
reader.Close();
conn.Close();
_CustomerIDs = ids.ToArray();
}
int index = Array.BinarySearch(_CustomerIDs, prefixText, new CaseInsensitiveComparer());
//~ is bitwise complement (reverse each bit)
if (index < 0) index = ~index;
int matchingCount;
for (matchingCount = 0; matchingCount < count && index + matchingCount < _CustomerIDs.Length; matchingCount++)
{
if (!_CustomerIDs[index + matchingCount].StartsWith(prefixText, StringComparison.CurrentCultureIgnoreCase))
{
break;
}
}
String[] returnValue = new string[matchingCount];
if (matchingCount > 0)
{
Array.Copy(_CustomerIDs, index, returnValue, 0, matchingCount);
}
return returnValue;
}
Conclusion
ASP.NET AJAX offre une excellente prise en charge de l’appel de services Web sans écrire beaucoup de code JavaScript personnalisé pour gérer les messages de requête et de réponse. Dans cet article, vous avez vu comment activer ajax-enable .NET Web Services pour les activer pour traiter des messages JSON et comment définir des proxys JavaScript à l’aide du contrôle ScriptManager. Vous avez également vu comment les proxys JavaScript peuvent être utilisés pour appeler des services Web, gérer des types simples et complexes et traiter les échecs. Enfin, vous avez vu comment les méthodes de page peuvent être utilisées pour simplifier le processus de création et d’exécution d’appels de service web et comment le contrôle AutoCompleteExtender peut fournir de l’aide aux utilisateurs finaux au fur et à mesure qu’ils tapez. Bien que updatePanel disponible dans ASP.NET AJAX soit certainement le contrôle du choix pour de nombreux programmeurs AJAX en raison de sa simplicité, savoir comment appeler des services Web via des proxys JavaScript peut être utile dans de nombreuses applications.
Bio
Dan Wahlin (Microsoft Most Valuable Professional for ASP.NET and XML Web Services) est un instructeur de développement .NET et consultant en architecture à l’interface Technical Training (http://www.interfacett.com). Dan a fondé le XML for ASP.NET Developers Web site (www.XMLforASP.NET), est sur le Bureau de l’orateur INETA et parle à plusieurs conférences. Dan co-auteur professional Windows DNA (Wrox), ASP.NET : Conseils, Tutoriels et Code (Sams), ASP.NET 1.1 Insider Solutions, Professional ASP.NET 2.0 AJAX (Wrox), ASP.NET 2.0 MVP Hacks et créé XML pour les développeurs ASP.NET (Sams). Quand il n’écrit pas de code, d’articles ou de livres, Dan aime écrire et enregistrer de la musique et jouer au golf et au basket-ball avec sa femme et ses enfants.
Scott Cate travaille avec les technologies Web Microsoft depuis 1997 et est le président de myKB.com (www.myKB.com) où il se spécialise dans l’écriture d’applications basées sur des ASP.NET basées sur des solutions logicielles de base de connaissances. Scott peut être contacté par e-mail ou scott.cate@myKB.com son blog à ScottCate.com