Мені вдалося обійти цю проблему, використовуючи такі налаштування у веб-формах asp.net за допомогою .NET 3.5.
Шаблон, який я реалізував, обходить власне рішення перенаправлення .NET у web.config, оскільки я написав власний для обробки всіх сценаріїв правильний код стану HTTP у заголовку.
По-перше, розділ customErrors web.config виглядає так:
<customErrors mode="RemoteOnly" defaultRedirect="~/error.htm" />
Це налаштування гарантує, що для режиму CustomErrors увімкнено параметр, який нам знадобиться пізніше, і надає опцію "все-ще-невдачі" для defaultRedirect з error.htm. Це стане в нагоді, коли у мене немає обробника для конкретної помилки, або є щось на зразок зламаного з'єднання з базою даних.
По-друге, ось глобальна помилка asax Error:
protected void Application_Error(object sender, EventArgs e)
{
HandleError();
}
private void HandleError()
{
var exception = Server.GetLastError();
if (exception == null) return;
var baseException = exception.GetBaseException();
bool errorHandled = _applicationErrorHandler.HandleError(baseException);
if (!errorHandled) return;
var lastError = Server.GetLastError();
if (null != lastError && HttpContext.Current.IsCustomErrorEnabled)
{
Elmah.ErrorSignal.FromCurrentContext().Raise(lastError.GetBaseException());
Server.ClearError();
}
}
Цей код передає відповідальність за обробку помилки іншому класу. Якщо помилка не обробляється, а CustomErrors увімкнено, це означає, що ми маємо випадок, коли ми працюємо, і якось помилка не була оброблена. Ми очистимо його тут, щоб не дати користувачеві побачити його, але увійдіть в систему Elmah, щоб знати, що відбувається.
Клас applicationErrorHandler виглядає так:
public bool HandleError(Exception exception)
{
if (exception == null) return false;
var baseException = exception.GetBaseException();
Elmah.ErrorSignal.FromCurrentContext().Raise(baseException);
if (!HttpContext.Current.IsCustomErrorEnabled) return false;
try
{
var behavior = _responseBehaviorFactory.GetBehavior(exception);
if (behavior != null)
{
behavior.ExecuteRedirect();
return true;
}
}
catch (Exception ex)
{
Elmah.ErrorSignal.FromCurrentContext().Raise(ex);
}
return false;
}
Цей клас по суті використовує шаблон команди, щоб знайти відповідний обробник помилок для типу виданої помилки. Важливо використовувати Exception.GetBaseException () на цьому рівні, оскільки майже кожна помилка буде загорнута у виняток вищого рівня. Наприклад, якщо "кинути новий System.Exception ()" з будь-якої сторінки aspx, на цьому рівні буде отримано HttpUnhandledException, а не System.Exception.
"Заводський" код простий і виглядає так:
public ResponseBehaviorFactory()
{
_behaviors = new Dictionary<Type, Func<IResponseBehavior>>
{
{typeof(StoreException), () => new Found302StoreResponseBehavior()},
{typeof(HttpUnhandledException), () => new HttpExceptionResponseBehavior()},
{typeof(HttpException), () => new HttpExceptionResponseBehavior()},
{typeof(Exception), () => new Found302DefaultResponseBehavior()}
};
}
public IResponseBehavior GetBehavior(Exception exception)
{
if (exception == null) throw new ArgumentNullException("exception");
Func<IResponseBehavior> behavior;
bool tryGetValue = _behaviors.TryGetValue(exception.GetType(), out behavior);
if (!tryGetValue)
_behaviors.TryGetValue(typeof(Exception), out behavior);
if (behavior == null)
Elmah.ErrorSignal.FromCurrentContext().Raise(
new Exception(
"Danger! No Behavior defined for this Exception, therefore the user might have received a yellow screen of death!",
exception));
return behavior();
}
Врешті-решт, у мене є розширювана установка схеми обробки помилок. У кожному з визначених "поведінок" у мене є спеціальна реалізація для типу помилки. Наприклад, виняток Http буде перевірено на наявність коду стану та оброблено належним чином. Код стану 404 вимагатиме Server.Transfer замість Request.Redirect, а також відповідний код стану, записаний у заголовку.
Сподіваюся, це допомагає.