14 Stimmen

Global Ausnahmen von ASP.NET [ScriptService]-Diensten protokollieren

Ich verwende das [System.Web.Script.Services.ScriptService]-Tag, um Webdienste aufrufen zu können, die von clientseitigem JavaScript aus aufrufbar sind. Was ich brauche, ist eine Möglichkeit, alle unbehandelten Ausnahmen in diesen Methoden global zu protokollieren. Auf der Clientseite erhalte ich den Fehler-Callback und kann von dort aus fortfahren, aber ich benötige einen serverseitigen Catch, um die Ausnahme zu protokollieren.

Der Typ unter dieser URL: http://ayende.com/Blog/archive/2008/01/06/ASP.Net-Ajax-Error-Handling-and-WTF.aspx

schlägt vor, dass dies nicht möglich ist.

Ist das korrekt? Muss ich wirklich zu jedem einzelnen Webmethoden im gesamten System gehen und die Methode als Ganzes mit Try/Catch versehen.

15voto

Daniel Richardson Punkte 4696

Sie können ein HTTP-Modul verwenden, um die Ausnahmemeldung, den Stapelüberlauf und den Ausnahmetyp zu erfassen, der von der Webdienstmethode ausgelöst wird.

Zuerst etwas Hintergrundinformationen...

  • Wenn eine Webdienstmethode eine Ausnahme auslöst, hat die HTTP-Antwortstatuscode 500.

  • Wenn benutzerdefinierte Fehler deaktiviert sind, gibt der Webdienst die Ausnahmemeldung und den Stapelüberlauf als JSON an den Client zurück. Zum Beispiel:
    {"Message":"Ausnahmemeldung","StackTrace":" at WebApplication.HelloService.HelloWorld() in C:\Projects\Stackoverflow Examples\WebApplication\WebApplication\HelloService.asmx.cs:line 22","ExceptionType":"System.ApplicationException"}

  • Wenn benutzerdefinierte Fehler aktiviert sind, gibt der Webdienst eine Standardmeldung an den Client zurück und entfernt den Stapelüberlauf und den Ausnahmetyp:
    {"Message":"Bei der Verarbeitung der Anfrage ist ein Fehler aufgetreten.","StackTrace":"","ExceptionType":""}

Also müssen wir benutzerdefinierte Fehler für den Webdienst deaktivieren und ein HTTP-Modul einfügen, das folgendes macht:

  1. Überprüfen, ob die Anfrage für eine Webdienstmethode ist
  2. Überprüfen, ob eine Ausnahme ausgelöst wurde - das heißt, ein Statuscode von 500 wird zurückgegeben
  3. Wenn 1) und 2) zutreffen, dann das ursprüngliche JSON abrufen, das an den Client gesendet werden würde, und es durch das Standard-JSON ersetzen

Der folgende Code ist ein Beispiel für ein HTTP-Modul, das dies tut:

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Web;

public class ErrorHandlerModule : IHttpModule {

  public void Init(HttpApplication context) {
    context.PostRequestHandlerExecute += OnPostRequestHandlerExecute;
    context.EndRequest += OnEndRequest;
  }

  static void OnPostRequestHandlerExecute(object sender, EventArgs e) {
    HttpApplication context = (HttpApplication) sender;
    // TODO: Aktualisieren Sie mit der richtigen Überprüfung für Ihre Anwendung
    if (context.Request.Path.StartsWith("/HelloService.asmx") 
        && context.Response.StatusCode == 500) {
      context.Response.Filter = 
        new ErrorHandlerFilter(context.Response.Filter);
      context.EndRequest += OnEndRequest;
    }
  }

  static void OnEndRequest(object sender, EventArgs e) {
    HttpApplication context = (HttpApplication) sender;
    ErrorHandlerFilter errorHandlerFilter = 
      context.Response.Filter as ErrorHandlerFilter;
    if (errorHandlerFilter == null) {
      return;
    }

    string originalContent =
      Encoding.UTF8.GetString(
        errorHandlerFilter.OriginalBytesWritten.ToArray());

    // Wenn customErrors deaktiviert sind, enthält originalContent JSON mit
    // der ursprünglichen Ausnahmemeldung, dem Stapelüberlauf und dem Ausnahmetyp.

    // TODO: Ausnahme protokollieren
  }

  public void Dispose() { }
}

Dieses Modul verwendet den folgenden Filter, um den Inhalt zu überschreiben, der an den Client gesendet wird, und um die ursprünglichen Bytes (die die Ausnahmemeldung, den Stapelüberlauf und den Ausnahmetyp enthalten) zu speichern:

public class ErrorHandlerFilter : Stream {

  private readonly Stream _responseFilter;

  public List OriginalBytesWritten { get; private set; }

  private const string Content = 
    "{\"Message\":\"Bei der Verarbeitung der Anfrage ist ein Fehler aufgetreten.\" + \",\"StackTrace\":\"\",\"ExceptionType\":\"\"}";

  public ErrorHandlerFilter(Stream responseFilter) {
    _responseFilter = responseFilter;
    OriginalBytesWritten = new List();
  }

  public override void Flush() {
    byte[] bytes = Encoding.UTF8.GetBytes(Content);
    _responseFilter.Write(bytes, 0, bytes.Length);
    _responseFilter.Flush();
  }

  public override long Seek(long offset, SeekOrigin origin) {
    return _responseFilter.Seek(offset, origin);
  }

  public override void SetLength(long value) {
    _responseFilter.SetLength(value);
  }

  public override int Read(byte[] buffer, int offset, int count) {
    return _responseFilter.Read(buffer, offset, count);
  }

  public override void Write(byte[] buffer, int offset, int count) {
    for (int i = offset; i < offset + count; i++) {
      OriginalBytesWritten.Add(buffer[i]);
    }
  }

  public override bool CanRead {
    get { return _responseFilter.CanRead; }
  }

  public override bool CanSeek {
    get { return _responseFilter.CanSeek; }
  }

  public override bool CanWrite {
    get { return _responseFilter.CanWrite; }
  }

  public override long Length {
    get { return _responseFilter.Length; }
  }

  public override long Position {
    get { return _responseFilter.Position; }
    set { _responseFilter.Position = value; }
  }
}

Diese Methode erfordert, dass benutzerdefinierte Fehler für die Webdienste deaktiviert sind. Wahrscheinlich möchten Sie benutzerdefinierte Fehler für den Rest der Anwendung eingeschaltet lassen, sodass die Webdienste in einem Unterverzeichnis platziert sein sollten. Benutzerdefinierte Fehler können in diesem Verzeichnis nur durch eine web.config deaktiviert werden, die die übergeordnete Einstellung außer Kraft setzt.

0 Stimmen

Obwohl ich dies nicht in meinem aktuellen Projekt verfolge, ist dies wahrscheinlich der einzige Weg, um alle diese Fehler zuverlässig zu erkennen.

0 Stimmen

Ich habe es versucht, aber irgendwie hat mein context.Response.Filter.length eine Ausnahme vom Typ "System.NotSupportedException" ausgelöst. Es funktioniert einfach nicht. Ich denke, es ist sehr nah dran, mein Output ist genau wie du gesagt hast und ich habe den 500-Statuscode erhalten.

3voto

Sameer Punkte 31

Sie führen die gespeicherte Prozedur im Hintergrund aus. Dann gibt es für eine einzige Variable mehr als einen Wert zurück. Aufgrund dessen kommt es zu einem Konflikt und dieser Fehler wird ausgelöst.

1voto

Nicholas Head Punkte 4071

Ich weiß, dass dies die Frage nicht direkt beantwortet, aber ich habe vor einer Weile meine eigene Suche gestartet, um dies herauszufinden, und bin leer ausgegangen. Am Ende habe ich jeden Webservice-Aufruf in ein try/catch eingepackt und der catch ruft unseren Fehler-Logger auf. Ist ärgerlich, aber es funktioniert.

-1voto

John Punkte 28172

In ASP.Net ist es möglich, alle unbehandelten Ausnahmen mit einem globalen Fehlerbehandler zu erfassen, obwohl der Blogbeitrag darauf hinweist, dass dies nicht funktionieren würde. Man könnte jedoch mit diesem Ansatz experimentieren und versuchen, den Fehler auf irgendeine Weise erneut auszulösen?

Eine andere Idee wäre, sich das Open-Source-Projekt elmah (Error Logging Modules and Handlers) für ASP.Net anzusehen, das möglicherweise helfen könnte, oder jemand in dieser Community könnte eine Idee haben.

1 Stimmen

Ja, ich bin mir nicht sicher, ob du das Problem wirklich verstanden hast. Die Ausnahme wird vom ASP.NET-Skriptdienstcode abgefangen - bevor ich die Möglichkeit habe, sie abzufangen. Daher funktioniert der globale Fehlerbehandler nicht. Das Framework sendet einen Fehler clientseitig, damit ich eine Nachricht anzeigen kann, aber es gibt keinen Server-Hook.

0 Stimmen

Allerdings ist der elmah Link interessant...ich werde mir das auf jeden Fall ansehen

0 Stimmen

Ich würde auch ELMAH empfehlen. Ich benutze es auch für genau diesen Zweck.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X