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

ASP.net - Accès concurrent à une même session interdite – SessionState en mode ReadOnly

De plus en plus d’applications web utilisent des services “Ajax” pour communiquer avec les serveurs. Ces services retournent généralement du JSON qui sera ensuite interprété côté client.

Pour diverses raisons, il est possible de vouloir exécuter 2 requêtes simultanément. Par exemple, un traitement longue durée s’effectue en arrière-plan tandis que le reste de l’application continue de fonctionner et d’effectuer des requêtes simples.
Dans certains cas, ASP.net peut bloquer la deuxième requête en attendant la fin de la première, cela peut s’avérer très problématique.

Il m’est récemment arrivé ce cas, j’ai trouvé l’explication du côté des sessions ASP.net :

Concurrent Requests and Session State

Access to ASP.NET session state is exclusive per session, which means that if two different users make concurrent requests, access to each separate session is granted concurrently. However, if two concurrent requests are made for the same session (by using the same SessionID value), the first request gets exclusive access to the session information. The second request executes only after the first request is finished. (The second session can also get access if the exclusive lock on the information is freed because the first request exceeds the lock time-out.) If the EnableSessionState value in the @ Page directive is set to ReadOnly, a request for the read-only session information does not result in an exclusive lock on the session data. However, read-only requests for session data might still have to wait for a lock set by a read-write request for session data to clear.
>> http://msdn.microsoft.com/en-us/library/ms178581.aspx 

Comme le note l’article MSDN, l’accès aux sessions est exclusif. Si une requête a besoin d’un accès à une session, toutes les autres requêtes ayant besoin d’accéder à cette même session sera mis en attente.

Avant de rentrer en détail dans les explications, il est important de savoir que les navigateurs limitent leur nombre de connexion simultanées. Internet Explorer 8- effectue maximum 2 requête simultanées pour un même nom d’hôte (cela correspond à la RFC et ne sera plus le cas avec IE9) alors que Firefox en fait 5.

Pour mettre en avant ce comportement, j’ai utilisé le bout de code suivant :

for (var i = 0; i < 20; i++) {
    $.ajax({
        cache: false,
        dataType: 'json',
        async: true,
        url: 'PouetService.svc/DoWork',
        success: function (result) {
            $('#pouet').append('<li>' + result.d + '</li>');
        }
    });
}

Lorsque j’exécute ce code, j’obtiens les résultats suivant avec Firebug :

image

On voit que 5 requêtes sont lancés de façon simultanées par le navigateur cependant les réponses arrivent de façon séquentiel.

Ce comportement peut être bloquant. Pour contourner cela, il est possible d’indiquer à ASP.net comment la requête accède à la session de l’utilisateur. Il y a 3 choix possible : aucun accès à la session, accès en lecture seul ou accès complet à la session. Seul l’accès complet ne peut pas être concurrent.

Si votre requête n’a pas besoin des sessions ou a besoin d’un accès en lecture seul aux sessions, il faut alors l’indiquer à ASP.net, ainsi la requête ne sera pas bloquée.

Comment spécifier le mode d’accès aux sessions ?

La modification du mode d’accès à la session dépend de façon dont est effectuée la requête.

Si la requête est une page ASP.net (WebForm ou MVC), alors on peut indiquer le mode d’accès dans la directive de page à l’aide de l’attribut EnableSessionState. Les valeurs possibles sont True, False, ReadOnly.

<%@ Page Language="C#" AutoEventWireup="true" EnableSessionState="False" CodeBehind="…" Inherits="…" %>

La valeur true est la valeur par défaut et donne un accès total à la session, seule cette valeur bloque les autres requêtes.

La valeur false permet de ne pas avoir de session pour la requête en cours. Dans ce cas, si vous tentez d’accéder à la session alors que la session est désactivé, vous aurez l’exception suivante : “Session state can only be used when enableSessionState is set to true”.

Comme son nom l’indique, la valeur ReadOnly permet d’accéder à la session mais la modification de valeur est interdite. Une nouveauté a été introduite dans .net 4.0, il est possible d’ajouter une valeur dans la session même en mode ReadOnly seul la modification de valeur est interdite avec .net 4.0. Avec .net 3.5, la création ou modification de valeur est interdite. Attention, si vous tentez de modifier une valeur, aucune erreur ne sera levée. Pour savoir si la session est en ReadOnly ou non, on peut utiliser la propriété IsReadOnly de l’objet Session.

Il est possible de changer la valeur par défaut pour toutes les pages depuis le fichier de config :

<system.web>
  <pages enableSessionState="ReadOnly" />
</system.web>

Autre nouveauté de ASP.net 4.0, on peut définir de façon impérative cette valeur, il faut pour cela utiliser la méthode SetSessionStateBehavior du HttpContext. Cette méthode doit par contre être appelée avant l’évènement AcquireRequestState.

Si la requête est un handler (ashx), alors par défaut, vous n’avez pas accès à la session. Pour avoir un accès total à la session, il faut implémenter l’interface IRequiresSessionState pour avoir un accès en lecture seul, il faut implémenter l’interface IReadOnlySessionState.

public class PouetHandler : IHttpHandler, IReadOnlySessionState

Le mécanisme décrit pour les pages reste identiques.

Si la requête est un service WCF, on ne peut pas contrôler le mode de session utilisé. La seule solution que j’ai trouvé consiste à désactiver le mode de compatibilité ASP.net, ainsi on aura plus accès à la session.

Pour désactiver le mode de compatibilité ASP.net, il faut enlever l’attribut AspNetCompatibilityRequirement du service et l’attribut aspNetCompatibilityEnabled de la section serviceHostingEnvironment du fichier de config

[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]

Je n’ai pas creusé avec Reflector. Si quelqu’un à une autre solution, je suis preneur.


Après avoir configuré correctement le mode d’accès à la session ASP.net, le comportement de mon application est désormais correcte : on peut voir que 5 requêtes s’exécutent en parallèle, ces 5 requêtes correspondent aux pool de requêtes de Firefox

image

Pour conclure, si votre page n’a pas besoin d’accéder à la session, désactiver la session. Si votre page ne fait que lire des objets en session, alors utilisez le mode ReadOnly. De plus, au-delà de l’accès concurrent, ASP.net effectuera moins de traitement, les performances de votre application sera alors meilleures.

Et vous, avez-vous déjà eu des problèmes similaires ?

Posted: samedi 19 février 2011 18:54 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

grozeille a dit :

Salut,

Très sympa cet article.

&gt; Et vous, avez-vous déjà eu des problèmes similaires ?

En effet, et même pire! J'utilise Spring.Net avec des instances "scope=session" ce qui rend impossible l'affichage de 2 pages en simultané pour la même session!

Du coup, j'en avais déjà parlé:

http://grozeille.com/2010/10/24/spring-net-asp-net-session-et-multithreadind/

# février 22, 2011 07:55

postb99 a dit :

Bonjour,

Merci pour l'astuce.

Et si on n'a qu'une seule page aspx, tout le cntenu issu de requêtes Ajax... dans ce cas comment distinguer les appels ajax qui feront usage de la session en RW et ceux en readonly ? Je pense qu'on est coincés alors ?

# mars 3, 2011 13:14

cyril a dit :

@postb99 : je ne comprends pas la question, peux tu expliciter ?

# mars 3, 2011 22:39
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