Sie können ein HTTP-Modul verwenden, um die Ausnahmemeldung, den Stapelüberlauf und den Ausnahmetyp zu erfassen, der von der Webdienstmethode ausgelöst wird.
Zuerst etwas Hintergrundinformationen...
-
Wenn eine Webdienstmethode eine Ausnahme auslöst, hat die HTTP-Antwortstatuscode 500.
-
Wenn benutzerdefinierte Fehler deaktiviert sind, gibt der Webdienst die Ausnahmemeldung und den Stapelüberlauf als JSON an den Client zurück. Zum Beispiel:
{"Message":"Ausnahmemeldung","StackTrace":" at WebApplication.HelloService.HelloWorld() in C:\Projects\Stackoverflow Examples\WebApplication\WebApplication\HelloService.asmx.cs:line 22","ExceptionType":"System.ApplicationException"}
-
Wenn benutzerdefinierte Fehler aktiviert sind, gibt der Webdienst eine Standardmeldung an den Client zurück und entfernt den Stapelüberlauf und den Ausnahmetyp:
{"Message":"Bei der Verarbeitung der Anfrage ist ein Fehler aufgetreten.","StackTrace":"","ExceptionType":""}
Also müssen wir benutzerdefinierte Fehler für den Webdienst deaktivieren und ein HTTP-Modul einfügen, das folgendes macht:
- Überprüfen, ob die Anfrage für eine Webdienstmethode ist
- Überprüfen, ob eine Ausnahme ausgelöst wurde - das heißt, ein Statuscode von 500 wird zurückgegeben
- Wenn 1) und 2) zutreffen, dann das ursprüngliche JSON abrufen, das an den Client gesendet werden würde, und es durch das Standard-JSON ersetzen
Der folgende Code ist ein Beispiel für ein HTTP-Modul, das dies tut:
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: Aktualisieren Sie mit der richtigen Überprüfung für Ihre Anwendung
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());
// Wenn customErrors deaktiviert sind, enthält originalContent JSON mit
// der ursprünglichen Ausnahmemeldung, dem Stapelüberlauf und dem Ausnahmetyp.
// TODO: Ausnahme protokollieren
}
public void Dispose() { }
}
Dieses Modul verwendet den folgenden Filter, um den Inhalt zu überschreiben, der an den Client gesendet wird, und um die ursprünglichen Bytes (die die Ausnahmemeldung, den Stapelüberlauf und den Ausnahmetyp enthalten) zu speichern:
public class ErrorHandlerFilter : Stream {
private readonly Stream _responseFilter;
public List OriginalBytesWritten { get; private set; }
private const string Content =
"{\"Message\":\"Bei der Verarbeitung der Anfrage ist ein Fehler aufgetreten.\" + \",\"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; }
}
}
Diese Methode erfordert, dass benutzerdefinierte Fehler für die Webdienste deaktiviert sind. Wahrscheinlich möchten Sie benutzerdefinierte Fehler für den Rest der Anwendung eingeschaltet lassen, sodass die Webdienste in einem Unterverzeichnis platziert sein sollten. Benutzerdefinierte Fehler können in diesem Verzeichnis nur durch eine web.config deaktiviert werden, die die übergeordnete Einstellung außer Kraft setzt.