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

Optimisation du ViewState - l'enregistrer sur le server via le SessionPageStatePersister

Il y a quelques temps je vous avez expliqué comment modifier la façon dont le viewstate est enregistré, nous avions vu qu'il fallait surcharger les méthodes SavePageStateToPersistenceMedium et LoadPageStateToPersistenceMedium. Je viens de découvrir que l'on peut faire encore mieux, il est également possible de surcharger la propriété PageStatePersister de l'objet Page.

Cette propriété de type PageStatePersister est une classe abstraite qui nécessite la surcharge de deux méthodes : Save et Load qui sauvegarde ou restaure l'état des contrôles. Il existe deux implémentations dans ASP.net, HiddenFieldPageStatePersister et SessionPageStatePersister. Par défaut le HiddenFieldPageStatePersister est utilisé. C'est lui qui est responsable de l'émission d'un champ caché "__VIEWSTATE" qui pose bien des problèmes.

Avec ASP.net Ajax, on utilise de plus en plus des UpdatePanel, or le fonctionnement d'un UpdatePanel est exactement le même qu'un postback : le viewstate transite entre les appels ! Dans certains cas cela peut être une cause de problème de performance, il peut alors être intéressant de stocker cet état au niveau du serveur dans la session. De plus, il semble que si l'on utilise massivement le viewstate, le CPU et la mémoire s'affole. Pour sauvegarder l'état de la page dans le session on peut utiliser le SessionPageStatePersister. Deux possibilités :

  • Vous disposez d'une classe Page abstraite commune à toutes vos pages (ce que je recommande). Il faut alors surcharger la propriété PageStatePersister de la sorte :

protected override PageStatePersister PageStatePersister { get { return new SessionPageStatePersister(this.Page); } }

  • Vous ne disposez pas d'une classe Page abstraite. Il vous faut alors utiliser un Control Adapter :

public class MyPageAdapter : System.Web.UI.Adapters.PageAdapter { public override PageStatePersister GetStatePersister() { return new SessionPageStatePersister(Page); } }

Puis dans votre fichier .browser rajouter votre ControlAdapter :
<browsers> <browser refID="Default"> <controlAdapters> <adapter controlType="System.Web.UI.Page" adapterType="CS.CSSFriendly.MyPageAdapter" />

Par défaut, le ControlState est encore stocké dans le champ caché __ViewState pour modifier ce comportement il faut modifier le fichier .browser

<browsers> <browser refID="Default"> <capabilities> <capability name="requiresControlStateInSession" value="true" /> </capabilities>

Le ControlState est généralement très petit et contient l'état d'un contrôle même si l'on met EnableViewState à false : Control State vs. View State Example (MSDN)

[UPDATE] Ashi4 m'a donné une autre solution pour modifier ce comportement directement au niveau du web.config. Vu ici : ViewState, ControlState et PageStatePersister

<configuration>
   
<system.web>
       
<browserCaps>
           
<case>RequiresControlStateInSession=true</case>
       
</browserCaps>
   
</system.web>
</configuration>

[/UPDATE]

Le champ "__ViewState" restera malgré tout toujours présent. Pourquoi ? En fait, le viewstate ne contiendra plus que la clé de l'état dans la session, il pésera moins de 100 octets. Si vous ne voulez plus du champ ViewState vous pouvez toujours modifier ce comportement en surchargeant les méthodes SavePageStateToPersistenceMedium et LoadPageStateToPersistenceMedium.

Attention : Changer ce paramètre n'est pas une choses anodine ! En utilisant le SessionPageStatePersister vous allez considérablement augmenter les ressources utilisé par votre serveur, en effet toutes les requêtes vont alors enregistrer l'état en session, y compris les requêtes qui ne gèrent pas les sessions (bot, refus des cookies, ...) Il est alors bon de bien customiser son fichier .browser pour utiliser le SessionPageStatePersister avec les clients/pages qui nécessitent l'utilisation du SessionStatePersister.

L'avantages d'utiliser un champ caché et au niveau de la gestion de l'historique. En effet lorsque l'on va sur la page précédente, on retrouve le bon viewstate. Pour gérer ce cas là, le SessionPageStatePersister utilise une Queue qui contient par défaut les 9 derniers états en session. Pour modifier cette valeur il faut modifier le web.config de la sorte :

<configuration> <system.web> <sessionPageState historySize="9"/>

Remarque : Bien sur, mettre l'état des contrôles sur le serveur est une solution à bien des problèmes, mais il est également nécessaire de désactiver le viewstate là où il n'est pas indispensable. Pour cela il faut bien comprendre le fonctionnement de celui-ci. L'article TRULY Understanding ViewState vous sera très utile.

PS : Je n'ai pas encore utilisé cette solution dans un vrai site web, mais je vais l'utiliser assez rapidement. Si vous avez des retour d'experience, n'hésitez pas à les partager :)

D'autres en parlent :

Posted: mercredi 2 janvier 2008 15:23 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

Ashi4 a dit :

j'étais tomber sur cette classe il y a quelque temps...

Public Class SpecialPage

   Inherits System.Web.UI.Page

   Private _PageStatePersister As PageStatePersister

   Protected Overloads Overrides ReadOnly Property PageStatePersister() As System.Web.UI.PageStatePersister

       Get

           If _PageStatePersister Is Nothing Then

               _PageStatePersister = New SessionPageStatePersister(Me)

           End If

           Return _PageStatePersister

       End Get

   End Property

End Class

et les pages hérite non plus de page mais de specialpage. Tout le viewstat ce retrouve alors sur le server.

les explications sont là :

http://controlbreak.free.fr/index.php/tag/ViewState

# janvier 2, 2008 16:03

cyril a dit :

Vi c'est la version VB de ce que j'explique avec la classe Page abstraite :-)

Je viens de mettre à jour mon post en expliquant comment modifier la persistance du ControlState au niveau du web.config.

As tu des retour particuliers sur le SessionPageStatePersister ? Je pense réimplémenter mon propre PageStatePersister pour désactiver le mode Session aux bots pour éviter de trop surcharger le serveur.

# janvier 2, 2008 16:48

Ashi4 a dit :

bah non étonnament tout marche bien, par contre, j'ai pas fait de test avec pleins de visiteur, je travail uniquement sur un intranet, et j'ai un serveur qui peut très largement prendre les sessions de mes utilisateurs...

donc pour ma part, je peux vous dire que dans le cadre d'un intranet ça marche très bien et ça améliore les temps de réponse. mais je ne m'avance pas plus.

# janvier 2, 2008 17:05

brezhon a dit :

Bonjour,

J'ai mis en place ce mécanisme il y a quelques temps et je rencontre aujourd'hui des problèmes en cas de navigation multi-onglet.

L'utilisateur ouvre un premier onglet, puis un second sur lequel il navigue (nb de postback &gt; historySize); quand il revient au premier onglet il n'a plus le viewstate correspondant à cette page.

J'ai augmenté l'attribut historySize à 25 pour avoir moins d'erreurs techniques mais cette solution n'est pas viable.

Quelqu'un a-t-il déjà rencontré ce problème?

Je me demande également si la solution du viewstate côté serveur n'est pas une fausse bonne idée? (au vu de mon problème.)

Julien.

# mai 6, 2010 10:05

cyril a dit :

Bonjour,

Le problème rencontré est "by design".

Afin de gérer l'historique des pages, chaque viewstate est mis en session. Pour éviter que la session explose, il y a une limite au niveau du nombre d'état sauvegardé (9 par défaut).

Si l'utilisateur peut faire plein de retour arriere, alors ce n'est pas forcément une bonne idée de mettre le viewstate coté serveur.

Cette solution à effectivement ses limites du coté de l'historique, ce n'est pas génant dans la majorité des cas.

# mai 6, 2010 11:21
Les commentaires anonymes sont désactivés

Les 10 derniers blogs postés

- SharePoint : Bug sur la gestion des permissions et la synchronisation Office par Blog Technique de Romelard Fabrice le 07-10-2014, 11:35

- SharePoint 2007 : La gestion des permissions pour les Workflows par Blog Technique de Romelard Fabrice le 07-08-2014, 11:27

- TypeMock: mock everything! par Fathi Bellahcene le 07-07-2014, 17:06

- Coding is like Read par Aurélien GALTIER le 07-01-2014, 15:30

- Mes vidéos autour des nouveautés VS 2013 par Fathi Bellahcene le 06-30-2014, 20:52

- Recherche un passionné .NET par Tkfé le 06-16-2014, 12:22

- [CodePlex] Projet KISS Workflow Foundation lancé par Blog de Jérémy Jeanson le 06-08-2014, 22:25

- Etes-vous yOS compatible ? (3/3) : la feuille de route par Le blog de Patrick [MVP SharePoint] le 06-06-2014, 00:30

- [MSDN] Utiliser l'approche Contract First avec Workflow Foundation 4.5 par Blog de Jérémy Jeanson le 06-05-2014, 21:19

- [ #ESPC14 ] TH10 Moving mountains with SharePoint ! par Le blog de Patrick [MVP SharePoint] le 06-01-2014, 11:30