我正在使用[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方法并尝试/捕获整个方法。答案 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模块:
以下代码是执行此操作的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(错误记录模块和处理程序),或者该社区中的某个人可能有想法。