asp.net - tutorial - web forms c#
¿Cómo devolver una vista para HttpNotFound() en ASP.Net MVC 3? (6)
¿Hay alguna forma de devolver la misma vista cada vez que se devuelve un HttpNotFoundResult desde un controlador? ¿Cómo se especifica esta vista? Supongo que configurar una página 404 en la web.config podría funcionar, pero quería saber si había una forma mejor de manejar este resultado.
Editar / Seguimiento:
Terminé usando la solución que se encuentra en la segunda respuesta a esta pregunta con algunas ligeras modificaciones para que ASP.Net MVC 3 maneje mis 404: ¿Cómo puedo manejar adecuadamente 404s en ASP.Net MVC?
Aquí hay una respuesta verdadera que permite personalizar completamente la página de error en un solo lugar. No es necesario modificar web.confiog o crear clases sofisticadas y código. Funciona también en MVC 5.
Agregue este código al controlador:
if (bad) {
Response.Clear();
Response.TrySkipIisCustomErrors = true;
Response.Write(product + I(" Toodet pole"));
Response.StatusCode = (int)HttpStatusCode.NotFound;
//Response.ContentType = "text/html; charset=utf-8";
Response.End();
return null;
}
Basado en http://www.eidias.com/blog/2014/7/2/mvc-custom-error-pages
Esta solución combina IResultFilter e IExceptionFilter para capturar HttpException lanzada o devolver HttpStatusCodeResult desde dentro de una acción.
public class CustomViewForHttpStatusResultFilter: IResultFilter, IExceptionFilter
{
string viewName;
int statusCode;
public CustomViewForHttpStatusResultFilter(HttpStatusCodeResult prototype, string viewName)
: this(prototype.StatusCode, viewName) {
}
public CustomViewForHttpStatusResultFilter(int statusCode, string viewName) {
this.viewName = viewName;
this.statusCode = statusCode;
}
public void OnResultExecuted(ResultExecutedContext filterContext) {
HttpStatusCodeResult httpStatusCodeResult = filterContext.Result as HttpStatusCodeResult;
if (httpStatusCodeResult != null && httpStatusCodeResult.StatusCode == statusCode) {
ExecuteCustomViewResult(filterContext.Controller.ControllerContext);
}
}
public void OnResultExecuting(ResultExecutingContext filterContext) {
}
public void OnException(ExceptionContext filterContext) {
HttpException httpException = filterContext.Exception as HttpException;
if (httpException != null && httpException.GetHttpCode() == statusCode) {
ExecuteCustomViewResult(filterContext.Controller.ControllerContext);
// This causes ELMAH not to log exceptions, so commented out
//filterContext.ExceptionHandled = true;
}
}
void ExecuteCustomViewResult(ControllerContext controllerContext) {
ViewResult viewResult = new ViewResult();
viewResult.ViewName = viewName;
viewResult.ViewData = controllerContext.Controller.ViewData;
viewResult.TempData = controllerContext.Controller.TempData;
viewResult.ExecuteResult(controllerContext);
controllerContext.HttpContext.Response.TrySkipIisCustomErrors = true;
}
}
Puede registrar este filtro para que especifique el código de estado http de HttpException o el HttpStatusCodeResult concreto para el que desea mostrar la vista personalizada.
GlobalFilters.Filters.Add(new CustomViewForHttpStatusResultFilter(new HttpNotFoundResult(), "Error404"));
// alternate syntax
GlobalFilters.Filters.Add(new CustomViewForHttpStatusResultFilter(404, "Error404"));
Maneja excepciones y HttpStatusCodeResult lanzados o devueltos dentro de una acción. No manejará los errores que ocurran antes de que MVC seleccione una acción adecuada y un controlador como este problema común:
- Rutas desconocidas
- Controladores desconocidos
- Acciones desconocidas
Para manejar este tipo de errores NotFound, combine esta solución con otras soluciones que se encuentran en .
Información útil de @Darin Dimitrov de que HttpNotFoundResult
está devolviendo el resultado vacío.
Después de un estudio. La solución alternativa para MVC 3 aquí es derivar todas las HttpNotFoundResult
, HttpUnauthorizedResult
, HttpStatusCodeResult
e implementar un nuevo método HttpNotFound
() sobre HttpNotFound
( HttpNotFound
).
Es una buena práctica usar el Controlador base para que tenga ''control'' sobre todos los Controladores derivados.
Creo una nueva clase HttpStatusCodeResult
, que no se deriva de ActionResult
sino de ViewResult
para representar la vista o cualquier View
que desee al especificar la propiedad ViewName
. Sigo el HttpStatusCodeResult
original para establecer HttpContext.Response.StatusCode
y HttpContext.Response.StatusDescription
pero luego base.ExecuteResult(context)
representará la vista adecuada porque de nuevo deriva de ViewResult
. Lo suficientemente simple es? Espero que esto se implemente en el núcleo de MVC.
Ver mi BaseController
abajo:
using System.Web;
using System.Web.Mvc;
namespace YourNamespace.Controllers
{
public class BaseController : Controller
{
public BaseController()
{
ViewBag.MetaDescription = Settings.metaDescription;
ViewBag.MetaKeywords = Settings.metaKeywords;
}
protected new HttpNotFoundResult HttpNotFound(string statusDescription = null)
{
return new HttpNotFoundResult(statusDescription);
}
protected HttpUnauthorizedResult HttpUnauthorized(string statusDescription = null)
{
return new HttpUnauthorizedResult(statusDescription);
}
protected class HttpNotFoundResult : HttpStatusCodeResult
{
public HttpNotFoundResult() : this(null) { }
public HttpNotFoundResult(string statusDescription) : base(404, statusDescription) { }
}
protected class HttpUnauthorizedResult : HttpStatusCodeResult
{
public HttpUnauthorizedResult(string statusDescription) : base(401, statusDescription) { }
}
protected class HttpStatusCodeResult : ViewResult
{
public int StatusCode { get; private set; }
public string StatusDescription { get; private set; }
public HttpStatusCodeResult(int statusCode) : this(statusCode, null) { }
public HttpStatusCodeResult(int statusCode, string statusDescription)
{
this.StatusCode = statusCode;
this.StatusDescription = statusDescription;
}
public override void ExecuteResult(ControllerContext context)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
context.HttpContext.Response.StatusCode = this.StatusCode;
if (this.StatusDescription != null)
{
context.HttpContext.Response.StatusDescription = this.StatusDescription;
}
// 1. Uncomment this to use the existing Error.ascx / Error.cshtml to view as an error or
// 2. Uncomment this and change to any custom view and set the name here or simply
// 3. (Recommended) Let it commented and the ViewName will be the current controller view action and on your view (or layout view even better) show the @ViewBag.Message to produce an inline message that tell the Not Found or Unauthorized
//this.ViewName = "Error";
this.ViewBag.Message = context.HttpContext.Response.StatusDescription;
base.ExecuteResult(context);
}
}
}
}
Para usar en tu acción de esta manera:
public ActionResult Index()
{
// Some processing
if (...)
return HttpNotFound();
// Other processing
}
Y en _Layout.cshtml (como la página maestra)
<div class="content">
@if (ViewBag.Message != null)
{
<div class="inlineMsg"><p>@ViewBag.Message</p></div>
}
@RenderBody()
</div>
Además, puede usar una vista personalizada como Error.shtml
o crear una nueva NotFound.cshtml
como he comentado en el código y puede definir un modelo de vista para la descripción del estado y otras explicaciones.
Por favor, siga esto si quiere un error httpnotfound en su controlador
public ActionResult Contact()
{
return HttpNotFound();
}
HttpNotFoundResult
no representa una vista. Simplemente establece el código de estado en 404 y devuelve un resultado vacío que es útil para cosas como AJAX, pero si quieres una página de error 404 personalizada, puedes throw new HttpException(404, "Not found")
que renderizará automáticamente la vista configurada en web.config:
<customErrors mode="RemoteOnly" redirectMode="ResponseRewrite">
<error statusCode="404" redirect="/Http404.html" />
</customErrors>
protected override void HandleUnknownAction(string actionName)
{
ViewBag.actionName = actionName;
View("Unknown").ExecuteResult(this.ControllerContext);
}