Jak prawidłowo obsłużyć 404 w ASP.NET MVC?
Używam RC2
Korzystanie z adresu URL:
routes.MapRoute(
"Error",
"{*url}",
new { controller = "Errors", action = "NotFound" } // 404s
);
Powyższe wydaje się dbać o takie żądania (zakładając domyślne tabele tras ustawione przez początkowy projekt MVC): "/ bla / bla/bla / bla"
Nadpisanie funkcji HandleUnknownAction () w samym kontrolerze:
// 404s - handle here (bad action requested
protected override void HandleUnknownAction(string actionName) {
ViewData["actionName"] = actionName;
View("NotFound").ExecuteResult(this.ControllerContext);
}
Jednak poprzednie strategie nie obsługują żądania do złego / nieznanego kontrolera. Na przykład nie mam "/ IDoNotExist", jeśli o to poproszę, dostaję ogólną stronę 404 z serwer WWW, a nie mój 404 Jeśli używam routingu + override.
Więc na koniec moje pytanie brzmi: Czy Jest jakiś sposób, aby złapać tego typu żądania za pomocą trasy lub czegoś innego w samym frameworku MVC?
Czy powinienem domyślnie używać Web.Config customErrors jako mój handler 404 i zapomnieć o tym wszystkim? Zakładam, że jeśli pójdę z customErrors będę musiał przechowywać ogólną stronę 404 poza / Views ze względu na sieć.Ograniczenia konfiguracji bezpośredniego dostępu.
19 answers
Oto jak obsługuję wyjątki http:
protected void Application_Error(object sender, EventArgs e)
{
Exception exception = Server.GetLastError();
// Log the exception.
ILogger logger = Container.Resolve<ILogger>();
logger.Error(exception);
Response.Clear();
HttpException httpException = exception as HttpException;
RouteData routeData = new RouteData();
routeData.Values.Add("controller", "Error");
if (httpException == null)
{
routeData.Values.Add("action", "Index");
}
else //It's an Http Exception, Let's handle it.
{
switch (httpException.GetHttpCode())
{
case 404:
// Page not found.
routeData.Values.Add("action", "HttpError404");
break;
case 500:
// Server error.
routeData.Values.Add("action", "HttpError500");
break;
// Here you can handle Views to other error codes.
// I choose a General error template
default:
routeData.Values.Add("action", "General");
break;
}
}
// Pass exception details to the target error View.
routeData.Values.Add("error", exception);
// Clear the error on server.
Server.ClearError();
// Avoid IIS7 getting in the middle
Response.TrySkipIisCustomErrors = true;
// Call target Controller and pass the routeData.
IController errorController = new ErrorController();
errorController.Execute(new RequestContext(
new HttpContextWrapper(Context), routeData));
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-10-05 18:17:30
Wymagania dla 404
Oto moje wymagania dla rozwiązania 404, a poniżej pokazuję, jak je wdrażam:
- chcę obsługiwać dopasowane trasy z złych działań
- chcę obsługiwać dopasowane trasy ze złymi kontrolerami
- chcę obsługiwać Nie dopasowane trasy (arbitralne adresy URL, których moja aplikacja nie może zrozumieć) - nie chcę, aby te bąbelki do globalnego.asax lub IIS ponieważ wtedy Nie mogę przekierować z powrotem do mojej aplikacji MVC właściwie
- chcę, aby Sposób obsługi w taki sam sposób, jak powyżej, niestandardowe 404s-jak wtedy, gdy identyfikator jest przesyłany dla obiektu, który nie istnieje (może usunięty)
- chcę, aby wszystkie moje 404 zwracały widok MVC (nie statyczną stronę), do którego mogę później pompować więcej danych, jeśli to konieczne ( dobre projekty 404) i oni muszą zwrócić kod statusu HTTP 404
Rozwiązanie
Myślę, że powinieneś zapisać Application_Error
w globalnym.asax dla wyższych rzeczy, takie jak nieobsługiwane wyjątki i logowanie (jak Shay Jacoby ' s answer pokazuje), ale nie obsługa 404. Dlatego moja sugestia trzyma 404 rzeczy z dala od globalnego.plik asax.
Krok 1: miej wspólne miejsce dla 404-logika błędów
Jest to dobry pomysł na konserwację. Użyj ErrorController , aby przyszłe ulepszenia do Twojej dobrze zaprojektowanej strony 404 mogły się łatwo dostosować. upewnij się, że Twoja odpowiedź ma 404 kod !
public class ErrorController : MyController
{
#region Http404
public ActionResult Http404(string url)
{
Response.StatusCode = (int)HttpStatusCode.NotFound;
var model = new NotFoundViewModel();
// If the url is relative ('NotFound' route) then replace with Requested path
model.RequestedUrl = Request.Url.OriginalString.Contains(url) & Request.Url.OriginalString != url ?
Request.Url.OriginalString : url;
// Dont get the user stuck in a 'retry loop' by
// allowing the Referrer to be the same as the Request
model.ReferrerUrl = Request.UrlReferrer != null &&
Request.UrlReferrer.OriginalString != model.RequestedUrl ?
Request.UrlReferrer.OriginalString : null;
// TODO: insert ILogger here
return View("NotFound", model);
}
public class NotFoundViewModel
{
public string RequestedUrl { get; set; }
public string ReferrerUrl { get; set; }
}
#endregion
}
Krok 2: Użyj podstawowej klasy kontrolera, aby łatwo wywołać niestandardową akcję 404 i podłączyć ją HandleUnknownAction
404s w ASP.NET MVC muszą być złowione w wielu miejscach. Pierwszy to HandleUnknownAction
.
Metoda InvokeHttp404
tworzy wspólne miejsce dla przekierowania do ErrorController
i naszej nowej akcji Http404
. Pomyśl wytrzyj !
public abstract class MyController : Controller
{
#region Http404 handling
protected override void HandleUnknownAction(string actionName)
{
// If controller is ErrorController dont 'nest' exceptions
if (this.GetType() != typeof(ErrorController))
this.InvokeHttp404(HttpContext);
}
public ActionResult InvokeHttp404(HttpContextBase httpContext)
{
IController errorController = ObjectFactory.GetInstance<ErrorController>();
var errorRoute = new RouteData();
errorRoute.Values.Add("controller", "Error");
errorRoute.Values.Add("action", "Http404");
errorRoute.Values.Add("url", httpContext.Request.Url.OriginalString);
errorController.Execute(new RequestContext(
httpContext, errorRoute));
return new EmptyResult();
}
#endregion
}
Krok 3: Użyj Dependency Injection w fabryce kontrolera i podłącz 404 HttpExceptions]}
Like so (it nie musi być StructureMap):
przykład MVC1. 0:
public class StructureMapControllerFactory : DefaultControllerFactory
{
protected override IController GetControllerInstance(Type controllerType)
{
try
{
if (controllerType == null)
return base.GetControllerInstance(controllerType);
}
catch (HttpException ex)
{
if (ex.GetHttpCode() == (int)HttpStatusCode.NotFound)
{
IController errorController = ObjectFactory.GetInstance<ErrorController>();
((ErrorController)errorController).InvokeHttp404(RequestContext.HttpContext);
return errorController;
}
else
throw ex;
}
return ObjectFactory.GetInstance(controllerType) as Controller;
}
}
przykład MVC2. 0:
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
try
{
if (controllerType == null)
return base.GetControllerInstance(requestContext, controllerType);
}
catch (HttpException ex)
{
if (ex.GetHttpCode() == 404)
{
IController errorController = ObjectFactory.GetInstance<ErrorController>();
((ErrorController)errorController).InvokeHttp404(requestContext.HttpContext);
return errorController;
}
else
throw ex;
}
return ObjectFactory.GetInstance(controllerType) as Controller;
}
Myślę, że lepiej jest łapać błędy bliżej miejsca ich powstania. Dlatego wolę powyższe od Application_Error
.
Krok 4: Dodaj NotFound route do Global.asax dla adresów URL, które nie są przetwarzane w aplikacji
Ta trasa powinna wskazywać na naszą Http404
akcję. Zwróć uwagę na url
param będzie względnym adresem URL, ponieważ silnik routingu usuwa część domeny tutaj? Dlatego mamy całą tę warunkową logikę url w Kroku 1.
routes.MapRoute("NotFound", "{*url}",
new { controller = "Error", action = "Http404" });
To trzecie i ostatnie miejsce, aby złapać 404s w aplikacji MVC, że nie powoływać się. Jeśli nie złapiesz tu niezrównanych tras, MVC przekaże problem do ASP.NET (Global.asax) i tak naprawdę nie chcesz tego w tej sytuacji.
Krok 5: na koniec wywołaj 404s, gdy aplikacja nie może znaleźć coś
Jak wtedy, gdy zły identyfikator jest złożony do mojego kontrolera kredytów (wynika z MyController
):
//
// GET: /Detail/ID
public ActionResult Detail(int ID)
{
Loan loan = this._svc.GetLoans().WithID(ID);
if (loan == null)
return this.InvokeHttp404(HttpContext);
else
return View(loan);
}
Byłoby miło, gdyby to wszystko można było podłączyć w mniejszej liczbie miejsc z mniejszą ilością kodu, ale myślę, że to rozwiązanie jest bardziej łatwe do utrzymania, bardziej testowalne i dość pragmatyczne.
Dzięki za opinie na razie. Chciałbym dostać więcej.
Uwaga: to zostało edytowane znacznie z mojej oryginalnej odpowiedzi, ale cel/wymagania są takie same - dlatego ja nie dodano nowej odpowiedzi
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 10:31:35
ASP.NET MVC nie obsługuje niestandardowych stron 404 bardzo dobrze. Custom Controller factory, catch-all route, base controller class with HandleUnknownAction
- argh!
Niestandardowe strony błędów IIS są na razie lepszą alternatywą:
Www.config
<system.webServer>
<httpErrors errorMode="Custom" existingResponse="Replace">
<remove statusCode="404" />
<error statusCode="404" responseMode="ExecuteURL" path="/Error/PageNotFound" />
</httpErrors>
</system.webServer>
ErrorController
public class ErrorController : Controller
{
public ActionResult PageNotFound()
{
Response.StatusCode = 404;
return View();
}
}
Przykładowy Projekt
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-04 07:28:52
Szybka Odpowiedź / TL; DR
Dla leniwych ludzi:
Install-Package MagicalUnicornMvcErrorToolkit -Version 1.0
Następnie usuń ten wiersz z global.asax
GlobalFilters.Filters.Add(new HandleErrorAttribute());
i to jest tylko dla IIS7 + i IIS Express.
Jeśli używasz Cassini .. cóż .. um .. er.. niezręcznie ...Długa, wyjaśniona odpowiedź
Wiem, że ktoś na to odpowiedział. Ale odpowiedź jest naprawdę prosta (Pozdro Dla Davida Fowlera i Damiana Edwardsa dla naprawdę odpowiedź na to pytanie).
Nie ma potrzeby robić niczego niestandardowego .
Dla ASP.NET MVC3
, wszystkie kawałki i kawałki są tam.
Krok 1 - > zaktualizuj swoją sieć.config w dwóch miejscach.
<system.web>
<customErrors mode="On" defaultRedirect="/ServerError">
<error statusCode="404" redirect="/NotFound" />
</customErrors>
I
<system.webServer>
<httpErrors errorMode="Custom">
<remove statusCode="404" subStatusCode="-1" />
<error statusCode="404" path="/NotFound" responseMode="ExecuteURL" />
<remove statusCode="500" subStatusCode="-1" />
<error statusCode="500" path="/ServerError" responseMode="ExecuteURL" />
</httpErrors>
...
<system.webServer>
...
</system.web>
Teraz zwróć uwagę na trasy, z których zdecydowałem się skorzystać. Możesz użyć wszystkiego, ale Moje trasy to
-
/NotFound
-
/ServerError
Widzisz jak pierwsza sekcja w <system.web>
ma tylko jeden Niestandardowy wpis? statusCode="404"
wpis? Wymieniłem tylko jeden kod statusu, ponieważ wszystkie inne błędy, w tym 500 Server Error
(ie. te brzydkie błąd, który dzieje się, gdy kod ma błąd i zawiesza żądanie użytkownika).. wszystkie pozostałe błędy są obsługiwane przez ustawienie defaultRedirect="/ServerError"
.. co mówi, jeśli nie jesteś 404 Strona nie znaleziono, następnie proszę goto trasy /ServerError
.
global.asax
Krok 2-tworzenie tras w trybie globalnym.asax
Oto mój pełny odcinek trasy..public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.IgnoreRoute("{*favicon}", new {favicon = @"(.*/)?favicon.ico(/.*)?"});
routes.MapRoute(
"Error - 404",
"NotFound",
new { controller = "Error", action = "NotFound" }
);
routes.MapRoute(
"Error - 500",
"ServerError",
new { controller = "Error", action = "ServerError"}
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new {controller = "Home", action = "Index", id = UrlParameter.Optional}
);
}
Który wymienia dwie ignorowane trasy - > axd's
i favicons
(ooo! bonus dla Ciebie!)
Następnie (a kolejność jest tu niezbędna), mam moje dwa wyraźne trasy obsługi błędów .. a następnie innymi trasami. W tym przypadku domyślnym. Oczywiście, mam więcej, ale to jest specjalne dla mojej strony internetowej. tylko upewnij się, że trasy błędów są na na szczycie listy. Porządek jest konieczny .
Wreszcie, gdy znajdujemy się w naszym pliku global.asax
, nie rejestrujemy globalnie atrybutu HandleError. Nie, Nie, Nie sir. Nadda. Nie. Nien. Nie. Nieeee...
Usuń ten wiersz z global.asax
GlobalFilters.Filters.Add(new HandleErrorAttribute());
Krok 3-Utwórz kontroler z metodami akcji
Teraz .. dodajemy kontroler z dwiema metodami akcji ...public class ErrorController : Controller
{
public ActionResult NotFound()
{
Response.StatusCode = (int)HttpStatusCode.NotFound;
return View();
}
public ActionResult ServerError()
{
Response.StatusCode = (int)HttpStatusCode.InternalServerError;
// Todo: Pass the exception into the view model, which you can make.
// That's an exercise, dear reader, for -you-.
// In case u want to pass it to the view, if you're admin, etc.
// if (User.IsAdmin) // <-- I just made that up :) U get the idea...
// {
// var exception = Server.GetLastError();
// // etc..
// }
return View();
}
// Shhh .. secret test method .. ooOOooOooOOOooohhhhhhhh
public ActionResult ThrowError()
{
throw new NotImplementedException("Pew ^ Pew");
}
}
Ok, sprawdźmy to. Po pierwsze, nie ma nie [HandleError]
atrybut tutaj. Dlaczego? Ponieważ wbudowany framework ASP.NET
już obsługuje błędy i określiliśmy wszystko, co musimy zrobić, aby obsłużyć błąd :) to w tej metodzie!
Następnie mam dwie metody działania. Nic trudnego. Jeśli chcesz wyświetlić informacje o wyjątkach, możesz użyć Server.GetLastError()
, aby uzyskać te informacje.
Bonus WTF: tak, zrobiłem trzecią metodę działania, aby przetestować obsługę błędów.
Krok 4-Utwórz widoki
I na koniec utwórz dwa widoki. Put em w normalnym miejscu widoku, dla tego kontrolera.
Komentarze bonusowe
- nie potrzebujesz
Application_Error(object sender, EventArgs e)
- wszystkie powyższe kroki działają w 100% idealnie z Elmah . Elmah pieprzone wroxs!
Gratulacje za przeczytanie tego dużo i mieć jednorożca jako nagrodę!
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:10:41
Badałem wiele Jak prawidłowo zarządzać 404s w MVC (konkretnie MVC3) , i to, IMHO jest najlepszym rozwiązaniem, jakie wymyśliłem:
In global.asax:
public class MvcApplication : HttpApplication
{
protected void Application_EndRequest()
{
if (Context.Response.StatusCode == 404)
{
Response.Clear();
var rd = new RouteData();
rd.DataTokens["area"] = "AreaName"; // In case controller is in another area
rd.Values["controller"] = "Errors";
rd.Values["action"] = "NotFound";
IController c = new ErrorsController();
c.Execute(new RequestContext(new HttpContextWrapper(Context), rd));
}
}
}
ErrorsController:
public sealed class ErrorsController : Controller
{
public ActionResult NotFound()
{
ActionResult result;
object model = Request.Url.PathAndQuery;
if (!Request.IsAjaxRequest())
result = View(model);
else
result = PartialView("_NotFound", model);
return result;
}
}
(opcjonalnie)
Explanation:
AFAIK, jest 6 różnych przypadków, które ASP.NET aplikacje MVC3 mogą generować 404s.(automatycznie generowane przez ASP.NET ramy:)
(1) Adres URL nie znajduje dopasowania w tabeli tras.
(automatycznie generowane przez ASP.NET MVC Framework:)
(2) adres URL znajduje dopasowanie w tabeli tras, ale określa nieistniejący kontroler.
(3) adres URL znajduje dopasowanie w tabeli tras, ale określa nieistniejącą akcję.
(generowane ręcznie:)
(4) akcja zwraca HttpNotFoundResult przy użyciu metody HttpNotFound().
(5) akcja powoduje wywołanie HttpException o kodzie stanu 404.
(6) akcja ręcznie modyfikuje odpowiedź.Właściwość StatusCode do 404.
Zwykle chcesz osiągnąć 3 cele:
(1) wyświetla Użytkownikowi niestandardową stronę błędu 404.
(2) Zachowaj kod statusu 404 w Odpowiedzi klienta (szczególnie ważny dla SEO).
(3) wyślij odpowiedź bezpośrednio, bez przekierowania 302.
Istnieją różne sposoby, aby to osiągnąć:
(1)
<system.web>
<customErrors mode="On">
<error statusCode="404" redirect="~/Errors/NotFound"/>
</customError>
</system.web>
Problemy z tym rozwiązaniem:
- nie spełnia celu (1) w przypadkach (1), (4), (6).
- nie spełnia automatycznie celu (2). Musi być zaprogramowany ręcznie.
- nie spełnia celu (3).
(2)
<system.webServer>
<httpErrors errorMode="Custom">
<remove statusCode="404"/>
<error statusCode="404" path="App/Errors/NotFound" responseMode="ExecuteURL"/>
</httpErrors>
</system.webServer>
Problemy z tym rozwiązanie:
- działa tylko na IIS 7+.
- nie spełnia celu (1) w przypadkach (2), (3), (5).
- nie spełnia automatycznie celu (2). Musi być zaprogramowany ręcznie.
(3)
<system.webServer>
<httpErrors errorMode="Custom" existingResponse="Replace">
<remove statusCode="404"/>
<error statusCode="404" path="App/Errors/NotFound" responseMode="ExecuteURL"/>
</httpErrors>
</system.webServer>
Problemy z tym rozwiązaniem:
- działa tylko na IIS 7+.
- nie spełnia automatycznie celu (2). Musi być zaprogramowany ręcznie.
- zasłania http na poziomie aplikacji wyjątki. Np. nie można użyć sekcji customErrors, System.Www.Mvc.HandleErrorAttribute itp. Nie może wyświetlać tylko ogólnych stron błędów.
(4)
<system.web>
<customErrors mode="On">
<error statusCode="404" redirect="~/Errors/NotFound"/>
</customError>
</system.web>
I
<system.webServer>
<httpErrors errorMode="Custom">
<remove statusCode="404"/>
<error statusCode="404" path="App/Errors/NotFound" responseMode="ExecuteURL"/>
</httpErrors>
</system.webServer>
Problemy z tym rozwiązaniem:
- działa tylko na IIS 7+.
- nie spełnia automatycznie celu (2). Musi być zaprogramowany ręcznie.
- nie spełnia celu (3) w przypadkach (2), (3), (5).
Ludzie, którzy mają kłopoty z tym przed nawet próbował utworzyć własne biblioteki (patrz http://aboutcode.net/2011/02/26/handling-not-found-with-asp-net-mvc3.html ). jednak poprzednie rozwiązanie wydaje się obejmować wszystkie przypadki bez złożoności korzystania z zewnętrznej biblioteki.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-22 22:29:22
Naprawdę podoba mi się rozwiązanie cottsaks i myślę, że jest bardzo jasno wyjaśnione. moim jedynym dodatkiem było zmienić Krok 2 w następujący sposób
public abstract class MyController : Controller
{
#region Http404 handling
protected override void HandleUnknownAction(string actionName)
{
//if controller is ErrorController dont 'nest' exceptions
if(this.GetType() != typeof(ErrorController))
this.InvokeHttp404(HttpContext);
}
public ActionResult InvokeHttp404(HttpContextBase httpContext)
{
IController errorController = ObjectFactory.GetInstance<ErrorController>();
var errorRoute = new RouteData();
errorRoute.Values.Add("controller", "Error");
errorRoute.Values.Add("action", "Http404");
errorRoute.Values.Add("url", httpContext.Request.Url.OriginalString);
errorController.Execute(new RequestContext(
httpContext, errorRoute));
return new EmptyResult();
}
#endregion
}
Zasadniczo powstrzymuje to adresy URL zawierające nieprawidłowe akcje i kontrolery przed dwukrotnym uruchomieniem procedury wyjątku. np. dla adresów URL takich jak asdfsdf / dfgdfgd
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-01 06:16:22
Jedynym sposobem, aby metoda @ cottsak działała dla nieprawidłowych kontrolerów, było zmodyfikowanie istniejącego żądania trasy w CustomControllerFactory, tak:
public class CustomControllerFactory : DefaultControllerFactory
{
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
try
{
if (controllerType == null)
return base.GetControllerInstance(requestContext, controllerType);
else
return ObjectFactory.GetInstance(controllerType) as Controller;
}
catch (HttpException ex)
{
if (ex.GetHttpCode() == (int)HttpStatusCode.NotFound)
{
requestContext.RouteData.Values["controller"] = "Error";
requestContext.RouteData.Values["action"] = "Http404";
requestContext.RouteData.Values.Add("url", requestContext.HttpContext.Request.Url.OriginalString);
return ObjectFactory.GetInstance<ErrorController>();
}
else
throw ex;
}
}
}
Powinienem wspomnieć, że używam MVC 2.0.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-07-29 23:43:14
Oto kolejna metoda wykorzystująca narzędzia MVC, która może obsługiwać żądania złych nazw kontrolerów, złych nazw tras i innych kryteriów, które według ciebie pasują do metody akcji. Osobiście wolę unikać jak największej liczby stron internetowych.ustawienia config, jak to możliwe, ponieważ robią przekierowanie 302 / 200 i nie obsługują ResponseRewrite (Server.Transfer
) używając widoku Razor. Wolałbym zwrócić 404 z niestandardową stroną błędu ze względów SEO.
Niektóre z nich to nowe spojrzenie na technikę cottsaka powyżej.
To rozwiązanie wykorzystuje również minimal web.ustawienia konfiguracyjne faworyzujące filtry błędów MVC 3.
Użycie
Po prostu wyrzuć HttpException z akcji lub niestandardowego filtra ActionFilterAttribute.
Throw New HttpException(HttpStatusCode.NotFound, "[Custom Exception Message Here]")
Krok 1
Dodaj następujące ustawienie do swojej sieci.config. Jest to wymagane do użycia HandleErrorAttribute MVC.
<customErrors mode="On" redirectMode="ResponseRedirect" />
Krok 2
Dodaj niestandardowy HandleHttpErrorAttribute podobny do HandleErrorAttribute frameworka MVC, z wyjątkiem dla błędów HTTP:
<AttributeUsage(AttributeTargets.All, AllowMultiple:=True)>
Public Class HandleHttpErrorAttribute
Inherits FilterAttribute
Implements IExceptionFilter
Private Const m_DefaultViewFormat As String = "ErrorHttp{0}"
Private m_HttpCode As HttpStatusCode
Private m_Master As String
Private m_View As String
Public Property HttpCode As HttpStatusCode
Get
If m_HttpCode = 0 Then
Return HttpStatusCode.NotFound
End If
Return m_HttpCode
End Get
Set(value As HttpStatusCode)
m_HttpCode = value
End Set
End Property
Public Property Master As String
Get
Return If(m_Master, String.Empty)
End Get
Set(value As String)
m_Master = value
End Set
End Property
Public Property View As String
Get
If String.IsNullOrEmpty(m_View) Then
Return String.Format(m_DefaultViewFormat, Me.HttpCode)
End If
Return m_View
End Get
Set(value As String)
m_View = value
End Set
End Property
Public Sub OnException(filterContext As System.Web.Mvc.ExceptionContext) Implements System.Web.Mvc.IExceptionFilter.OnException
If filterContext Is Nothing Then Throw New ArgumentException("filterContext")
If filterContext.IsChildAction Then
Return
End If
If filterContext.ExceptionHandled OrElse Not filterContext.HttpContext.IsCustomErrorEnabled Then
Return
End If
Dim ex As HttpException = TryCast(filterContext.Exception, HttpException)
If ex Is Nothing OrElse ex.GetHttpCode = HttpStatusCode.InternalServerError Then
Return
End If
If ex.GetHttpCode <> Me.HttpCode Then
Return
End If
Dim controllerName As String = filterContext.RouteData.Values("controller")
Dim actionName As String = filterContext.RouteData.Values("action")
Dim model As New HandleErrorInfo(filterContext.Exception, controllerName, actionName)
filterContext.Result = New ViewResult With {
.ViewName = Me.View,
.MasterName = Me.Master,
.ViewData = New ViewDataDictionary(Of HandleErrorInfo)(model),
.TempData = filterContext.Controller.TempData
}
filterContext.ExceptionHandled = True
filterContext.HttpContext.Response.Clear()
filterContext.HttpContext.Response.StatusCode = Me.HttpCode
filterContext.HttpContext.Response.TrySkipIisCustomErrors = True
End Sub
End Class
Krok 3
Dodaj filtry do GlobalFilterCollection (GlobalFilters.Filters
) w Global.asax
. Ten przykład przekieruje wszystkie błędy InternalServerError (500) do widoku współdzielonego błędu (Views/Shared/Error.vbhtml
). Błędy NotFound (404) zostaną wysłane do ErrorHttp404.vbhtml również we współdzielonych widokach. Dodałem tutaj Błąd 401, aby pokazać, jak można to rozszerzyć o dodatkowe kody błędów HTTP. Zauważ, że muszą to być wspólne widoki i wszystkie używają obiektu System.Web.Mvc.HandleErrorInfo
jako model.
filters.Add(New HandleHttpErrorAttribute With {.View = "ErrorHttp401", .HttpCode = HttpStatusCode.Unauthorized})
filters.Add(New HandleHttpErrorAttribute With {.View = "ErrorHttp404", .HttpCode = HttpStatusCode.NotFound})
filters.Add(New HandleErrorAttribute With {.View = "Error"})
Krok 4
Utwórz podstawową klasę kontrolera i Dziedzicz z niej w kontrolerach. Ten krok pozwala nam obsłużyć nieznane nazwy akcji i podnieść Błąd HTTP 404 do naszego HandleHttpErrorAttribute.
Public Class BaseController
Inherits System.Web.Mvc.Controller
Protected Overrides Sub HandleUnknownAction(actionName As String)
Me.ActionInvoker.InvokeAction(Me.ControllerContext, "Unknown")
End Sub
Public Function Unknown() As ActionResult
Throw New HttpException(HttpStatusCode.NotFound, "The specified controller or action does not exist.")
Return New EmptyResult
End Function
End Class
Krok 5
Utwórz nadpisanie ControllerFactory i nadpisanie go w Twoim globalnym.plik asax w Application_Start. Ten krok pozwala nam podnieść wyjątek HTTP 404, gdy Niepoprawna nazwa kontrolera została określone.
Public Class MyControllerFactory
Inherits DefaultControllerFactory
Protected Overrides Function GetControllerInstance(requestContext As System.Web.Routing.RequestContext, controllerType As System.Type) As System.Web.Mvc.IController
Try
Return MyBase.GetControllerInstance(requestContext, controllerType)
Catch ex As HttpException
Return DependencyResolver.Current.GetService(Of BaseController)()
End Try
End Function
End Class
'In Global.asax.vb Application_Start:
controllerBuilder.Current.SetControllerFactory(New MyControllerFactory)
Krok 6
Dołącz specjalną trasę do tabeli tras.Trasy dla akcji BaseController Unknown. To pomoże nam podnieść 404 w przypadku, gdy użytkownik uzyskuje dostęp do nieznanego kontrolera lub nieznanej akcji.
'BaseController
routes.MapRoute( _
"Unknown", "BaseController/{action}/{id}", _
New With {.controller = "BaseController", .action = "Unknown", .id = UrlParameter.Optional} _
)
Podsumowanie
Ten przykład zademonstrował, w jaki sposób można użyć frameworka MVC, aby zwrócić 404 kody błędów Http do przeglądarki bez przekierowania, używając atrybutów filtrów i wspólnych widoków błędów. Pokazuje również pokazanie tego samego niestandardowa strona błędu, gdy podano niepoprawne nazwy kontrolerów i nazwy akcji.
Dodam zrzut ekranu nieprawidłowej nazwy kontrolera, nazwy akcji i niestandardowego 404 podniesionego z akcji Home / TriggerNotFound, jeśli dostanę wystarczającą ilość głosów, aby dodać jeden =). Fiddler zwraca wiadomość 404, gdy uzyskuję dostęp do następujących adresów URL za pomocą tego rozwiązania:
/InvalidController
/Home/InvalidRoute
/InvalidController/InvalidRoute
/Home/TriggerNotFound
Post Cottsaka powyżej i te artykuły były dobrymi referencjami.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-12 07:31:25
Moje skrócone rozwiązanie, które działa z nieobsługiwanymi obszarami, kontrolerami i akcjami:
Utwórz widok 404.cshtml.
-
Utwórz klasę bazową dla kontrolerów:
public class Controller : System.Web.Mvc.Controller { protected override void HandleUnknownAction(string actionName) { Http404().ExecuteResult(ControllerContext); } protected virtual ViewResult Http404() { Response.StatusCode = (int)HttpStatusCode.NotFound; return View("404"); } }
-
Utwórz niestandardową fabrykę kontrolerów zwracając kontroler bazowy jako rezerwowy:
public class ControllerFactory : DefaultControllerFactory { protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType) { if (controllerType != null) return base.GetControllerInstance(requestContext, controllerType); return new Controller(); } }
-
Dodaj do
Application_Start()
następujący wiersz:ControllerBuilder.Current.SetControllerFactory(typeof(ControllerFactory));
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-23 13:09:51
W MVC4 WebAPI 404 mogą być obsługiwane w następujący sposób,
KURSY APICONTROLLER
// GET /api/courses/5
public HttpResponseMessage<Courses> Get(int id)
{
HttpResponseMessage<Courses> resp = null;
var aCourse = _courses.Where(c => c.Id == id).FirstOrDefault();
resp = aCourse == null ? new HttpResponseMessage<Courses>(System.Net.HttpStatusCode.NotFound) : new HttpResponseMessage<Courses>(aCourse);
return resp;
}
HOME CONTROLLER
public ActionResult Course(int id)
{
return View(id);
}
Widok
<div id="course"></div>
<script type="text/javascript">
var id = @Model;
var course = $('#course');
$.ajax({
url: '/api/courses/' + id,
success: function (data) {
course.text(data.Name);
},
statusCode: {
404: function()
{
course.text('Course not available!');
}
}
});
</script>
GLOBAL
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
Wyniki
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-08 12:59:48
Spróbuj NotFoundMVC na nuget. To działa, bez konfiguracji.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-09 14:06:53
Moje rozwiązanie, na wypadek, gdyby ktoś uznał je za przydatne.
W Sieci.config:
<system.web>
<customErrors mode="On" defaultRedirect="Error" >
<error statusCode="404" redirect="~/Error/PageNotFound"/>
</customErrors>
...
</system.web>
W Controllers/ErrorController.cs
:
public class ErrorController : Controller
{
public ActionResult PageNotFound()
{
if(Request.IsAjaxRequest()) {
Response.StatusCode = (int)HttpStatusCode.NotFound;
return Content("Not Found", "text/plain");
}
return View();
}
}
Dodaj PageNotFound.cshtml
do folderu Shared
i to wszystko.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-01 10:31:13
Wydaje mi się, że standardowa konfiguracja CustomErrors
powinna po prostu działać jednak ze względu na zależność od Server.Transfer
wydaje się, że wewnętrzna implementacja ResponseRewrite
nie jest zgodna z MVC.
Wydaje mi się to rażącą dziurą w funkcjonalności, więc postanowiłem ponownie zaimplementować tę funkcję za pomocą modułu HTTP. Poniższe rozwiązanie pozwala obsłużyć dowolny kod statusu HTTP (w tym 404) poprzez przekierowanie na dowolną ważną trasę MVC, tak jak byś to zrobił normalnie.
<customErrors mode="RemoteOnly" redirectMode="ResponseRewrite">
<error statusCode="404" redirect="404.aspx" />
<error statusCode="500" redirect="~/MVCErrorPage" />
</customErrors>
To zostało przetestowane na następujących platformach;
-
[17]}MVC4 w trybie zintegrowanego rurociągu (IIS Express 8)
[[17]} MVC4 w trybie klasycznym (VS Development Server, Cassini)
- MVC4 w trybie klasycznym (IIS6)
Korzyści
- ogólne rozwiązanie, które można wrzucić do dowolnego projektu MVC
- umożliwia obsługę tradycyjnej konfiguracji błędów niestandardowych
- Działa zarówno w zintegrowanym rurociągu, jak i Tryby klasyczne
Rozwiązanie
namespace Foo.Bar.Modules {
/// <summary>
/// Enables support for CustomErrors ResponseRewrite mode in MVC.
/// </summary>
public class ErrorHandler : IHttpModule {
private HttpContext HttpContext { get { return HttpContext.Current; } }
private CustomErrorsSection CustomErrors { get; set; }
public void Init(HttpApplication application) {
System.Configuration.Configuration configuration = WebConfigurationManager.OpenWebConfiguration("~");
CustomErrors = (CustomErrorsSection)configuration.GetSection("system.web/customErrors");
application.EndRequest += Application_EndRequest;
}
protected void Application_EndRequest(object sender, EventArgs e) {
// only handle rewrite mode, ignore redirect configuration (if it ain't broke don't re-implement it)
if (CustomErrors.RedirectMode == CustomErrorsRedirectMode.ResponseRewrite && HttpContext.IsCustomErrorEnabled) {
int statusCode = HttpContext.Response.StatusCode;
// if this request has thrown an exception then find the real status code
Exception exception = HttpContext.Error;
if (exception != null) {
// set default error status code for application exceptions
statusCode = (int)HttpStatusCode.InternalServerError;
}
HttpException httpException = exception as HttpException;
if (httpException != null) {
statusCode = httpException.GetHttpCode();
}
if ((HttpStatusCode)statusCode != HttpStatusCode.OK) {
Dictionary<int, string> errorPaths = new Dictionary<int, string>();
foreach (CustomError error in CustomErrors.Errors) {
errorPaths.Add(error.StatusCode, error.Redirect);
}
// find a custom error path for this status code
if (errorPaths.Keys.Contains(statusCode)) {
string url = errorPaths[statusCode];
// avoid circular redirects
if (!HttpContext.Request.Url.AbsolutePath.Equals(VirtualPathUtility.ToAbsolute(url))) {
HttpContext.Response.Clear();
HttpContext.Response.TrySkipIisCustomErrors = true;
HttpContext.Server.ClearError();
// do the redirect here
if (HttpRuntime.UsingIntegratedPipeline) {
HttpContext.Server.TransferRequest(url, true);
}
else {
HttpContext.RewritePath(url, false);
IHttpHandler httpHandler = new MvcHttpHandler();
httpHandler.ProcessRequest(HttpContext);
}
// return the original status code to the client
// (this won't work in integrated pipleline mode)
HttpContext.Response.StatusCode = statusCode;
}
}
}
}
}
public void Dispose() {
}
}
}
Użycie
Dołącz to jako ostateczny moduł HTTP w swojej sieci.config
<system.web>
<httpModules>
<add name="ErrorHandler" type="Foo.Bar.Modules.ErrorHandler" />
</httpModules>
</system.web>
<!-- IIS7+ -->
<system.webServer>
<modules>
<add name="ErrorHandler" type="Foo.Bar.Modules.ErrorHandler" />
</modules>
</system.webServer>
Dla tych z Was, którzy zwracają uwagę, zauważycie, że w trybie zintegrowanego potoku zawsze będzie to odpowiadać HTTP 200 ze względu na sposób działania Server.TransferRequest
. Aby zwrócić właściwy kod błędu używam poniższego kontrolera błędów.
public class ErrorController : Controller {
public ErrorController() { }
public ActionResult Index(int id) {
// pass real error code to client
HttpContext.Response.StatusCode = id;
HttpContext.Response.TrySkipIisCustomErrors = true;
return View("Errors/" + id.ToString());
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-31 15:39:03
Radzenie sobie z błędami w ASP.NET MVC to tylko wrzód na tyłku. Próbowałem wiele sugestii na tej stronie i na inne pytania i strony i nic nie działa dobrze. Jedną z sugestii było usunięcie błędów w sieci.config wewnątrz systemu.webserver ale to po prostu zwraca puste strony.
Moim celem przy wymyślaniu tego rozwiązania było;
- NIE REDIRECT
- zwraca poprawne KODY STANU Nie 200 / Ok jak domyślne obsługa błędów
1.Dodaj następujący tekst do systemu.web section
<system.web>
<customErrors mode="On" redirectMode="ResponseRewrite">
<error statusCode="404" redirect="~/Error/404.aspx" />
<error statusCode="500" redirect="~/Error/500.aspx" />
</customErrors>
<system.web>
Powyższe obsługuje wszystkie adresy URL, które nie są obsługiwane przez trasy .config i nieobsługiwane wyjątki, szczególnie te spotykane w widokach. Zauważ, że użyłem aspx nie html . To dlatego mogę dodać kod odpowiedzi na kod z tyłu.
2. Utwórz folder o nazwie Error (czy jak wolisz) w korzeń twojego projektu i dodaj dwa formularze internetowe. Poniżej moja 404 Strona;
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="404.aspx.cs" Inherits="Myapp.Error._404" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title >Page Not found</title>
<link href="<%=ResolveUrl("~/Content/myapp.css")%>" rel="stylesheet" />
</head>
<body>
<div class="top-nav">
<a runat="server" class="company-logo" href="~/"></a>
</div>
<div>
<h1>404 - Page Not found</h1>
<p>The page you are looking for cannot be found.</p>
<hr />
<footer></footer>
</div>
</body>
</html>
A na kodzie za ustawiłem kod odpowiedzi
protected void Page_Load(object sender, EventArgs e)
{
Response.StatusCode = 404;
}
Zrób to samo dla 500 stron
3.do obsługi błędów w kontrolerach. Można to zrobić na wiele sposobów. To mi się udało. Wszystkie moje Kontrolery dziedziczą po kontrolerze bazowym. W kontrolerze bazowym mam następujące metody
protected ActionResult ShowNotFound()
{
return ShowNotFound("Page not found....");
}
protected ActionResult ShowNotFound(string message)
{
return ShowCustomError(HttpStatusCode.NotFound, message);
}
protected ActionResult ShowServerError()
{
return ShowServerError("Application error....");
}
protected ActionResult ShowServerError(string message)
{
return ShowCustomError(HttpStatusCode.InternalServerError, message);
}
protected ActionResult ShowNotAuthorized()
{
return ShowNotAuthorized("You are not allowed ....");
}
protected ActionResult ShowNotAuthorized(string message)
{
return ShowCustomError(HttpStatusCode.Forbidden, message);
}
protected ActionResult ShowCustomError(HttpStatusCode statusCode, string message)
{
Response.StatusCode = (int)statusCode;
string title = "";
switch (statusCode)
{
case HttpStatusCode.NotFound:
title = "404 - Not found";
break;
case HttpStatusCode.Forbidden:
title = "403 - Access Denied";
break;
default:
title = "500 - Application Error";
break;
}
ViewBag.Title = title;
ViewBag.Message = message;
return View("CustomError");
}
4.Dodaj CustomError.cshtml to your Shared folder widoki. Poniżej jest mój;
<h1>@ViewBag.Title</h1>
<br />
<p>@ViewBag.Message</p>
Teraz w kontrolerze aplikacji możesz zrobić coś takiego;
public class WidgetsController : ControllerBase
{
[HttpGet]
public ActionResult Edit(int id)
{
Try
{
var widget = db.getWidgetById(id);
if(widget == null)
return ShowNotFound();
//or return ShowNotFound("Invalid widget!");
return View(widget);
}
catch(Exception ex)
{
//log error
logger.Error(ex)
return ShowServerError();
}
}
}
A teraz zastrzeżenie. Nie obsługuje statycznych błędów plików. Więc jeśli masz trasę taką jak example.com/widgets a użytkownik zmienia go na example.com/widgets.html , otrzymają domyślną stronę błędu IIS, więc musisz obsłużyć błędy poziomu IIS w inny sposób.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-01 12:08:24
Zamieszczanie odpowiedzi, ponieważ mój komentarz był zbyt długi...
To zarówno komentarz jak i pytania do wpisu/odpowiedzi:
Https://stackoverflow.com/a/7499406/687549
Wolę tę odpowiedź od innych ze względu na prostotę i fakt, że najwyraźniej konsultowano się z niektórymi osobami z Microsoftu. Mam jednak trzy pytania i jeśli można na nie odpowiedzieć, nazwę tę odpowiedź Świętym Graalem wszystkich odpowiedzi błędów 404/500 na interwebs dla ASP.NET Aplikacja MVC (x).
@Pure.Krome
Czy możesz zaktualizować swoją odpowiedź o SEO z komentarzy wskazywanych przez GWB (nigdy nie było o tym wzmianki w twojej odpowiedzi) -
<customErrors mode="On" redirectMode="ResponseRewrite">
i<httpErrors errorMode="Custom" existingResponse="Replace">
?Możesz zapytać swojego ASP.NET przyjaciele zespołu jeśli można to zrobić w ten sposób-byłoby miło mieć jakieś potwierdzenie-może to duże Nie-Nie zmienić
redirectMode
iexistingResponse
w ten sposób, aby móc ładnie grać z SEO?!Możesz dodać trochę wyjaśnienie tego wszystkiego (
customErrors redirectMode="ResponseRewrite"
,customErrors redirectMode="ResponseRedirect"
,httpErrors errorMode="Custom" existingResponse="Replace"
, usunąćcustomErrors
CAŁKOWICIE jak ktoś zasugerował) po rozmowie ze znajomymi z Microsoftu?
Jak już mówiłem, byłoby supernice, gdybyśmy mogli uzupełnić Twoją odpowiedź, ponieważ wydaje się to dość popularne pytanie z ponad 54 000 odsłon.
Update: odpowiedź jednorożca robi 302 Znalezione i 200 OK i nie można go zmienić, aby zwrócić tylko 404 za pomocą trasy. Musi to być plik fizyczny, który nie jest bardzo MVC:) Przechodzimy więc do innego rozwiązania. Szkoda, bo to wydawało się być ostatecznym MVC: ish odpowiedź tak daleko.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:28
Dodanie mojego rozwiązania, które jest prawie identyczne z rozwiązaniem Hermana Kana, z małą zmarszczką, aby umożliwić to działanie dla mojego projektu.
Tworzenie niestandardowego kontrolera błędów:
public class Error404Controller : BaseController
{
[HttpGet]
public ActionResult PageNotFound()
{
Response.StatusCode = 404;
return View("404");
}
}
Następnie utwórz niestandardową fabrykę kontrolerów:
public class CustomControllerFactory : DefaultControllerFactory
{
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
return controllerType == null ? new Error404Controller() : base.GetControllerInstance(requestContext, controllerType);
}
}
Na koniec dodaj nadpisanie do niestandardowego kontrolera błędów:
protected override void HandleUnknownAction(string actionName)
{
var errorRoute = new RouteData();
errorRoute.Values.Add("controller", "Error404");
errorRoute.Values.Add("action", "PageNotFound");
new Error404Controller().Execute(new RequestContext(HttpContext, errorRoute));
}
I to wszystko. Nie ma potrzeby tworzenia sieci.zmiany konfiguracji.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-03 12:44:39
1) Stwórz abstrakcyjną klasę kontrolera.
public abstract class MyController:Controller
{
public ActionResult NotFound()
{
Response.StatusCode = 404;
return View("NotFound");
}
protected override void HandleUnknownAction(string actionName)
{
this.ActionInvoker.InvokeAction(this.ControllerContext, "NotFound");
}
protected override void OnAuthorization(AuthorizationContext filterContext) { }
}
2) Stwórz dziedziczenie z tej abstrakcyjnej klasy w swoich kontrolerach
public class HomeController : MyController
{}
3) i dodaj widok o nazwie "NotFound" w folderze View-Shared.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-20 13:21:06
Przejrzałem większość rozwiązań zamieszczonych w tym wątku. Chociaż to pytanie może być Stare, to nadal ma zastosowanie do nowych projektów nawet teraz, więc spędziłem sporo czasu czytając odpowiedzi przedstawione tutaj, jak również gdzie indziej.
Jak @Marco zwrócił uwagę na różne przypadki, w których może się zdarzyć 404, sprawdziłem rozwiązanie, które zestawiłem razem z tą listą. Oprócz jego listy wymagań, dodałem jeszcze jeden.
- roztwór powinien być w stanie obsłużyć MVC, jak również AJAX/WebAPI wywołań w najbardziej odpowiedni sposób. (tzn. jeśli 404 dzieje się w MVC, powinien pokazać stronę Not Found, a jeśli 404 dzieje się w WebAPI, nie powinien przejmować odpowiedzi XML / JSON, aby konsumujący Javascript mógł ją łatwo przeanalizować).
Rozwiązanie to jest 2-krotne:
Pierwsza część pochodzi od @Guillaume at https://stackoverflow.com/a/27354140/2310818 . ich rozwiązanie zajmuje się każdym 404, które były spowodowane nieprawidłową trasą, nieprawidłowym kontrolerem i nieprawidłową akcją.
Chodzi o stworzenie formularza internetowego, a następnie wywołanie akcji NotFound kontrolera błędów MVC. Robi to wszystko bez żadnych przekierowań, więc nie zobaczysz ani jednego 302 w Fiddler. Oryginalny adres URL jest również zachowany, co sprawia, że to rozwiązanie jest fantastyczne!
Druga część pochodzi z @ Germán at https://stackoverflow.com/a/5536676/2310818 . ich rozwiązanie zajmuje się każdym 404 zwracane przez twoje działania w postaci HttpNotFoundResult () lub throw new HttpException()!
Chodzi o to, aby filtr spojrzał na odpowiedź, a także wyjątek rzucany przez kontrolery MVC i wywołał odpowiednią akcję w kontrolerze błędów. Ponownie to rozwiązanie działa bez żadnych przekierowań i oryginalny adres URL jest zachowany!
Jak widać, oba te rozwiązania razem oferują bardzo solidny mechanizm obsługi błędów i osiągają wszystkie wymagania wymienione przez @ Marco, jak również moje wymagania. Jeśli chcesz zobaczyć działającą próbkę lub demo tego rozwiązania, zostaw w komentarzach, a ja chętnie je złożę.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:54:58
Przejrzałem Wszystkie artykuły, ale nic nie działa dla mnie: Moje Wymaganie Wpisz cokolwiek w swoim adresie URL niestandardowa strona 404 powinna pokazać.Myślałem, że to bardzo proste.Ale powinieneś dobrze zrozumieć obsługę 404:
<system.web>
<customErrors mode="On" redirectMode="ResponseRewrite">
<error statusCode="404" redirect="~/PageNotFound.aspx"/>
</customErrors>
</system.web>
<system.webServer>
<httpErrors errorMode="Custom">
<remove statusCode="404"/>
<error statusCode="404" path="/PageNotFound.html" responseMode="ExecuteURL"/>
</httpErrors>
</system.webServer>
Uważam ten artykuł za bardzo pomocny.powinien być przeczytany od razu.Custome error page-Ben Foster
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-30 06:23:55