我正在使用[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方法并尝试/捕获整个方法.
您可以使用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模块:
检查请求是否适用于Web服务方法
检查是否抛出异常 - 即返回状态代码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服务的自定义错误.您可能希望为应用程序的其余部分保留自定义错误,因此Web服务应放在子目录中.只能使用覆盖父设置的web.config在该目录中关闭自定义错误.