Вы можете использовать модуль HTTP для захвата сообщения об исключении, трассировки стека и типа исключения, создаваемого методом веб-службы.
Сначала немного фона ...
Если метод веб-службы выдает исключение, ответ HTTP имеет код состояния 500.
Если пользовательские ошибки отключены, то в Интернете
сервис вернет исключение
трассировка сообщения и стека клиенту
как JSON. Например:
{"Message":"Exception
message","StackTrace":" at
WebApplication.HelloService.HelloWorld()
in C:\Projects\Stackoverflow
Examples\WebApplication\WebApplication\HelloService.asmx.cs:line
22","ExceptionType":"System.ApplicationException"}
Когда пользовательские ошибки включены, то
веб-сервис возвращает сообщение по умолчанию
клиенту и удаляет стек
тип трассировки и исключения:
{"Message":"There was an error processing the request.","StackTrace":"","ExceptionType":""}
Итак, нам нужно отключить пользовательские ошибки для веб-службы и подключить модуль HTTP, который:
- Проверяет, относится ли запрос к методу веб-службы
- Проверяет, было ли создано исключение, то есть возвращается код состояния 500
- Если 1) и 2) имеют значение true, тогда получите исходный JSON, который будет отправлен клиенту, и замените его на JSON по умолчанию
Приведенный ниже код является примером модуля HTTP, который делает это:
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() { }
}
Этот модуль использует следующий фильтр для переопределения содержимого, отправляемого клиенту, и для хранения исходных байтов (которые содержат сообщение об исключении, трассировку стека и тип исключения):
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; }
}
}
Этот метод требует отключения пользовательских ошибок для веб-сервисов. Возможно, вы захотите сохранить пользовательские ошибки для остальной части приложения, поэтому веб-службы должны быть помещены в подкаталог. Пользовательские ошибки можно отключить в этом каталоге только с помощью файла web.config, который переопределяет родительский параметр.