Retour sur le ViewState
Par amethyste le Oct 18, 2008 | Dans focus | 4 retours »
Cette semaine j'ai reçu un email d'une personne qui venait de lire mon article sur le viewstate[1] émaillé de plusieurs questions.
Comme il y a longtemps que je n'ai pas fais de blog je vais y répondre ici. D'autant plus que la bonne maîtrise du fonctionnement du ViewState me semble indispensable en ASP.NET.
Quand tu écris: "...Seules les données dont la propriété IsDirty est à false seront recopiées..." (partie "Créer correctement un composant dynamique"), je ne comprend pas pourquoi.
Pourquoi aller sauvegarder des propriétés qui n'ont pas été modifiées dans le code (code behind après la phase d'init et donc le marked à true) au niveau du ViewState ??? Ne souhaitons-nous pas plutôt sauvegarder ce qui a été changé dans le code afin de faire persister ces données ???
IsDirty sert à différencier deux situations.
Une propriété peut être présente dans le code d'initialisation du composant, c'est-à-dire soit alimentée au cours de son événement Init, soit déclaré dans la page ASPX comme ceci:
<asp:Button ID="Button1" runat="server" Text="Valider" />
Dans les deux cas on va trouver quelque chose de ce genre dans le code d'initialisation:
this.Button1.Text = "Valider"; (1)
Dans ce cas il est inutile de sauvegarder la valeur de la propriété Text dans le ViewState car elle est déjà dans le code généré par ASP pour initialiser la page.
Mais ce n'est pas toujours le cas. Notre code peut contenir ceci dans l'événement Page.Load:
this.Button1.Text = MaBll.MaFonction(); (2)
Si MaFonction() retourne une information rapide à obtenir et/ou non pérenne (un cours boursier!) on doit effectivement réexécuter ce code à chaque renvoi. Mais le plus souvent c'est inutile et on préfère l'enregistrer dans le ViewState pour le recharger automatiquement (on n'oublie pas d'implémenter la règle d'alimentation dans ce cas!).
Si vous comparez (1) et (2), vous constatez qu'il s'agit du même code, mais dans deux situations distinctes. IsDirty permet de les distinguer et dire à ASP.NET si on doit ou non sérialiser l'information dans le ViewState.
Voici donc ma compréhension du mécanisme.
Quand tu écris "...Simplement le fait que les composants qui implémentent IPostBackEventHandler, comme les TextBox, gèrent eux même leur état..." (partie "Persistance d'un Label"), je suis personnellement et actuellement (car j'ai peut-être pas bien compris) à moitié d'accord. En effet, le TextBox n'est persistant qu'au niveau de la propriété Text uniquement.
En effet, si je prend le TextBox suivant:<asp:TextBox ID="txtBox1" EnableViewState="false" runat="server" />Et que dans le page_load, je fais:
if (!this.IsPostBack)
{
txtBox1.ToolTip = "Def";
txtBox1.Text = "test";
}
La propriété Text sera bien persistante mais pas la propriété ToolTip. Ceci doit être du au fait que le POST ne "poste" que la valeur du champ input>.
Le code standard pour créer une propriété personnalisée qui persiste sa valeur dans le viewstate est le suivant:
#region MyProperty /// <summary> /// (Description) /// </summary> [Category("Data"), Description("(Description)")] public String MyProperty { [DebuggerStepThrough] get { if (this.ViewState["MyProperty"] == null) { // valeur par défaut return default(String); } return (String)this.ViewState["MyProperty"]; } [DebuggerStepThrough] set { this.ViewState["MyProperty"] = value; } } #endregion
(Notez la présence des commentaires, je suis un intégriste religieux la dessus!).
Je suis certain que vous comprendrez sans difficultés comment ça marche.
Si vous décompilez la classe TextBox vous verrez un code similaire pour sa propriété Text. Si vous faites de même pour ToolTip (hérité de WebControl), vous trouvez aussi la même chose!
De fait la persistance de ToolTip est active, comme celle de Text. Chez moi le code fonctionne comme prévu. Mais avec VS2008. Peut être que cela à changé par rapport à des versions plus anciennes de ASP.NET.
Depuis la rédaction de cet article, j'ai appris des choses que j'ignorai au sujet des coulisses du mécanisme de persistance qui ne doit rien à ASP.NET, mais est natif à HTML. J'ai expliqué cela dans un autre blog que je vous encourage à lire[2] également.
Je vous y encourage même vivement, car par expérience il m'aurait évité de m'arracher les cheveux sur des composants dynamiques qui ne se réinitialisent pas bien sur pas mal de projets alors que la solution tenait en une seule ligne!
Bibliographie
[1] http://www.dotnetguru.org/articles/dossiers/viewstate/viewstate.htm
[2] http://www.dotnetguru2.org/amethyste/index.php?p=785&more=1&c=1&tb=1&pb=1
4 commentaires
En effet, la question est "lorsque l'on implemente LIPostBackEventHandler la persistance des proproiétés est activé ?"
Je répondrais non, IPostBackDataHandler (et non IPostBackEventHandler) est nécessaire quand le webcontrol posséde des champs de type input, ce qui est le cas d'une textbox.
Cette interface permet de récuperer la valeur de l'input en cas de postback. C'est très rare d'avoir besoin de cette interface puisque pour tous les input existant en HTML il existe un WebControl correspondant. On peut avoir besoin de cette interface si on ne veut pas faire de composition (via CompositeControl) mais la nécessité de ce cas est rare.
IPostBackDataHandler est Viewstate n'a donc pas grand chose à voir, dans le cas de l'exemple, la persistance de la propriété Text est "assuré" car c'est le formulaire qui renvoie la valeur de cette propriété et non le viewstate.
Du coup le fait que la propriété Text persiste dans le viewstate peut paraitre étrange puisque cette valeur se trouve déjà dans les données POST classique du formulaire. Cela se justifie lorsque la textbox se trouve dans dans un container où l'on peut jouer avec la visibilité, ce qui est le cas du multiview & co.
J'ai bien étudié vos réponses et je vous en remercie (je suis la personne ayant posé les questions).
Cependant, je ne comprend pas (ou plutôt je comprend totalement...) la première réponse sur la propriété IsDirty à false.
Je comprend tout à fait ce que tu expliques. IsDirty est fait pour différencier les propriétés instanciées avant initialisation (code de la page aspx ou méthode OnInit) des autres.
De plus, les propriétés chargées avant initialisation n'ont nullement besoin d'être sauvegardées (normal). Cependant, pour moi (dites moi si je me trompe), ces propriétés correspondent à une propriété IsDirty à false.
Donc, pour moi, les propriétés qui doivent être sauvegardées dans le ViewState sont les propriétés avec IsDirty=true (ou non false).
En effet, si je lance le code suivant dans le page_load:
if(!IsPostBack)
{
lbl1.txt = "test";
}
Je voudrais que ce texte soit sauvegardé quelque part pour être restituer à chaque chargement de page. Et pour moi, le IsDirty passe à true après l'exécution du code (lbl1.txt = "test") si je comprend bien ton article.
Donc, ca reste flou dans mon esprit. Je suis d'accord avec toi sur ton raisonnement mais tu conclues en disant: on sauvegarde les propriétés avec IsDirty=false (c'est là que je te perds ^^).
Merci encore pour tout,
Bonne journée,
effectiement il y a une erreur dans mon texte que l'on m'a d'ailleurs fait remarquer en juin dernier.
j'ai intervertit le true et le false dans le fonctionnement de IsDirty
Laisser un commentaire
| « Les chaînes et le contexte linguistique | SAGA 5: sérialisation XML » |