Bienvenue à Blogs CodeS-SourceS Identification | Inscription | Aide

Atteint de JavaScriptite Aiguë [Cyril Durand]

Expert ASP.net Ajax et WCF, Cyril Durand parle dans son blog de point techniques sur ASP.net, ASP.net Ajax, JavaScript, WCF et .net en général. Cyril est également consultant indépendant, n'hésitez pas à le contacter pour de l'assistance sur vos projets

Actualités

  • Blog de Cyril DURAND, passionné de JavaScript, Ajax, ASP.net et tout ce qui touche au developpement Web Client-Side.

    N'hésitez pas à me contacter pour vos projets .net : architecture, accompagnement, formation, ...

    View Cyril Durand's profile on LinkedIn
    hit counters


    Expertise Commerce server et BizTalk

Communication grille extjs vers WCF ou WebService ASMX "Ajax" via JSON

Je suis actuellement en train d'utiliser le framework extjs.com. Parmi les contrôles de ce framework il existe un contrôle Ext.grid.GridPanel qui, comme son nom l'indique affiche une grille coté client (démo grid extjs).
Pour ceux qui ne connaissent pas extjs, je vous conseille vivement de faire un tour sur la page de démos de ce framework : démos des contrôles extjs, vous risquez d'être étonné.

Comment binder le contrôle grid avec un service WCF ou ASMX "Ajax Enabled" ?

Pour binder un contrôle à une source de donnée, extjs a un mécanisme de "store", celui-ci s'occupe de rechercher les données, les transformer en une donnée utilisable par les contrôles, etc...
Puisqu'un service WCF est capable de nous générer du JSON, le store qui nous intéresse est le JsonStore. Ce "store" permet de faire une requête XMLHttpRequest vers une url nous retournant du JSON. Le JsonStore effectue une requête GET, par défaut WCF n'autorise pas les requêtes GET, il faut donc rajouter l'attribut [WebGet] au niveau du service WCF afin d'autoriser ce verbe.

Voici à quoi ressemble notre service WCF.

[WebGet] [OperationContract] public List<Person> GetPersons() { return new List<Person>() { new Person(){FirstName = "Cyril", LastName = "Durand", BirthDate = new DateTime(1986, 1, 31), Company = "Freelance"}, new Person(){FirstName = "Toto", LastName="Pouet", BirthDate = new DateTime(1900, 1, 1), Company="Student"} }; }

Si vous utilisez un WebService ASMX classique il faut rajouter le paramètre UseHttpGet=true dans l'attribut ScriptMethod.

[WebMethod] [ScriptMethod(UseHttpGet = true)] public List<Person> GetPersons()

Au niveau du client, il n'y a rien de spécial à configurer, nous n'avons même pas besoin d'utiliser le framework Microsoft Ajax Library ou d'inclure le proxy autogénéré du service WCF (service1.svc/js).
Voici le code nécessaire.

var store = new Ext.data.JsonStore({ url : 'service.svc/GetPersons', root : 'd', // anti CSRF attack fields: [ 'FirstName', 'LastName', 'Company', {name:'BirthDate', type:'date', dateFormat: 'atlas'} ] }); var grid = new Ext.grid.GridPanel({ store: store, columns: [ {header: "Prenom", width: 75, sortable: true, dataIndex: 'FirstName'}, {header: "Nom", width: 75, sortable: true, dataIndex: 'LastName'}, {header: "Date de naissance", width: 155, sortable: true, dataIndex: 'BirthDate', renderer: Ext.util.Format.dateRenderer('m/d/Y')}, {id:'company',header: "Nom de la companie", width: 100, sortable: true, dataIndex: 'Company'} ], loadMask : true, autoExpandColumn: 'company', height:350, width:800 }); grid.render(document.body); store.load();

Si vous voulez renvoyer des données de type DateTime voici une petite astuce permettant de déserializer une Date "WCF" avec extjs.

// petite bidouille pour deserialiser les dates atlas avec extjs Date.parseFunctions['atlas'] = '_parseAtlas'; Date._parseAtlas = function(input){ input = input.replace( new RegExp('/Date\\((-?[0-9]+)(?:[a-zA-Z]|(?:\\+|-)[0-9]{4})?\\)/', 'g'), '(new Date($1))'); return eval(input); }

Cette astuce est à exécuter qu'une seule fois au lancement de votre application.

Posted: jeudi 17 avril 2008 02:46 par cyril
Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :

Commentaires

Promesses a dit :

Salut Cyril,

ca fait un bail!

Et pour cause, je me suis mis au framework script.aculo.us mixé avec les webservices, c'est un vrai bonheur!

En revanche comment ca se fait que tu te mets à un framework js, je croyais que celui de MS suffisait ?

Ce qui est bien en revanche ici, c'est que tu n'es pas obligé d'enregistrer ton webservice auprès du ScriptManager...

ExtJS n'est il pas un peu difficile à customiser comme bon nous semble ?

# avril 17, 2008 13:06

dapoussin a dit :

Bonjour Cyril,

Intéressant tout ça ! J'avais entendu parler de extJs mais je ne pensais pas que c'était aussi abouti. Je profite de ton post pour poser une petite question : que penses-tu des projets comme "ExtJs Extender Controls" ou "CoolLite", comparé à l'AjaxControlToolkit que j'utilise actuellement ? Apparemment ExtJs propose bien plus de choses que le framework AJAX.NET, et j'aurais bien besoin d'un gridview côté client comme tu le présentes. Mais bon, remplacer tous les controles AjaxControlToolkit par leur équivalent "extJs" me parait fastidieux, et avoir les deux frameworks en parralèle devrait trop alourdir mon site. Même si c'est un intranet, je tiens à garder de bonnes performances et ne pas trop surcharger le réseau.

Merci d'avance pour ta réponse et pour tes billets enrichissants ;)

Laurent

# avril 17, 2008 17:46

cyril a dit :

Attention, tu parles de 2 choses différentes, extjs,  les toolkits et des projets .net pour extjs (je ne connais pas coollite).

Ces projets correspondent à différentes approches de la création d'un site web. Soit :

- tu fais une application cliente, donc tout en JS;

- tu fais une application serveur qui génére des choses coté client donc en .net

Les toolkits et "ExtJS Extender Controls" permettent de générer du javascript à partir de contrôle serveur, tu as donc beaucoup d'aller/retour client/server et autre postback. L'avantage de ce genre de projet c'est que cela permet d'avoir quelques interactions client tout en gardant la logique d'ASP.net, la notion de page, de contrôle, de postback etc...

D'experience, quand on veut faire quelque chose de très interactif coté client, ce genre d'approche n'est pas viable car cela nécessite trop d'aller/retour. Pour contrer ce problème il faut déporter la logique d'affichage coté client. On perd alors toute les notions d'ASP.net, plus de page, plus de postback, ... on code tout en javascript et ASP.net ne nous sert plus que comme fournisseur d'accès aux données via WCF ou asmx.

C'est désormais la seconde approche que je met en place lorsqu'il faut une intéraction riche avec l'utilisateur. J'ai par exemple mis cette architecture en place pour www.vacancesvuesduciel.fr

# avril 18, 2008 22:24

phoenixenator a dit :

Bonjour Cyril,

Serrais tu d’où vient mon problème ? J’ai repris ces quelques lignes de code et lors de l’exécution mon serveur ne semble pas répondre au client. Voici mon code :

service1.asmx.cs :

using System;

using System.Collections;

using System.ComponentModel;

using System.Data;

using System.Linq;

using System.Web;

using System.Web.Services;

using System.Web.Services.Protocols;

using System.Xml.Linq;

using System.Collections.Generic;

using System.Web.Script.Services;

namespace WSExtJs {

 ///

<summary>

 /// Description résumée de Service1

 /// </summary>

<Person> GetPersons() {

     List<Person> persons = new List<Person>() {

       new Person(){FirstName = "Cyril", LastName = "Durand", BirthDate = new DateTime(1986, 1, 31), Company = "Freelance"},

       new Person(){FirstName = "Toto", LastName="Pouet", BirthDate = new DateTime(1900, 1, 1), Company="Student"}

     };

     int count = persons.Count;

     return persons;

   }

 }

}

service2.svc.cs :

using System;

using System.Linq;

using System.Runtime.Serialization;

using System.ServiceModel;

using System.ServiceModel.Activation;

using System.ServiceModel.Web;

using System.Collections.Generic;

using System.Web.Script.Services;

using System.Web.Services;

using System.Web.Services.Protocols;

namespace WSExtJs {

 [ServiceContract(Namespace = "")]

 [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]

 public class Service2 {

   // Ajoutez l'attribut [WebGet] pour utiliser HTTP GET

   [OperationContract]

   public void DoWork() {

     // Ajoutez votre implémentation d'opération ici

     return;

   }

   // Ajoutez des opérations supplémentaires ici et marquez-les avec [OperationContract]

   [WebGet]

   [OperationContract]

   public List<Person> GetPersons() {

     List<Person> persons =  new List<Person>() {

       new Person(){FirstName = "Cyril", LastName = "Durand", BirthDate = new DateTime(1986, 1, 31), Company = "Freelance"},

       new Person(){FirstName = "Toto", LastName="Pouet", BirthDate = new DateTime(1900, 1, 1), Company="Student"}

     };

     int count = persons.Count;

     return persons;

   }

 }

 public class Person {

   public Person() { }

   public string FirstName { get; set; }

   public string LastName { get; set; }

   public DateTime BirthDate { get; set; }

   public string Company { get; set; }

 }

}

code html :

<html>

<head>

 <title>Grid .Net Example</title>

 <link rel="stylesheet" type="text/css" href="ExtJs/ext-all.css" />

<script type="text/javascript" src="ExtJs/ext-base.js"></script>

 <script type="text/javascript" src="ExtJs/ext-all.js"></script>

<script type="text/javascript"><![CDATA[

   Ext.onReady(function(){

     var store = new Ext.data.JsonStore({

       //url: 'Service2.svc/GetPersons',

       url: 'Service1.asmx/GetPersons',

       root : 'd',  // anti CSRF attack

       fields: [

           'FirstName',

           'LastName',

           'Company',

           {name:'BirthDate', type:'date', dateFormat: 'atlas'}

       ]

     });

     var grid = new Ext.grid.GridPanel({

       store: store,

       columns: [

           {header: "Prenom", width: 75, sortable: true, dataIndex: 'FirstName'},

           {header: "Nom", width: 75, sortable: true, dataIndex: 'LastName'},

           {header: "Date de naissance", width: 155, sortable: true,

               dataIndex: 'BirthDate', renderer: Ext.util.Format.dateRenderer('m/d/Y')},

           {id:'company',header: "Nom de la companie", width: 100,

               sortable: true, dataIndex: 'Company'}

       ],

       loadMask : true,

       autoExpandColumn: 'company',

       height:350,

       width:800

     });

     grid.render(document.body);

     store.load();

   });

 ]]></script>

</head>

<body>

<h1>Grid .Net Example</h1>

<div id="grid-example" style="margin: 10px;"></div>

</body>

</html>

# mai 24, 2008 17:48

phoenixenator a dit :

Merci pour vos éventuelles réponses.

# mai 24, 2008 17:50

cyril a dit :

Bonjour,

regarde avec Fiddler ou tout autre analyseur HTTP afin de déterminer s'il y a une requête contenant les données qui transite.

Je viens de rapidement regarder le code, essaye de supprimer le dataformat:'atlas', puisque tu n'as pas la bidouille permettant de comprendre les dates Atlas avec extjs.

# mai 26, 2008 10:11

phoenixenator a dit :

Merci pour ta réponse cyril.

En fait dans le code que j’ai posté avant-hier contient plusieurs erreurs, donc ca ne pouvait pas fonctionner. Voici le code mise à jour.

Service2.svc.cs :

using System;

using System.Linq;

using System.Runtime.Serialization;

using System.ServiceModel;

using System.ServiceModel.Activation;

using System.ServiceModel.Web;

using System.Collections.Generic;

using System.Web.Services;

using System.Web.Script.Services;

using System.Web.Services.Protocols;

namespace WSExtJs {

//[ServiceBehavior(AddressFilterMode = AddressFilterMode.Any)]

 //[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]

public class Service2 : IService {

   public List

<Person> GetPersons() {

     List<Person> persons =  new List<Person>() {

       new Person(){FirstName = "Cyril", LastName = "Durand", BirthDate = new DateTime(1986, 1, 31), Company = "Freelance"},

       new Person(){FirstName = "Toto", LastName="Pouet", BirthDate = new DateTime(1900, 1, 1), Company="Student"}

     };

     int count = persons.Count;

     return persons;

   }

public string GetFirstName(string name) {

return name;

}

 }

[ServiceContract]

public interface IService {

[OperationContract]

[WebGet(

BodyStyle = WebMessageBodyStyle.Bare,

RequestFormat = WebMessageFormat.Json,

ResponseFormat = WebMessageFormat.Json,

UriTemplate = "/GetPersons")]

List<Person> GetPersons();

[OperationContract]

[WebGet(

BodyStyle = WebMessageBodyStyle.Bare,

RequestFormat = WebMessageFormat.Json,

ResponseFormat = WebMessageFormat.Json,

UriTemplate = "/FirstName?name={name}")]

string GetFirstName(string name);

}

[DataContract]

 public class Person {

   public Person() { }

[DataMember]

   public string FirstName { get; set; }

[DataMember]

   public string LastName { get; set; }

[DataMember]

   public DateTime BirthDate { get; set; }

[DataMember]

   public string Company { get; set; }

 }

}

Web.config :

<Person>

<configuration>

<system.serviceModel>

<services>

<service name="WSExtJs.Service2" behaviorConfiguration="Service2AspNetAjaxBehavior">

<endpoint address="" binding="webHttpBinding" contract="WSExtJs.IService" />

</service>

</services>

<behaviors>

<serviceBehaviors>

<behavior name="Service2AspNetAjaxBehavior">

<serviceDebug includeExceptionDetailInFaults="true" />

<serviceMetadata httpGetEnabled="true" />

</behavior>

</serviceBehaviors>

</behaviors>

</system.serviceModel>

<system.web>

<compilation debug="true" />

 </system.web>

</configuration>

En utilisant ce code j’arrive à générer le wsdl ; mais dès que je veux tester dans mon navigateur le rendu du service (http://localhost:4105/Service2.svc/GetPerson) j’obtiens l’erreur suivante :

<Fault>

<Code>

<Value>Sender</Value>

<Subcode>

<Value>a:DestinationUnreachable</Value>

</Subcode>

</Code>

<Reason>

<Text xml:lang="fr-FR">

Impossible de traiter le message contenant To « http://localhost:4105/Service2.svc/GetPerson » au récepteur en raison d’une non-correspondance de AddressFilter au EndpointDispatcher. Vérifiez que les adresses EndpointAddress de l’expéditeur et du récepteur s’accordent.

</Text>

</Reason>

</Fault>

Est ce que quelqu’un pourrait me donner une piste pour corriger l’erreur. Merci d’avance.

# mai 26, 2008 18:11

cyril a dit :

c'est un problème de configuration WCF ...

WCF est sympa sur le papier mais c'est une plaie pour le configurer correctement ...

Regarde ton fichier de config si tout est correcte. Sinon, créé un nouveau site web et rajoute un nouveau service WCF (ajax enabled) et vérifie que ce service WCF fonctionne, puis compare les fichiers de config ...

Bon courage

# mai 26, 2008 18:24

phoenixenator a dit :

Merci pour tes conseils. Je viens de trouver la solution. Afin que tout le monde puisse en profiter voici mon code.

service2.svc :

using System;

using System.Linq;

using System.Runtime.Serialization;

using System.ServiceModel;

using System.ServiceModel.Activation;

using System.ServiceModel.Web;

using System.Collections.Generic;

using System.Web.Services;

using System.Web.Script.Services;

using System.Web.Services.Protocols;

namespace WSExtJs {

//[ServiceBehavior(AddressFilterMode = AddressFilterMode.Any)]

   //[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]

public class Service2 : IService {

   public List

<Person> GetPersons() {

     List<Person> persons =  new List<Person>() {

       new Person(){FirstName = "Cyril", LastName = "Durand", BirthDate = new DateTime(1986, 1, 31), Company = "Freelance"},

       new Person(){FirstName = "Toto", LastName="Pouet", BirthDate = new DateTime(1900, 1, 1), Company="Student"}

     };

     int count = persons.Count;

     return persons;

   }

public string GetFirstName(string name) {

return name;

}

 }

[ServiceContract]

public interface IService {

[OperationContract]

       [WebGet]

       //[WebGet(

       //    BodyStyle = WebMessageBodyStyle.Bare,

       //    RequestFormat = WebMessageFormat.Json,

       //    ResponseFormat = WebMessageFormat.Json,

       //    UriTemplate = "/GetPersons")]

List<Person> GetPersons();

[OperationContract]

       [WebGet]

       //[WebGet(

       //    BodyStyle = WebMessageBodyStyle.Bare,

       //    RequestFormat = WebMessageFormat.Json,

       //    ResponseFormat = WebMessageFormat.Json,

       //    UriTemplate = "/FirstName?name={name}")]

string GetFirstName(string name);

}

[DataContract]

 public class Person {

   public Person() { }

[DataMember]

   public string FirstName { get; set; }

[DataMember]

   public string LastName { get; set; }

[DataMember]

   public DateTime BirthDate { get; set; }

[DataMember]

   public string Company { get; set; }

 }

}

web.config :

<Person>

<configuration>

 <system.serviceModel>

   <services>

     <service name="WSExtJs.Service2" behaviorConfiguration="ServiceBehavior">

       <endpoint contract="WSExtJs.IService" binding="webHttpBinding" address="" behaviorConfiguration="AjaxBehavior" />

     </service>

   </services>

   <behaviors>

     <serviceBehaviors>

       <behavior name="ServiceBehavior">

         <serviceMetadata httpGetEnabled="true" />

       </behavior>

     </serviceBehaviors>

     <endpointBehaviors>

       <behavior name="AjaxBehavior">

         <enableWebScript />

       </behavior>

     </endpointBehaviors>

   </behaviors>

 </system.serviceModel>

<system.web>

<compilation debug="true" />

 </system.web>

</configuration>

# mai 26, 2008 19:33
Les commentaires anonymes sont désactivés

Les 10 derniers blogs postés

- Office 365: Script PowerShell pour auditer l’usage des Office Groups de votre tenant par Blog Technique de Romelard Fabrice le 04-26-2019, 11:02

- Office 365: Script PowerShell pour auditer l’usage de Microsoft Teams de votre tenant par Blog Technique de Romelard Fabrice le 04-26-2019, 10:39

- Office 365: Script PowerShell pour auditer l’usage de OneDrive for Business de votre tenant par Blog Technique de Romelard Fabrice le 04-25-2019, 15:13

- Office 365: Script PowerShell pour auditer l’usage de SharePoint Online de votre tenant par Blog Technique de Romelard Fabrice le 02-27-2019, 13:39

- Office 365: Script PowerShell pour auditer l’usage d’Exchange Online de votre tenant par Blog Technique de Romelard Fabrice le 02-25-2019, 15:07

- Office 365: Script PowerShell pour auditer le contenu de son Office 365 Stream Portal par Blog Technique de Romelard Fabrice le 02-21-2019, 17:56

- Office 365: Script PowerShell pour auditer le contenu de son Office 365 Video Portal par Blog Technique de Romelard Fabrice le 02-18-2019, 18:56

- Office 365: Script PowerShell pour extraire les Audit Log basés sur des filtres fournis par Blog Technique de Romelard Fabrice le 01-28-2019, 16:13

- SharePoint Online: Script PowerShell pour désactiver l’Option IRM des sites SPO non autorisés par Blog Technique de Romelard Fabrice le 12-14-2018, 13:01

- SharePoint Online: Script PowerShell pour supprimer une colonne dans tous les sites d’une collection par Blog Technique de Romelard Fabrice le 11-27-2018, 18:01