如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