Comme décrit dans Capture all unhandled exceptions automatically with WebService il n'y a vraiment pas de bonne solution.
La raison pour laquelle vous ne pouvez pas capturer le HttpApplication.Error etc a à voir avec la façon dont le RestHandler a été implémenté par les bonnes personnes chez Microsoft. Plus précisément, le RestHandler attire explicitement (poignées) l'exception et écrit les détails de l'exception à la réponse:
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);
}
}
Pour aggraver les choses, il n'y a pas de point d'extension propre (que je pourrais trouver) où vous pouvez modifier/étendre le comportement. Si vous voulez suivre le chemin de l'écriture de votre propre IHttpHandler, je crois que vous aurez à ré-implémenter le RestHandler (ou RestHandlerWithSession); quel que soit Reflector sera votre ami.
Pour ceux qui peuvent choisir de modifier leurs WebMethods
Si vous utilisez Visual Studio 2008 ou plus tard, en utilisant des expressions Lambda rend les choses pas trop mal (mais pas solution globale/générique) en termes ou suppression d'dupliqués code.
[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...
}
}
Où Execute peut être implémenté dans une sous-classe de WebService ou en tant que méthode d'extension.
MISE À JOUR: Réflexion mal
Comme mentionné dans ma réponse d'origine, vous pouvez abuser de réflexion pour obtenir ce que vous voulez ... vous pouvez spécifiquement créer votre propre HttpHandler qui utilise des composants internes du RestHandler à fournir un point d'interception pour capturer les détails de l'exception. J'ai inclus un exemple de code «dangereux» ci-dessous pour vous aider à démarrer.
Personnellement, je n'utiliserais PAS ce code; mais ça marche.
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});
}
}
}
}
est-il une certaine flexibilité dans l'exigence que vous ne pouvez pas modifier les méthodes Web? –
Eh bien, oui - tant que je n'ai pas à les entourer tous de blocs d'essai géants/catch .. Si la solution est propre, alors je suis ouvert à cela. –
J'ai une solution qui nécessite un bloc Try et une seule ligne Catch. Vous pourriez être en mesure de l'améliorer pour faire disparaître complètement le try/catch, je n'ai pas creusé aussi profondément. Voulez-vous posté? –