Pude solucionar este problema usando la siguiente configuración en formularios web asp.net usando .NET 3.5.
El patrón que implementé omite la solución de redireccionamiento personalizado de .NET en web.config, ya que escribí el mío para manejar todos los escenarios con el código de estado HTTP correcto en el encabezado.
Primero, la sección customErrors de web.config se ve así:
<customErrors mode="RemoteOnly" defaultRedirect="~/error.htm" />
Esta configuración garantiza que el modo CustomErrors esté activado, una configuración que necesitaremos más adelante, y proporciona una opción de error de todo lo demás para el defaultRedirect de error.htm. Esto será útil cuando no tenga un controlador para el error específico o si hay algo parecido a una conexión de base de datos rota.
En segundo lugar, aquí está el evento de error global asax:
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();
}
}
Este código transfiere la responsabilidad de manejar el error a otra clase. Si el error no se maneja y CustomErrors está activado, eso significa que tenemos un caso en el que estamos en producción y de alguna manera no se ha manejado un error. Lo borraremos aquí para evitar que el usuario lo vea, pero inicie sesión en Elmah para que sepamos qué está pasando.
La clase applicationErrorHandler se ve así:
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;
}
Esta clase esencialmente usa el patrón de comando para ubicar el controlador de errores apropiado para el tipo de error que se emite. Es importante usar Exception.GetBaseException () en este nivel, porque casi todos los errores se incluirán en una excepción de nivel superior. Por ejemplo, si hace "lanzar una nueva System.Exception ()" desde cualquier página aspx, se recibirá una HttpUnhandledException en este nivel, no una System.Exception.
El código de "fábrica" es simple y tiene este aspecto:
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();
}
Al final, tengo una configuración de esquema de manejo de errores extensible. En cada uno de los "comportamientos" que se definen, tengo una implementación personalizada para el tipo de error. Por ejemplo, se inspeccionará una excepción Http para el código de estado y se manejará adecuadamente. Un código de estado 404 requerirá un Server.Transfer en lugar de un Request.Redirect, junto con el código de estado apropiado escrito en el encabezado.
Espero que esto ayude.