Car*_*000 16 asp.net ajax error-handling webmethod
我们有一个较旧的ASP.NET WebForms应用程序,它通过$.ajax()
在客户端使用jQuery 调用来执行AJAX请求,在使用[WebMethod]
属性修饰的页面代码隐藏中调用静态方法.
如果在WebMethod中发生未处理的异常,则它不会触发Application_Error
事件,因此我们的错误记录器(ELMAH)不会将其捕获.这是众所周知的而不是问题 - 我们将所有WebMethod代码包装在try-catch块中,并将异常手动记录到ELMAH.
但是,有一个案例令我难过.如果格式错误的Json发布到WebMethod URL,它会在输入我们的代码之前抛出异常,我找不到任何方法来捕获它.
例如,这个WebMethod签名
[WebMethod]
public static string LeWebMethod(string stringParam, int intParam)
Run Code Online (Sandbox Code Playgroud)
通常使用Json有效负载调用,如:
{"stringParam":"oh hai","intParam":37}
Run Code Online (Sandbox Code Playgroud)
我尝试使用Fiddler进行测试,将有效负载编辑为格式错误的Json:
{"stringParam":"oh hai","intPara
Run Code Online (Sandbox Code Playgroud)
并ArgumentException
从JavaScriptObjectDeserializer
发送到客户端获得以下错误响应(这是在本地运行的简单测试应用程序,没有自定义错误):
{"Message":"Unterminated string passed in. (32): {\"stringParam\":\"oh hai\",\"intPara","StackTrace":" at
System.Web.Script.Serialization.JavaScriptObjectDeserializer.DeserializeString()\r\n at
System.Web.Script.Serialization.JavaScriptObjectDeserializer.DeserializeMemberName()\r\n at
System.Web.Script.Serialization.JavaScriptObjectDeserializer.DeserializeDictionary(Int32 depth)\r\n at
System.Web.Script.Serialization.JavaScriptObjectDeserializer.DeserializeInternal(Int32 depth)\r\n at
System.Web.Script.Serialization.JavaScriptObjectDeserializer.BasicDeserialize(String input, Int32 depthLimit, JavaScriptSerializer serializer)\r\n at
System.Web.Script.Serialization.JavaScriptSerializer.Deserialize(JavaScriptSerializer serializer, String input, Type type, Int32 depthLimit)\r\n at
System.Web.Script.Serialization.JavaScriptSerializer.Deserialize[T](String input)\r\n at
System.Web.Script.Services.RestHandler.GetRawParamsFromPostRequest(HttpContext context, JavaScriptSerializer serializer)\r\n at
System.Web.Script.Services.RestHandler.GetRawParams(WebServiceMethodData methodData, HttpContext context)\r\n at
System.Web.Script.Services.RestHandler.ExecuteWebServiceCall(HttpContext context, WebServiceMethodData methodData)","ExceptionType":"System.ArgumentException"}
Run Code Online (Sandbox Code Playgroud)
它仍然没有触发Application_Error
事件,它从不输入我们的代码,所以我们不能自己记录错误.
我发现了一个类似的问题,它指向博客文章" 如何为Web服务创建全局异常处理程序 ",但这似乎只对SOAP Web服务有效,而不是对AJAX GET/POST有效.
在我的情况下是否有一些类似的方法来附加自定义处理程序?
Mic*_*Liu 21
根据引用源,内部RestHandler.ExecuteWebServiceCall
方法捕获所引发的所有异常,GetRawParams
并将它们简单地写入响应流,这就是为什么Application_Error
不调用它:
internal static void ExecuteWebServiceCall(HttpContext context, WebServiceMethodData methodData) {
try {
...
IDictionary<string, object> rawParams = GetRawParams(methodData, context);
InvokeMethod(context, methodData, rawParams);
}
catch (Exception ex) {
WriteExceptionJsonString(context, ex);
}
}
Run Code Online (Sandbox Code Playgroud)
我能想到的唯一解决方法是创建一个截取并记录输出的输出过滤器:
public class PageMethodExceptionLogger : Stream
{
private readonly HttpResponse _response;
private readonly Stream _baseStream;
private readonly MemoryStream _capturedStream = new MemoryStream();
public PageMethodExceptionLogger(HttpResponse response)
{
_response = response;
_baseStream = response.Filter;
}
public override void Close()
{
if (_response.StatusCode == 500 && _response.Headers["jsonerror"] == "true")
{
_capturedStream.Position = 0;
string responseJson = new StreamReader(_capturedStream).ReadToEnd();
// TODO: Do the actual logging.
}
_baseStream.Close();
base.Close();
}
public override void Flush()
{
_baseStream.Flush();
}
public override long Seek(long offset, SeekOrigin origin)
{
return _baseStream.Seek(offset, origin);
}
public override void SetLength(long value)
{
_baseStream.SetLength(value);
}
public override int Read(byte[] buffer, int offset, int count)
{
return _baseStream.Read(buffer, offset, count);
}
public override void Write(byte[] buffer, int offset, int count)
{
_baseStream.Write(buffer, offset, count);
_capturedStream.Write(buffer, offset, count);
}
public override bool CanRead { get { return _baseStream.CanRead; } }
public override bool CanSeek { get { return _baseStream.CanSeek; } }
public override bool CanWrite { get { return _baseStream.CanWrite; } }
public override long Length { get { return _baseStream.Length; } }
public override long Position
{
get { return _baseStream.Position; }
set { _baseStream.Position = value; }
}
}
Run Code Online (Sandbox Code Playgroud)
在Global.asax.cs(或HTTP模块)中,将过滤器安装在Application_PostMapRequestHandler
:
protected void Application_PostMapRequestHandler(object sender, EventArgs e)
{
HttpContext context = HttpContext.Current;
if (context.Handler is Page && !string.IsNullOrEmpty(context.Request.PathInfo))
{
string contentType = context.Request.ContentType.Split(';')[0];
if (contentType.Equals("application/json", StringComparison.OrdinalIgnoreCase))
{
context.Response.Filter = new PageMethodExceptionLogger(context.Response);
}
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
5286 次 |
最近记录: |