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

UpdatePanel et PageRequestManagerParserErrorException

Question :

Dans ma page j'utilise un UpdatePanel. Lorsque je click sur mon bouton l'UpdatePanel est censé se rafraichir. Malheureusement j'obtiens une erreur dans une alert JavaScript :

Sys.WebForms.PageRequestManagerParserErrorException: The message received from the server could not be parsed.

Voici le code que j'utilise :

<asp:UpdatePanel id="UpdatePanel1" runat="server"> <contenttemplate> <asp:Label id="Label1" runat="server" Text="Label"></asp:Label> </contenttemplate> <Triggers> <asp:AsyncPostBackTrigger ControlID="Button1" /> </Triggers> </asp:UpdatePanel> <asp:LinkButton ID="Button1" runat="server" OnClick="Button1_Click" Text="Button" />

Réponse :

Cette erreur provient suite à une écriture directe dans le flux de la réponse HTTP, la plupart du temps c'est suite à l'utilisation de la méthode Response.Write. Pour corriger le problème il suffit de ne plus utiliser cette méthode !

Si vous voulez écrire dans votre page il faut utiliser un literal et définir sa propriété Text :

<asp:Literal ID="lit1" runat="server" />
lit1.Text = "hello";

Response.Write est souvent utilisé pour ajouter du script JavaScript dans la page ! Ce n'est pas la bonne méthode ! Il faut utiliser les méthodes RegisterStartupScript de l'objet ScriptManager

ScriptManager.RegisterStartupScript(this, typeof(Default6), "deleteOK", "alert('enregistrement supprimé');", true);

Le dernier argument à true permet de laisser ASP.net gérer les balises <script> cela a aussi pour avantage de regrouper tous les scripts rajouté via cette méthode dans une seule balise <script>, par contre n'oubliez pas de terminer votre script par un point-virgule, sinon vous risquez d'avoir une erreur JavaScript. Pour information, si vous n'utilisez pas Microsoft Ajax vous devez utiliser la méthode Page.ClientScript.RegisterStartupScript qui prend les mêmes arguments.

Une autre cause du problème est l'utilisation de Response.Redirect qui va lui aussi modifié la réponse HTTP. Si vous voulez rediriger l'utilisateur suite à un AsyncPostBack il faudra le faire en JavaScript, par exemple :

ScriptManager.RegisterStartupScript(this, typeof(Default6), "redirect", "document.location.href='default6.aspx';", true);

Les fonctionnalités de tracing offertes par ASP.net peuvent elles aussi être responsable du problème, si vous activez la trace alors cela va automatiquement ajouter des infos de debug à la fin de la réponse HTTP et causé l'erreur. Pour éviter le problème il faut désactiver la trace au niveau de la page :

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default6.aspx.cs" Inherits="Default6" Trace="false" %>

Si vous voulez accéder aux informations de la trace il vous faudra modifier le fichier de config ainsi :

<trace enabled="true" localOnly="true" pageOutput="false" requestLimit="500" />

Vous pourrez alors accéder aux différentes traces via cet url : http://YourSite/trace.axd

Bien sur il existe de nombreuses autres possibilités de modifier la réponse HTTP, par exemple les Filters, les HttpModules, la méthode Response.Transfer, ... mais les 3 possibilités plus haut sont les plus courantes. Si vous ne faites partie d'aucun de ces 3 cas, vous pouvez utilisez Fiddler pour analyser la réponse http et ainsi détecter le problème.

Explications :

Pour bien comprendre le problème, reprenons l'exemple plus haut et analysons la réponse HTTP initiale (épuré pour les explications):

<script src="...url des ressources de Microsoft Ajax" type="text/javascript"></script> <script type="text/javascript"> //<![CDATA[ Sys.WebForms.PageRequestManager._initialize('sc1', document.getElementById('form1')); Sys.WebForms.PageRequestManager.getInstance()._updateControls(['tUpdatePanel1'], ['Button1'], [], 90); //]]> </script> <div id="UpdatePanel1"> <span id="Label1">Label</span> </div> <a id="Button1" href="javascript:__doPostBack('Button1','')">Button</a> <script type="text/javascript"> <!-- Sys.Application.initialize(); // --> </script>

Lorsque l'on click sur le bouton, on appelle la méthode __doPostBack, cette méthode n'est pas la classique méthode __doPostBack fournis par ASP.net 2.0 mais la méthode _doPostBack de l'objet Sys.WebForms.PageRequestManager. Comment est-ce possible ? Tout simplement car Microsoft Ajax surcharge notre classique __doPostBack.

La nouvelle méthode va alors déterminer si elle doit faire un asyncPostBack ou un classique postBack, pour cela elle s'appuie sur le premier argument de la méthode _doPostBack : le uniqueID du contrôle déclenchant le postback ainsi que les valeurs passé à la méthode _updateControls lors de l'initialisation de la page.

Sys.WebForms.PageRequestManager.getInstance()._updateControls(['tUpdatePanel1'], ['Button1'], [], 90);

Notre cas est simple car on utilise un triggers explicite mais si le button était contenu à l'intérieur de l'updatepanel alors la méthode _doPostBack regarde tous les contrôles parent pour savoir si il est contenu dans un UpdatePanel, à partir de là notre page sait s'il doit faire un AsyncPostBack ou non.

Dans le cas où l'on doit faire un AsyncPostBack, une requête XMLHttpRequest vers la page en cours est déclenchée. Côté serveur tout se passe normalement, jusqu'a la phase de rendering. Dans cette phase Microsoft ASP.net Ajax Extensions reprend la main et va déterminer les UpdatePanels à rafraichir en fonction des triggers pour ensuite générer une réponse spécial qui sera interprété par Microsoft Ajax Library. Dans notre exemple la réponse générée sera :

45|updatePanel|UpdatePanel1| <span id="Label1">toto</span> |0|hiddenField|__EVENTTARGET||0|hiddenField|__EVENTARGUMENT||104|hiddenField|__VIEWSTATE|/wEPDwUKLTk3ODgyMTQwMg9kFgICAw9kFgICAw9kFgJmD2QWAgIBDw8WAh4EVGV4dAUEdG90b2RkZCuO1Wdu9SGQj6z2+isctVSX0gD1|48|hiddenField|__EVENTVALIDATION|/wEWAgKCm9C4AgKM54rGBlUT5mTfn5wzMtH4umKYezTpKJ7o|7|asyncPostBackControlIDs||Button1|0|postBackControlIDs|||13|updatePanelIDs||tUpdatePanel1|0|childUpdatePanelIDs|||12|panelsToRefreshIDs||UpdatePanel1|2|asyncPostBackTimeout||90|13|formAction||default6.aspx|13|pageTitle||Untitled Page|

On voit que la réponse n'a rien à voir avec une réponse HTTP classique, elle respecte une syntaxe très précise qui permet d'être très rapidement interprété par Microsoft Ajax Library. En effet à partir de cette réponse, le script client est capable de déterminer les différents éléments html à rafraichir.

En utilisant la méthode Response.Write la réponse HTTP sera alors :

toto45|updatePanel|UpdatePanel1| <span id="Label1">toto</span> |0|hiddenField|__EVENTTARGET||0|hiddenField|__EVENTARGUMENT||104|hiddenField|__VIEWSTATE|/wEPDwUKLTk3ODgyMTQwMg9kFgICAw9kFgICAw9kFgJmD2QWAgIBDw8WAh4EVGV4dAUEdG90b2RkZCuO1Wdu9SGQj6z2+isctVSX0gD1|48|hiddenField|__EVENTVALIDATION|/wEWAgKCm9C4AgKM54rGBlUT5mTfn5wzMtH4umKYezTpKJ7o|7|asyncPostBackControlIDs||Button1|0|postBackControlIDs|||13|updatePanelIDs||tUpdatePanel1|0|childUpdatePanelIDs|||12|panelsToRefreshIDs||UpdatePanel1|2|asyncPostBackTimeout||90|13|formAction||default6.aspx|13|pageTitle||Untitled Page|

Cette réponse ne respecte pas le format établit par Microsoft Ajax Library c'est pour cela que l'exception PageRequestManagerParserErrorException est déclenché.

Vous avez surement remarqué que la syntaxe utilisée n'est pas une syntaxe courante. Pourquoi ce choix plutot que du JSON ou du XML ? Lors des différentes bêtas de Microsoft Ajax (aka Atlas), la réponse était sous le format XML, mais ce format posait deux problèmes : tout d'abord il est très verbeux et cela nécessitait de télécharger de nombreux octets inutiles, et surtout lire du XML en JavaScript est très couteux. En utilisant cette syntaxe, cela permet à Microsoft Ajax d'être plus rapide.

Eilon Lipton, le créateur de l'UpdatePanel, a aussi parlé de cette exception sur son blog : Sys.WebForms.PageRequestManagerParserErrorException - what it is and how to avoid it

Posted: dimanche 13 mai 2007 19:29 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

oliviers a dit :

Bonjour,

Merci pour ces explications qui éclairent ma lanterne quant à l'erreur (identique) que je reçois.

Question probablement stupide mais que faire quand modifier l'objet response reste nécessaire?

Dans mon cas, le construis une spreadsheet owc11 et la renvoie à l'utilisateur via l'objet response.

L'upadtePanel et l'UpadteProgress font bien leur boulot pendant la construction de la spreadsheet mais le flush de la response se plante proprement...

Merci,

Olivier

# février 27, 2008 16:19

cyril a dit :

Bonjour,

Si on utilise un UpdatePanel il est inutile de devoir modifier l'objet Response. Dans votre cas il est inutile d'utiliser un UpdatePanel car vous ne voulez pas rafraichir seulement une zone de la page.

Pourquoi ne pas alors mettre un UpdatePanel qui permettrais d'executer du code JavaScript pour ouvrir une nouvelle popup contenant votre spreadsheet ?

# mars 4, 2008 18:17
Les commentaires anonymes sont désactivés

Les 10 derniers blogs postés

- « Naviguer vers le haut » dans une librairie SharePoint par Blog de Jérémy Jeanson le 10-07-2014, 13:21

- PowerShell: Comment mixer NAGIOS et PowerShell pour le monitoring applicatif par Blog Technique de Romelard Fabrice le 10-07-2014, 11:43

- ReBUILD 2014 : les présentations par Le blog de Patrick [MVP Office 365] le 10-06-2014, 09:15

- II6 Management Compatibility présente dans Windows Server Technical Preview avec IIS8 par Blog de Jérémy Jeanson le 10-05-2014, 17:37

- Soft Restart sur Windows Server Technical Preview par Blog de Jérémy Jeanson le 10-03-2014, 19:43

- Non, le certificat public du CA n’est pas un certificat client !!! par Blog de Jérémy Jeanson le 10-03-2014, 00:08

- Windows Server Technical Preview disponible via MSDN par Blog de Jérémy Jeanson le 10-02-2014, 19:05

- Focus Sauvegardes SharePoint par Le blog de Patrick [MVP Office 365] le 10-02-2014, 13:11

- Technofolies, votre évènement numérique de l'année par Le Blog (Vert) d'Arnaud JUND le 09-26-2014, 18:40

- Xamarin : From Zero to Hero par Fathi Bellahcene le 09-24-2014, 17:35