Как описано в Автоматический захват всех необработанных исключений с помощью WebService , действительно хорошего решения не существует.
Причина, по которой вы не можете перехватить HttpApplication.Error и т. Д., Связана с тем, как RestHandler был реализован хорошими людьми из Microsoft. В частности, 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); Отражатель будет твоим другом.
Для тех, кто может изменить свои WebMethods
Если вы используете Visual Studio 2008 или более позднюю версию, использование лямбда-выражений делает вещи не слишком плохими (хотя и не глобальными / универсальными) в терминах или удалении дублирующегося кода.
[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 или как метод расширения.
ОБНОВЛЕНИЕ: Отражение зла
Как уже упоминалось в моем первоначальном ответе, вы можете злоупотреблять рефлексией, чтобы получить то, что вы хотите ... в частности, вы можете создать свой собственный 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});
}
}
}
}