Vous pouvez utiliser un module HTTP pour capturer le message d'exception, la trace de la pile et le type d'exception généré par la méthode de service Web.
Tout d'abord quelques arrière-plan ...
Si une méthode de service Web génère une exception la réponse HTTP a un code d'état de 500.
Si les erreurs personnalisées sont désactivées alors le service web renvoie le message d'exception et trace la pile au client en tant que JSON.Par exemple:
{"Message":"Exception message","StackTrace":" at WebApplication.HelloService.HelloWorld() in C:\Projects\Stackoverflow Examples\WebApplication\WebApplication\HelloService.asmx.cs:line 22","ExceptionType":"System.ApplicationException"}
Lorsque des erreurs personnalisées sont allumées, le service Web renvoie un message par défaut au client et supprime la pile trace et le type exception:
{"Message":"There was an error processing the request.","StackTrace":"","ExceptionType":""}
Alors ce que nous besoin de faire est de mettre des erreurs personnalisées hors service pour le service Web et branchez un module HTTP qui:
- C Hecks si la demande est une méthode de service Web
- Vérifie si une exception a été levée - à savoir, un code d'état de 500 est retourné
- Si 1) et 2) sont vraies alors obtenir le JSON original qui serait envoyé au client et le remplacer par la valeur par défaut JSON
le code suivant est un exemple d'un module HTTP qui fait cela:
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Web;
public class ErrorHandlerModule : IHttpModule {
public void Init(HttpApplication context) {
context.PostRequestHandlerExecute += OnPostRequestHandlerExecute;
context.EndRequest += OnEndRequest;
}
static void OnPostRequestHandlerExecute(object sender, EventArgs e) {
HttpApplication context = (HttpApplication) sender;
// TODO: Update with the correct check for your application
if (context.Request.Path.StartsWith("/HelloService.asmx")
&& context.Response.StatusCode == 500) {
context.Response.Filter =
new ErrorHandlerFilter(context.Response.Filter);
context.EndRequest += OnEndRequest;
}
}
static void OnEndRequest(object sender, EventArgs e) {
HttpApplication context = (HttpApplication) sender;
ErrorHandlerFilter errorHandlerFilter =
context.Response.Filter as ErrorHandlerFilter;
if (errorHandlerFilter == null) {
return;
}
string originalContent =
Encoding.UTF8.GetString(
errorHandlerFilter.OriginalBytesWritten.ToArray());
// If customErrors are Off then originalContent will contain JSON with
// the original exception message, stack trace and exception type.
// TODO: log the exception
}
public void Dispose() { }
}
ce module utilise le filtre suivant pour remplacer le contenu envoyé à le client et de stocker les octets d'origine (qui n le message d'exception, la trace de pile et le type d'exception):
public class ErrorHandlerFilter : Stream {
private readonly Stream _responseFilter;
public List OriginalBytesWritten { get; private set; }
private const string Content =
"{\"Message\":\"There was an error processing the request.\"" +
",\"StackTrace\":\"\",\"ExceptionType\":\"\"}";
public ErrorHandlerFilter(Stream responseFilter) {
_responseFilter = responseFilter;
OriginalBytesWritten = new List();
}
public override void Flush() {
byte[] bytes = Encoding.UTF8.GetBytes(Content);
_responseFilter.Write(bytes, 0, bytes.Length);
_responseFilter.Flush();
}
public override long Seek(long offset, SeekOrigin origin) {
return _responseFilter.Seek(offset, origin);
}
public override void SetLength(long value) {
_responseFilter.SetLength(value);
}
public override int Read(byte[] buffer, int offset, int count) {
return _responseFilter.Read(buffer, offset, count);
}
public override void Write(byte[] buffer, int offset, int count) {
for (int i = offset; i < offset + count; i++) {
OriginalBytesWritten.Add(buffer[i]);
}
}
public override bool CanRead {
get { return _responseFilter.CanRead; }
}
public override bool CanSeek {
get { return _responseFilter.CanSeek; }
}
public override bool CanWrite {
get { return _responseFilter.CanWrite; }
}
public override long Length {
get { return _responseFilter.Length; }
}
public override long Position {
get { return _responseFilter.Position; }
set { _responseFilter.Position = value; }
}
}
Cette méthode nécessite la désactivation des erreurs personnalisées pour les services Web. Vous souhaiterez probablement conserver des erreurs personnalisées pour le reste de l'application afin que les services Web soient placés dans un sous-répertoire. Les erreurs personnalisées peuvent être désactivées dans ce répertoire uniquement à l'aide d'un fichier web.config qui remplace le paramètre parent.
Bien que je ne m'occupe pas de cela sur mon projet actuel, c'est probablement le seul moyen de détecter de manière fiable toutes ces erreurs. – Clyde
J'ai essayé celui-ci, mais en quelque sorte mon contexte.Response.Filter.length a lancé une exception de type 'System.NotSupportedException'. Ça ne marche tout simplement pas. Je pense que c'est très proche, ma sortie est exactement comme tu l'as dit. et j'ai reçu 500 codes d'état. – maxisam