Глобальные исключения журналов из служб ASP.NET [ScriptService]

Я использую тег [System.Web.Script.Services.ScriptService] для использования веб-сервисов, вызываемых с javascript на стороне клиента. Мне нужен способ глобального регистрации любых необработанных исключений в этих методах. На стороне клиента я получаю обратный вызов ошибки и могу исходить оттуда, но мне нужен захват на стороне сервера для регистрации исключения.

Парень по этому URL: http://ayende.com/Blog/archive/2008/01/06/ASP.Net-Ajax-Error-Handling-and-WTF.aspx

предполагает, что это невозможно.

Это точно? Должен ли я серьезно перейти к каждому веб-методу во всей системе и попробовать/поймать метод в целом.

Ответ 1

Вы можете использовать HTTP-модуль для захвата сообщения об исключении, трассировки стека и типа исключения, которые вызывается методом веб-службы.

Сначала немного фона...

  • Если метод веб-службы генерирует исключение, HTTP-ответ имеет код состояния 500.

  • Если пользовательские ошибки отключены, веб-сайт служба вернет исключение сообщение и трассировка стека клиенту как JSON. Например:
    {"Message":"Exception message","StackTrace":" at WebApplication.HelloService.HelloWorld() in C:\Projects\Stackoverflow Examples\WebApplication\WebApplication\HelloService.asmx.cs:line 22","ExceptionType":"System.ApplicationException"}

  • Когда пользовательские ошибки включены, веб-служба возвращает сообщение по умолчанию клиенту и удаляет стек Тип следа и исключения:
    {"Message":"There was an error processing the request.","StackTrace":"","ExceptionType":""}

Итак, нам нужно установить пользовательские ошибки для веб-службы и подключить модуль HTTP, который:

  • Проверяет, является ли запрос для метода веб-службы
  • Проверяет, было ли исключено исключение - то есть возвращается код состояния 500.
  • Если 1) и 2) истинны, тогда получите исходный JSON, который будет отправлен клиенту, и замените его стандартным JSON

Ниже приведен пример HTTP-модуля, который делает это:

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() { }
}

Этот модуль использует следующий фильтр, чтобы переопределить содержимое, отправленное клиенту, и сохранить исходные байты (содержащие сообщение об исключении, трассировку стека и тип исключения):

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; }
  }
}

Этот метод требует, чтобы пользовательские ошибки были отключены для веб-служб. Вероятно, вы захотите сохранить пользовательские ошибки для остальной части приложения, чтобы веб-службы были размещены в подкаталоге. Пользовательские ошибки могут быть отключены в этом каталоге только с помощью файла web.config, который переопределяет родительский параметр.

Ответ 2

Вы запускаете хранимую процедуру в бэкэнд. Затем для одной переменной возвращается более 1 значения. Из-за этого возникают конфликты, и эта ошибка возникает.

Ответ 3

Я знаю, что это не отвечает на вопрос, скажем, но я снова отправился в свой собственный квест, чтобы узнать это и спустил бы с пустыми руками. Закончилось завершение каждого вызова веб-службы в try/catch, и catch вызывает наш регистратор ошибок. Отстой, но он работает.

Ответ 4

В ASP.Net можно поймать все запущенные обработанные исключения с помощью глобального обработчика ошибок, хотя сообщение в блоге предполагает, что это не сработает но вы могли бы экспериментировать с этим подходом, пытаясь каким-то образом переустановить ошибку?

Еще одна идея - посмотреть на открытый источник elmah (модули регистрации ошибок и обработчики) для ASP.Net, которые могут помочь или кто-то из этого сообщества может иметь идею.