asp.net-mvc-3 - net - web config error handlers
¿Cómo puedo visualizar páginas de error personalizadas en Asp.Net Mvc 3? (4)
Quiero que todos los errores 401 sean redirigidos a una página de error personalizada. Inicialmente configuré la siguiente entrada en mi web.config.
<customErrors defaultRedirect="ErrorPage.aspx" mode="On">
<error statusCode="401" redirect="~/Views/Shared/AccessDenied.aspx" />
</customErrors>
Cuando utilizo IIS Express, recibo la página de error stock IIS Express 401.
En el caso de que no use IIS Express, se devuelve una página en blanco. Utilizando la pestaña de red de Google Chrome para inspeccionar la respuesta, veo que mientras la página está en blanco, se devuelve un estado 401 en los encabezados
Lo que he intentado hasta ahora es utilizar las sugerencias de esta respuesta SO ya que estoy usando IIS Express pero fue en vano. Intenté usar una combinación de <custom errors>
y <httpErrors>
sin suerte: el error estándar o la página en blanco aún se muestran.
La sección httpErrors
se parece a esto en este momento, basada en el enlace de la pregunta SO más arriba (también encontré otra respuesta muy prometedora, pero sin suerte, respuesta en blanco)
<system.webServer>
<httpErrors errorMode="DetailedLocalOnly" existingResponse="PassThrough" >
<remove statusCode="401" />
<error statusCode="401" path="/Views/Shared/AccessDenied.htm" />
</httpErrors>
<!--
<httpErrors errorMode="Custom"
existingResponse="PassThrough"
defaultResponseMode="ExecuteURL">
<remove statusCode="401" />
<error statusCode="401" path="~/Views/Shared/AccessDenied.htm"
responseMode="File" />
</httpErrors>
-->
</system.webServer>
Incluso he modificado el archivo applicationhost.config
y modificado <httpErrors lockAttributes="allowAbsolutePathsWhenDelegated,defaultPath">
a <httpErrors lockAttributes="allowAbsolutePathsWhenDelegated">
función de la información de iis.net . Durante el curso de mis esfuerzos también logré encontrar este error como se describe en otra pregunta de SO .
¿Cómo puedo visualizar páginas de error personalizadas en Asp.Net Mvc 3?
información adicional
Las siguientes acciones del controlador se han decorado con el atributo Authorise
para un usuario específico.
[HttpGet]
[Authorize(Users = "domain//userXYZ")]
public ActionResult Edit()
{
return GetSettings();
}
[HttpPost]
[Authorize(Users = "domain//userXYZ")]
public ActionResult Edit(ConfigurationModel model, IList<Shift> shifts)
{
var temp = model;
model.ConfiguredShifts = shifts;
EsgConsole config = new EsgConsole();
config.UpdateConfiguration(model.ToDictionary());
return RedirectToAction("Index");
}
Nunca pude obtener CustomErrors en un web.config y MVC para jugar bien juntos, así que me di por vencido. Yo hago esto en su lugar.
En global.asax:
protected void Application_Error()
{
var exception = Server.GetLastError();
var httpException = exception as HttpException;
Response.Clear();
Server.ClearError();
var routeData = new RouteData();
routeData.Values["controller"] = "Errors";
routeData.Values["action"] = "General";
routeData.Values["exception"] = exception;
Response.StatusCode = 500;
if (httpException != null)
{
Response.StatusCode = httpException.GetHttpCode();
switch (Response.StatusCode)
{
case 403:
routeData.Values["action"] = "Http403";
break;
case 404:
routeData.Values["action"] = "Http404";
break;
}
}
// Avoid IIS7 getting in the middle
Response.TrySkipIisCustomErrors = true;
IController errorsController = new GNB.LG.StrategicPlanning.Website.Controllers.ErrorsController();
HttpContextWrapper wrapper = new HttpContextWrapper(Context);
var rc = new RequestContext(wrapper, routeData);
errorsController.Execute(rc);
}
En ErrorsController:
public class ErrorsController
{
public ActionResult General(Exception exception)
{
// log the error here
return View(exception);
}
public ActionResult Http404()
{
return View("404");
}
public ActionResult Http403()
{
return View("403");
}
}
En web.config:
<customErrors mode="Off" />
Eso funcionó para mí sin importar dónde o cómo se creó el error. 401 no se maneja en este momento, pero podría agregarlo con bastante facilidad.
Si observa la primera parte de su web.config allí, apunta directamente a una página .aspx. Cuando configuré mis páginas de error, señalé directamente un controlador y una acción. Por ejemplo:
<customErrors mode="On" defaultRedirect="~/Error/UhOh">
<error statusCode="404" redirect="~/Error/NotFound" />
<error statusCode="403" redirect="~/Error/AccessDenied" />
</customErrors>
Y tenía un controlador de error con todas las acciones requeridas. No creo que MVC funcione bien con llamadas directas a páginas .aspx.
Tal vez me falta algo, pero MVC tiene un ErrorHandlerAttribute
global predeterminado que usa errores personalizados. Esto se explica bastante bien here .
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
Todo lo que necesita hacer es activar custom errors
en la configuración y luego configurar los redireccionamientos de errores personalizados, preferiblemente en un archivo HTML
estático (en caso de que haya errores con la aplicación).
<customErrors mode="On" defaultRedirect="errors.htm">
<error statusCode="404" redirect="errors404.htm"/>
</customErrors>
Si lo prefiere, también podría apuntar a un Controller
personalizado para mostrar los errores. En el siguiente ejemplo, acabo de utilizar el enrutamiento predeterminado en un Controller
llamado Error
, con una acción llamada Index
y un parámetro de cadena llamado id
(para recibir el código de error). Por supuesto, puede utilizar cualquier ruta que desee. Su ejemplo no funciona porque está tratando de vincular directamente en el directorio de Views
sin pasar por un Controller
. MVC .NET no atiende solicitudes directamente a la carpeta Views
.
<customErrors mode="On" defaultRedirect="/error/index/500">
<error statusCode="404" redirect="/error/index/404"/>
</customErrors>
El ErrorHandlerAttribute también se puede usar ampliamente con Controllers/Actions
para redirigir los errores a las Views
nombradas relacionadas con el Controller
. Por ejemplo, para mostrar la View
llamada MyArgumentError
cuando se MyArgumentError
una excepción de tipo ArgumentException
, puede usar:
[ControllerAction,ExceptionHandler("MyArgumentError",typeof(ArgumentException))]
public void Index()
{
// some code that could throw ArgumentExcepton
}
Por supuesto, otra opción es actualizar la página stock Error
en Shared
.
Yo uso estos pasos:
// in Global.asax.cs:
protected void Application_Error(object sender, EventArgs e) {
var ex = Server.GetLastError().GetBaseException();
Server.ClearError();
var routeData = new RouteData();
routeData.Values.Add("controller", "Error");
routeData.Values.Add("action", "Index");
if (ex.GetType() == typeof(HttpException)) {
var httpException = (HttpException)ex;
var code = httpException.GetHttpCode();
routeData.Values.Add("status", code);
} else {
routeData.Values.Add("status", 500);
}
routeData.Values.Add("error", ex);
IController errorController = new Kavand.Web.Controllers.ErrorController();
errorController.Execute(new RequestContext(new HttpContextWrapper(Context), routeData));
}
protected void Application_EndRequest(object sender, EventArgs e) {
if (Context.Response.StatusCode == 401) { // this is important, because the 401 is not an error by default!!!
throw new HttpException(401, "You are not authorised");
}
}
Y:
// in Error Controller:
public class ErrorController : Controller {
public ActionResult Index(int status, Exception error) {
Response.StatusCode = status;
return View(status);
}
protected override void Dispose(bool disposing) {
base.Dispose(disposing);
}
}
Y la vista de índice en la carpeta Error:
@* in ~/Views/Error/Index.cshtml: *@
@model Int32
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<title>Kavand | Error</title>
</head>
<body>
<div>
There was an error with your request. The error is:<br />
<p style=" color: Red;">
@switch (Model) {
case 401: {
<span>Your message goes here...</span>
}
break;
case 403: {
<span>Your message goes here...</span>
}
break;
case 404: {
<span>Your message goes here...</span>
}
break;
case 500: {
<span>Your message goes here...</span>
}
break;
//and more cases for more error-codes...
default: {
<span>Unknown error!!!</span>
}
break;
}
</p>
</div>
</body>
</html>
Y, el último paso:
<!-- in web.config: -->
<customErrors mode="Off"/>