代码之家  ›  专栏  ›  技术社区  ›  Clyde

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

  •  13
  • Clyde  · 技术社区  · 17 年前

    我正在使用[system.web.script.services.scriptservice]标记来使用可从客户端javascript调用的Web服务。我需要的是全局记录这些方法中任何未处理的异常的方法。在客户机端,我得到了错误回调并可以从那里继续,但是我需要一个服务器端捕获来记录异常。

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

    暗示这是不可能的。

    那是准确的吗?我真的必须去整个系统中的每个单独的webmethod并尝试/捕获整个方法吗?

    4 回复  |  直到 13 年前
        1
  •  15
  •   Loki Kriasus    15 年前

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

    首先是一些背景…

    • 如果Web服务方法引发异常,则HTTP响应的状态代码为500。

    • 如果关闭自定义错误,则Web 服务将返回异常 到客户端的消息和堆栈跟踪 作为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. 检查是否引发异常-即返回状态代码500
    3. 如果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服务的自定义错误。您可能希望为应用程序的其余部分保留自定义错误,以便将Web服务放在子目录中。只能使用覆盖父设置的web.config关闭该目录中的自定义错误。

        2
  •  3
  •   WEFX venkateswararao    13 年前

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

        3
  •  1
  •   Nicholas Head    17 年前

    我知道这并不能回答每个人的问题,但我自己找了一段时间才发现这个问题,结果空手而归。最后将每个Web服务调用包装在一个try/catch中,catch调用我们的错误记录器。糟透了,但它起作用了。

        4
  •  -1
  •   John    17 年前

    在ASP.NET中,可以使用 global error handler 尽管博客文章建议这样做不起作用,但是你可以尝试用这种方法尝试以某种方式重新引发错误?

    另一个想法是研究开放源码 elmah (错误记录模块和处理程序)对于可能有帮助的ASP.NET或该社区中的某个人可能有想法。

    推荐文章