Dans une des applications dont je m’occupe, nous utilisons ASP.NET MVC (dans la version 3) dans une web application ou le contenu du site est mis à jour via des requêtes AJAX. J’ai remarqué que certaines actions pourtant rapide si effectuée seule, prenait beaucoup de temps lorsque celle-ci était effectuée après avoir lancée une autre action plus longue. L’application semblait comme bloquée pour la plupart des actions nécessitant le serveur.
Après analyse, j’ai vu qu’il s’agissait d’un problème lié à Session State.
Voici ce que dit la MSDN concernant Session State et les demandes simultanées.
Demandes simultanés et état de session
L’accès à l’état de session ASP.NET s’effectue exclusivement par session, ce qui signifie que si deux utilisateurs différents effectuent des demandes simultanées, l’accès à chaque session distincte est accordé simultanément. Toutefois, si deux demandes simultanées sont faites pour la même session (en utilisant la même valeur SessionID), la première demande a l’accès exclusif aux informations sur la session. La deuxième demande s’exécute uniquement après que la première demande est terminée. (La deuxième session peut également obtenir l’accès si le verrou exclusif sur les informations est libéré parce que la première demande dépasse le délai d’attente de verrouillage.) Si EnableSessionState de la directive @ Page a la valeur ReadOnly, une demande d’informations de session en lecture seule n’entraîne pas de verrouillage exclusif des données de session. Cependant, les demandes de données de session en lecture seule risquent encore de patienter jusqu’à ce qu’un verrouillage définit par une demande de données de session en lecture-écriture soit désactivé.
Voici un exemple montrant ce problème. J’ai créé un controller qui a 2 Actions de type JsonResult. Je simule un traitement long pour la méthode accédant à une variable en Session.
[SessionState(System.Web.SessionState.SessionStateBehavior.Default)] public class AjaxController : Controller { public JsonResult GetUserName() { //Simulate long process System.Threading.Thread.Sleep(3000); return Json(Session["Name"], JsonRequestBehavior.AllowGet); } public JsonResult GetUserCulture() { return Json(this.Request.UserLanguages", JsonRequestBehavior.AllowGet); } }
Pour le test, Voici le code JavaScript qui utilise jQuery pour faire 2 requête AJAX (donc asynchrones). J’utilise console.time et console.timeEnd pour afficher dans la console de la barre d’outils, le temps d’exécution des appels AJAX.
console.time('GetUserName'); $.ajax({ url: '/Home/GetUserName', success: function (response) { console.log(response); console.timeEnd('GetUserName'); } }); console.time('GetUserCulture'); $.ajax({ url: '/Home/GetUserCulture', success: function (response) { console.log(response); console.timeEnd('GetUserCulture'); } });
Et voici le résultat par défaut. On peut voir que le résultat de l’appel à la méthode GetUserCulture prends pratiquement 3,5s !
Nous allons modifier l’attribut SessionState du controller afin de lui indiquer que nous n’accédons qu’en lecture seule à la session. Ainsi les données de session ne seront plus verrouillées pour les méthodes du controler.
[SessionState(System.Web.SessionState.SessionStateBehavior.ReadOnly)] public class AjaxController : Controller
Le temps d’exécution de la méthode est de 540ms. Nous avons gagnés 3s qui était liées au traitement de la méthode GetUserName qui verrouillait la session.
Comme vous pouvez le voir, cet attribut se positionne sur les classes (controller) et non sur les méthodes, ce que je ne trouve pas forcément optimal. Voici un lien qui permet de définir un attribut personnalisé permettant la configuration par action.
Tweet