如Capture all unhandled exceptions automatically with WebService所述,确实没有好的解决方案。
您无法捕获HttpApplication.Error等的原因与Microsoft的好人如何实施RestHandler有关。具体来说,RestHandler明确捕获(句柄)异常并写出异常细节的响应:
internal static void ExecuteWebServiceCall(HttpContext context, WebServiceMethodData methodData)
{
try
{
NamedPermissionSet namedPermissionSet = HttpRuntime.NamedPermissionSet;
if (namedPermissionSet != null)
{
namedPermissionSet.PermitOnly();
}
IDictionary<string, object> rawParams = GetRawParams(methodData, context);
InvokeMethod(context, methodData, rawParams);
}
catch (Exception exception)
{
WriteExceptionJsonString(context, exception);
}
}
更糟糕的是,没有干净的扩展点(我能找到),您可以更改/延长行为。如果你想要写自己的IHttpHandler,我相信你几乎不得不重新实现RestHandler(或者RestHandlerWithSession)。无论Reflector会成为你的朋友。
对于那些可能选择。如果您正在使用Visual Studio 2008或更高版本来修改他们的WebMethods
,使用Lambda表达式使事情不是太糟糕了(虽然不是全球/通用的解决方案)的条款或删除复制码。
[WebMethod]
[ScriptMethod(UseHttpGet = true, ResponseFormat = ResponseFormat.Json)]
public String GetServerTime()
{
return Execute(() => DateTime.Now.ToString());
}
public T Execute<T>(Func<T> action)
{
if (action == null)
throw new ArgumentNullException("action");
try
{
return action.Invoke();
}
catch (Exception ex)
{
throw; // Do meaningful error handling/logging...
}
}
其中Execute可以在WebService的子类中实现或作为扩展方法实现。
UPDATE:反思危机
正如我在原始答复中提到,你可以滥用反射来得到你想要的......具体情况,你可以创建自己的HttpHandler,它利用了RestHandler的内部来提供捕获异常细节的拦截点。我在下面列出了一个“不安全”的代码示例,以帮助您入门。
就个人而言,我不会使用此代码;但它的工作原理。
namespace WebHackery
{
public class AjaxServiceHandler : IHttpHandler
{
private readonly Type _restHandlerType;
private readonly MethodInfo _createHandler;
private readonly MethodInfo _getRawParams;
private readonly MethodInfo _invokeMethod;
private readonly MethodInfo _writeExceptionJsonString;
private readonly FieldInfo _webServiceMethodData;
public AjaxServiceHandler()
{
_restHandlerType = typeof(ScriptMethodAttribute).Assembly.GetType("System.Web.Script.Services.RestHandler");
_createHandler = _restHandlerType.GetMethod("CreateHandler", BindingFlags.NonPublic | BindingFlags.Static, null, new[] { typeof(HttpContext) }, null);
_getRawParams = _restHandlerType.GetMethod("GetRawParams", BindingFlags.NonPublic | BindingFlags.Static);
_invokeMethod = _restHandlerType.GetMethod("InvokeMethod", BindingFlags.NonPublic | BindingFlags.Static);
_writeExceptionJsonString = _restHandlerType.GetMethod("WriteExceptionJsonString", BindingFlags.NonPublic | BindingFlags.Static, null, new[] { typeof(HttpContext), typeof(Exception) }, null);
_webServiceMethodData = _restHandlerType.GetField("_webServiceMethodData", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField);
}
public bool IsReusable
{
get { return true; }
}
public void ProcessRequest(HttpContext context)
{
var restHandler = _createHandler.Invoke(null, new Object[] { context });
var methodData = _webServiceMethodData.GetValue(restHandler);
var rawParams = _getRawParams.Invoke(null, new[] { methodData, context });
try
{
_invokeMethod.Invoke(null, new[] { context, methodData, rawParams });
}
catch (Exception ex)
{
while (ex is TargetInvocationException)
ex = ex.InnerException;
// Insert Custom Error Handling HERE...
_writeExceptionJsonString.Invoke(null, new Object[] { context, ex});
}
}
}
}
是否有任何灵活性您无法修改Web方法的要求? – 2011-11-11 16:57:34
嗯,是的 - 只要我不必在巨大的try/catch块中包围它们所有的东西。如果解决方案很干净,那么我对它开放。 – 2011-11-11 16:58:39
我有一个解决方案,它需要一个Try块和一行Catch。你或许可以改进它,完全消除try/catch,我还没有深入挖掘。要发布吗? – 2011-11-11 17:01:14