2010-12-15 44 views
8

Lorsque je crée un gestionnaire Session_Start vide dans Global.asax.cs, il provoque un échec significatif lors du rendu des pages dans le navigateur.Pourquoi Session_Start dans Global.asax.cs cause-t-il des problèmes de performances?

Comment reproduire:

Créer une application Web ASP.NET MVC 3 vide (J'utilise MVC 3 RC2). Ensuite, ajoutez un contrôleur Home avec ce code:

public class HomeController : Controller 
{ 
    public ActionResult Index() 
    { 
    return View(); 
    } 
    public ActionResult Number(int id) 
    { 
    return Content(id.ToString()); 
    } 
} 

Suivant créer une vue Accueil/Index.cshtml et placez ce qui suit dans la section BODY:

@for (int n = 0; n < 20; n++) 
{ 
    <iframe src="@Url.Content("~/Home/Number/" + n)" width=100 height=100 /> 
} 

Lorsque vous exécutez cette page, vous ll voir 20 IFRAMEs apparaissent sur la page, chacun avec un nombre à l'intérieur. Tout ce que je fais ici, c'est créer une page qui charge 20 pages de plus dans les coulisses. Avant de continuer, prenez note de la vitesse de chargement de ces 20 pages (actualisez la page plusieurs fois pour répéter les charges).

Ensuite, allez à votre Global.asax.cs et ajoutez cette méthode (oui, le corps de la méthode est vide):

protected void Session_Start() 
{ 
} 

Exécutez maintenant la page. Cette fois, vous remarquerez que les 20 IFRAME se chargent beaucoup plus lentement, l'un après l'autre à environ 1 seconde d'intervalle. C'est étrange parce que nous ne faisons rien dans Session_Start ... c'est juste une méthode vide. Mais cela semble être suffisant pour provoquer le ralentissement dans toutes les pages suivantes.

Est-ce que quelqu'un sait pourquoi cela se produit, et mieux encore quelqu'un a-t-il une solution/solution de contournement?

Mise à jour

J'ai découvert que ce problème se produit uniquement lorsque le débogueur est attaché (en cours d'exécution avec F5). Si vous l'exécutez sans le débogueur joint (Ctrl-F5), il semble que ce soit correct. Donc, peut-être que ce n'est pas un problème important mais c'est quand même étrange.

+0

J'ai rencontré ce problème sur les requêtes AJAX dans une application SPA. Je me suis éloigné de l'utilisation de SessionState. – voam

Répondre

10

tl; dr: Si vous faites face à ce problème avec Webforms et ne nécessitent pas l'accès en écriture à l'état de session dans cette page particulière, ajoutant EnableSessionState="ReadOnly" à votre @Page directive aide.


Apparemment, l'existence de forces Session_Start seule ASP.NET pour exécuter toutes les demandes provenant de la même manière séquentielle session. Ceci, cependant, peut être fixé page par page si vous n'avez pas besoin d'un accès en écriture à la session (voir ci-dessous).

J'ai créé mon propre paramètre de test avec Webforms, qui utilise une page aspx pour fournir des images.

est ici la page de test (HTML brut, la page de démarrage du projet):

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml"> 
<head><title></title></head> 
<body> 
    <div> 
     <img src="GetImage.aspx?text=A" /> 
     <img src="GetImage.aspx?text=B" /> 
     <img src="GetImage.aspx?text=C" /> 
     <img src="GetImage.aspx?text=D" /> 
     <img src="GetImage.aspx?text=E" /> 
     <img src="GetImage.aspx?text=F" /> 
     <img src="GetImage.aspx?text=G" /> 
     <img src="GetImage.aspx?text=H" /> 
     <img src="GetImage.aspx?text=I" /> 
     <img src="GetImage.aspx?text=J" /> 
     <img src="GetImage.aspx?text=K" /> 
     <img src="GetImage.aspx?text=L" /> 
    </div> 
</body> 
</html> 

est ici la page ASPX (GetImage.aspx):

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="GetImage.aspx.cs" Inherits="CsWebApplication1.GetImage" %> 

et les parties concernées du codebehind (GetImage.aspx.cs, using et namespace sauté):

public partial class GetImage : System.Web.UI.Page 
{ 
    protected void Page_Load(object sender, EventArgs e) 
    { 
     Debug.WriteLine("Start: " + DateTime.Now.Millisecond); 
     Response.Clear(); 
     Response.ContentType = "image/jpeg"; 

     var image = GetDummyImage(Request.QueryString["text"]); 
     Response.OutputStream.Write(image, 0, image.Length); 
     Debug.WriteLine("End: " + DateTime.Now.Millisecond); 
    } 

    // Empty 50x50 JPG with text written in the center 
    private byte[] GetDummyImage(string text) 
    { 
     using (var bmp = new Bitmap(50, 50)) 
     using (var gr = Graphics.FromImage(bmp)) 
     { 
      gr.Clear(Color.White); 
      gr.DrawString(text, 
       new Font(FontFamily.GenericSansSerif, 10, FontStyle.Regular, GraphicsUnit.Point), 
       Brushes.Black, new RectangleF(0, 0, 50, 50), 
       new StringFormat { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center }); 
      using (var stream = new MemoryStream()) 
      { 
       bmp.Save(stream, ImageFormat.Jpeg); 
       return stream.ToArray(); 
      } 
     } 
    } 
} 

test fonctionne

  • Run 1, non modifiée: La page se charge rapide, la fenêtre de sortie montre un mélange aléatoire de Start et End s, ce qui signifie que les demandes se traitées en parallèle.

  • Run 2, ajoutez vide Session_Start-global.asax (besoin de frapper F5 une fois dans le navigateur, ne sais pas pourquoi cela est): Start et End autre, montrant que les demandes traitées se sequentually. L'actualisation du navigateur plusieurs fois indique que cela pose des problèmes de performances même lorsque le débogueur n'est pas connecté.

  • Run 3, comme Run 2, mais ajouter EnableSessionState="ReadOnly" à la directive @Page de GetImage.aspx: La sortie de débogage affiche plusieurs Start s avant la première End. Nous sommes à nouveau parallèles et nous avons de bonnes performances.


Oui, je sais que cela doit être fait avec un gestionnaire de ashx à la place. C'est juste un exemple.

+0

Intéressant ... pouvez-vous tester ce qui se passe lorsque vous exécutez ces tests en dehors du débogueur (c'est-à-dire lancer avec Ctrl-F5 plutôt que F5) – Mike

+0

@Mike: Je l'ai fait. L'exécution 2 est plus lente que les autres, même sans le débogueur (la différence n'est pas aussi forte qu'avec le débogueur, mais elle est encore perceptible). – Heinzi

3

Vous ne pouvez pas vous dire ce que fait votre débogueur (intellitrace? Enregistrement détaillé? Exceptions de première chance?), Mais vous êtes toujours dans les mains de la capacité de sessions pour gérer des demandes simultanées.

L'accès à l'état de session ASP.NET est exclusif 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 effectuées pour la même session (en utilisant la même valeur SessionID), la première requête obtient un accès exclusif aux informations de session. La deuxième requête s'exécute seulement après que la première requête est terminée. (La deuxième session peut également avoir accès si le verrou exclusif sur les informations est libéré car la première requête dépasse le délai de verrouillage.) Si la valeur EnableSessionState dans la directive @ Page est définie sur ReadOnly, une demande de lecture seules les informations de session n'entraînent pas un verrouillage exclusif des données de session. Cependant, les requêtes en lecture seule pour les données de session peuvent toujours attendre qu'un verrou défini par une demande de lecture-écriture pour les données de session soit effacé.

Source: ASP.NET Session State Overview, mon accent

+0

Ceci est intéressant à savoir, mais je ne pense pas qu'il explique le comportement décrit ci-dessus. La seule différence entre le cas n ° 1 et le cas n ° 2 est la présence d'une méthode Session_Start vide dans Global.asax.cs. Selon votre référence, les deux cas doivent toujours se comporter de la même manière. – Mike

+0

Apparemment, une méthode 'Session_Start' vide dans Global.asax.cs suffit pour effectuer des demandes de sérialisation ASP.NET. J'ai rencontré un problème similaire avec Webforms et j'ai trouvé qu'il peut être corrigé en définissant 'EnableSessionState =" ReadOnly "' dans la directive '@ Page' de la page aspx servant les pages parallèles (images dans mon cas). Je ne sais pas si une option similaire existe pour MVC. – Heinzi

+0

@Heinzi Très intéressant! Avez-vous des documents/preuves montrant ce comportement? Si oui, veuillez créer une nouvelle réponse et je la marquerai comme acceptée. – Mike