从ASP.NET [ScriptService]服务全局记录异常

时间:2009-01-24 00:30:30

标签: asp.net asp.net-ajax error-handling

我正在使用[System.Web.Script.Services.ScriptService]标记来使用可从客户端javascript调用的Web服务。我需要的是一种全局记录这些方法中任何未处理的异常的方法。在客户端,我得到错误回调,可以从那里继续,但我需要一个服务器端catch来记录异常。

这个网址的人: http://ayende.com/Blog/archive/2008/01/06/ASP.Net-Ajax-Error-Handling-and-WTF.aspx

表示无法做到这一点。

这是准确的吗?我是否真的必须在整个系统中使用每一个web方法并尝试/捕获整个方法。

4 个答案:

答案 0 :(得分:15)

您可以使用HTTP模块捕获Web服务方法引发的异常消息,堆栈跟踪和异常类型。

首先是一些背景......

  • 如果Web服务方法抛出异常,则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"}

  • 当自定义错误打开时, Web服务返回默认消息 到客户端并删除堆栈 跟踪和例外类型:
    {"Message":"There was an error processing the request.","StackTrace":"","ExceptionType":""}

所以我们需要做的是为Web服务设置自定义错误并插入一个HTTP模块:

  1. 检查请求是否适用于Web服务方法
  2. 检查是否抛出异常 - 即返回状态代码
  3. 如果1)和2)为真,则获取将发送给客户端的原始JSON并将其替换为默认的JSON
  4. 以下代码是执行此操作的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服务的自定义错误。您可能希望为应用程序的其余部分保留自定义错误,因此Web服务应放在子目录中。只能使用覆盖父设置的web.config在该目录中关闭自定义错误。

答案 1 :(得分:3)

您在后端运行存储过程。然后,对于单个变量,它返回多于1个值。因此,发生冲突,并且抛出此错误。

答案 2 :(得分:1)

我知道这并没有回答每个人说的问题,但是我继续自己的追求一段时间才发现这个并且空手而归。结束在try / catch中包装每个Web服务调用,catch调用我们的错误记录器。糟透了,但它确实有效。

答案 3 :(得分:-1)

在ASP.Net中,可以使用global error handler捕获所有运行处理的异常,尽管博客文章建议这不起作用,但您可以尝试使用这种方法尝试以某种方式重新抛出错误吗?

另一个想法是查看可能有帮助的ASP.Net的开源elmah(错误记录模块和处理程序),或者该社区中的某个人可能有想法。