2010-03-04 5 views
14

Longue histoire courte, j'ai une application ASP.NET, je suis en train de déboguer et à un moment donné, dans des circonstances très particulières, l'application des exceptions à un lancer Response.Redirect() indiquant:Comment puis-je savoir quand des en-têtes HTTP ont été envoyés dans une application ASP.NET?

"Cannot redirect after HTTP headers have been sent." 

Que je plus ou moins obtenir, sauf que je ne peux pas comprendre les en-têtes ont été envoyés.

Y a-t-il quelque chose à rechercher dans une application ASP.NET qui indiquera que les en-têtes HTTP ont été envoyés?

BONUS DIFFICULTÉ: L'application ASP.NET est toujours dans .NET 1.1. Les circonstances concernant le retard de la mise à niveau sont un sujet vraiment douloureux.

+0

Réponse Buffering ('Response.Buffer' - vous voulez ceci sur) et Flushing réponse (' Response.Flush() '- vous n Je ne veux pas faire ça) sont deux candidats évidents. – bzlm

Répondre

15

HttpApplication a un événement PreSendRequestHeaders qui est appelé juste quand les en-têtes sont écrits. Abonnez-vous à cela et connectez-vous ou ajoutez un point d'arrêt.

Au-delà, HttpResponse a une propriété interne appelé HeadersWritten (champ _headersWritten dans .NET 1.1). Comme c'est interne, vous ne pouvez pas y accéder directement, mais vous pouvez le faire par réflexion. Si c'est uniquement pour le débogage interne (c'est-à-dire, pas pour le code de production), alors il est bon d'utiliser la réflexion.

Vérifiez cette méthode avant/après tous les événements lifecylce de la page. Une fois que vous savez quel événement écrit les en-têtes, ajoutez d'autres contrôles HeadersWritten pour savoir où ils sont écrits. Grâce au rétrécissement progressif des chèques à cette propriété, vous le trouverez.

Nouvelle information

HeadersWritten propriété est public à partir de .Net 4.5.2

+0

Cela semble vraiment bon ... sauf que j'ai oublié de mentionner que l'application est dans. NET 1.1 et cela semble être une solution .NET 2.0+. –

+0

@Schnapple, .NET 1.1 est vraiment vieux. Vous devriez toujours spécifier la version chaque fois que vous parlez d'une ancienne version. Dans .NET 1.1, il y avait juste un champ privé, '_headersWritten', que vous pouvez lire à travers la réflexion. –

+2

La propriété 'HeadersWritten' est publique à partir de .Net 4.5.2 –

5

la réponse de Samuel vient de résoudre ce problème pour moi (+1). Je ne peux pas coller un exemple de code dans un commentaire, mais dans l'intérêt d'aider les autres, voici comment je l'événement, il a suggéré d'ajouter une propriété HeadersWritten à mon IHTTPHandler:

protected bool HeadersWritten { get; private set; } 

void ApplicationInstance_BeginRequest(object sender, EventArgs e) 
{ 
    HeadersWritten = false; 
} 

void ApplicationInstance_PreSendRequestHeaders(object sender, EventArgs e) 
{ 
    HeadersWritten = true; 
} 

public void ProcessRequest(HttpContextBase context) 
{ 
    context.ApplicationInstance.PreSendRequestHeaders += new EventHandler(ApplicationInstance_PreSendRequestHeaders); 
    do_some_stuff(); 
} 

Dans mon code qui romprait si je mess avec les en-têtes trop tard, je vérifie simplement la propriété HeadersWritten première:

if (!HeadersWritten) 
{ 
    Context.Response.StatusDescription = get_custom_description(Context.Response.StatusCode); 
} 
+4

Sachez que chaque instance d'un objet 'HttpApplication' peut servir plusieurs requêtes (mais toujours séquentielles), vous devez * donc * réinitialiser l'indicateur au cours de l'événement BeginRequest. Cela s'applique également à un 'HTTPHandler' dont la propriété' IsReusable' renvoie true. Voir [HttpApplication] (http://msdn.microsoft.com/en-us/library/system.web.httpapplication.aspx) et [IsResuable] (http://msdn.microsoft.com/fr-fr/library/ system.web.ihttphandler.isreusable.aspx) dans MSDN pour plus de détails. –

+0

Merci pour cela, Euro. Pour être clair, j'ajoute cette propriété et le code et les événements associés à ma classe qui hérite de IHttpHandler. J'ai cru comprendre que cette classe devrait être à usage unique pour cette demande, et donc totalement à l'abri des interférences provenant d'autres demandes. Si cette compréhension n'est pas correcte, s'il vous plaît faites le moi savoir! –

+0

L'un des membres de l'interface IHttpHandler est une propriété appelée 'IsReusable' (j'ai mal orthographié dans mon commentaire original). Si votre implémentation est essentiellement 'public bool IsReusable {get {return false; }} ', alors tout va bien: ASP.NET va instancier un objet pour chaque requête et ensuite le jeter. Si vous renvoyez 'true', ASP.NET réutilisera vos instances pour plusieurs requêtes et vous ne pourrez pas utiliser de thread. –

Questions connexes