Globalnie loguj wyjątki z ASP.NET [ScriptService] usługi

Używam [systemu.Www.Scenariusz.Usługi.ScriptService] tag do korzystania z usług internetowych wywołanych z javascript po stronie klienta. Potrzebuję sposobu globalnego rejestrowania wszelkich nieobsługiwanych wyjątków w tych metodach. Po stronie klienta dostaję oddzwonienie o błędzie i mogę kontynuować stamtąd, ale potrzebuję przechwytywania po stronie serwera, aby zarejestrować wyjątek.

Facet pod tym adresem url: http://ayende.com/Blog/archive/2008/01/06/ASP.Net-Ajax-Error-Handling-and-WTF.aspx

Sugeruje, że to to niemożliwe.

Czy to prawda? Czy naprawdę muszę przejść do każdego webmethod w całym systemie i spróbować / złapać metodę jako całość.

Author: Clyde, 2009-01-24

4 answers

Możesz użyć modułu HTTP do przechwytywania wiadomości wyjątku, śledzenia stosu i typu wyjątku, które są rzucane przez metodę usługi internetowej.

Najpierw trochę tła...
  • Jeśli metoda usługi internetowej rzuca wyjątek, odpowiedź HTTP ma kod stanu 500.

  • Jeśli błędy niestandardowe są wyłączone, to sieć usługa zwróci wyjątek wiadomość i stos trace do klienta jako JSON. Na przykład:
    {"Message":"Exception message","StackTrace":" at WebApplication.HelloService.HelloWorld() in C:\Projects\Stackoverflow Examples\WebApplication\WebApplication\HelloService.asmx.cs:line 22","ExceptionType":"System.ApplicationException"}

  • Gdy błędy niestandardowe są włączone następnie usługa internetowa zwraca domyślną wiadomość do klienta i usuwa stos Typ śledzenia i wyjątku:
    {"Message":"There was an error processing the request.","StackTrace":"","ExceptionType":""}

Więc to, co musimy zrobić, to ustawić niestandardowe błędy dla usługi internetowej i podłączyć moduł HTTP, który:

  1. sprawdza, czy żądanie dotyczy metody usługi internetowej
  2. sprawdza, czy wyjątek został wyrzucony-tzn. zwracany jest kod stanu 500
  3. Jeśli 1) i 2) są prawdziwe, to pobierz oryginalny JSON, który zostanie wysłany do klient i zastąp go domyślnym JSON

Poniższy kod jest przykładem modułu HTTP, który to robi:

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: Update with the correct check for your application
    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());

    // If customErrors are Off then originalContent will contain JSON with
    // the original exception message, stack trace and exception type.

    // TODO: log the exception
  }

  public void Dispose() { }
}

Ten moduł używa następującego filtra do nadpisania zawartości wysłanej do klienta i do przechowywania oryginalnych bajtów (które zawierają wiadomość o wyjątku, ślad stosu i typ wyjątku):

public class ErrorHandlerFilter : Stream {

  private readonly Stream _responseFilter;

  public List OriginalBytesWritten { get; private set; }

  private const string Content = 
    "{\"Message\":\"There was an error processing the request.\"" +
    ",\"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; }
  }
}

Ta metoda wymaga wyłączenia niestandardowych błędów dla usług internetowych. Prawdopodobnie chcesz zachować niestandardowe błędy na resztę aplikacji więc web services powinny być umieszczone w podkatalogu. Błędy niestandardowe można wyłączyć w tym katalogu tylko przy użyciu sieci web.config, który nadpisuje ustawienie nadrzędne.

 14
Author: Daniel Richardson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-04 11:31:26

Uruchamiasz procedurę składowaną w backendzie. Następnie dla pojedynczej zmiennej zwraca więcej niż 1 wartość. Z tego powodu dochodzi do konfliktu, a ten błąd zostaje wyrzucony.

 3
Author: Sameer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-14 13:50:59

Wiem, że to nie odpowiada na pytanie per-say, ale poszedłem na własne poszukiwania jakiś czas temu, aby dowiedzieć się o tym i chciałbym się z pustymi rękami. Skończyło się na zawijaniu każdego połączenia usługi internetowej w try / catch, a catch wywołuje nasz rejestrator błędów. Do bani, ale działa.

 1
Author: Nicholas Head,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-19 07:48:25

In ASP.Net możliwe jest przechwycenie wszystkich obsługiwanych WYJĄTKÓW za pomocą global Error handler chociaż post na blogu sugeruje, że to nie zadziała, ale możesz eksperymentować z tym podejściem próbując w jakiś sposób zmienić błąd?

Innym pomysłem byłoby spojrzenie na open source elmah (moduły rejestrujące błędy i manipulatory) dla ASP.Net to może pomóc lub ktoś z tej społeczności może mieć pomysł.

 -1
Author: John,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-24 10:05:51