ASP.NET MVC - Как бросить страницу 404, похожую на страницу в StackOverflow
В настоящее время у меня есть класс BaseController, который наследуется от System.Web.Mvc.Controller
. В этом классе у меня есть атрибут HandleError
, который перенаправляет пользователей на страницу "500 - Упс, мы прикрутили". В настоящее время это работает как ожидалось.
ЭТО РАБОТЫ
<HandleError()> _
Public Class BaseController : Inherits System.Web.Mvc.Controller
''# do stuff
End Class
У меня также есть мои 404 страницы, работающие на основе Per-ActionResult, которая снова работает, как ожидалось.
ЭТО РАБОТЫ
Function Details(ByVal id As Integer) As ActionResult
Dim user As Domain.User = UserService.GetUserByID(id)
If Not user Is Nothing Then
Dim userviewmodel As Domain.UserViewModel = New Domain.UserViewModel(user)
Return View(userviewmodel)
Else
''# Because of RESTful URL's, some people will want to "hunt around"
''# for other users by entering numbers into the address. We need to
''# gracefully redirect them to a not found page if the user doesn't
''# exist.
Response.StatusCode = CInt(HttpStatusCode.NotFound)
Return View("NotFound")
End If
End Function
Опять же, это отлично работает. Если пользователь вводит что-то вроде http://example.com/user/999 (где userID 999 не существует), они будут видеть соответствующую страницу 404, и все же URL-адрес не изменится (они не перенаправляются на страницу с ошибкой).
Я НЕ МОГУ ПОЛУЧИТЬ ЭТУ ИДЕЮ РАБОТАТЬ
Здесь, где у меня проблема. Если пользователь вводит http://example.com/asdf-, они попадают на общую страницу 404. То, что я хочу сделать, это оставить URL-адрес в такте (IE: не перенаправить на любую другую страницу), а просто отобразить представление "NotFound", а также нажать HttpStatusCode.NotFound
клиенту.
В качестве примера просто зайдите на https://stackoverflow.com/asdf, где вы увидите пользовательскую страницу 404 и увидите URL-адрес, оставшийся в такте.
Очевидно, что я что-то упускаю, но не могу понять. Поскольку "asdf" на самом деле не указывает на какой-либо контроллер, мой базовый класс контроллера не загружается, поэтому я не могу сделать это в фильтре "HandleError" там.
Заранее благодарим за помощь.
Примечание. Я абсолютно не хочу перенаправлять пользователя на страницу 404. Я хочу, чтобы они оставались на существующем URL-адресе, и я хочу, чтобы MVC нажал 404 VIEW пользователю.
Изменить:
Я также пробовал следующее безрезультатно.
Shared Sub RegisterRoutes(ByVal routes As RouteCollection)
routes.RouteExistingFiles = False
routes.IgnoreRoute("{resource}.axd/{*pathInfo}")
routes.IgnoreRoute("Assets/{*pathInfo}")
routes.IgnoreRoute("{*robotstxt}", New With {.robotstxt = "(.*/)?robots.txt(/.*)?"})
routes.AddCombresRoute("Combres")
''# MapRoute allows for a dynamic UserDetails ID
routes.MapRouteLowercase("UserProfile", _
"Users/{id}/{slug}", _
New With {.controller = "Users", .action = "Details", .slug = UrlParameter.Optional}, _
New With {.id = "\d+"} _
)
''# Default Catch All Valid Routes
routes.MapRouteLowercase( _
"Default", _
"{controller}/{action}/{id}/{slug}", _
New With {.controller = "Events", .action = "Index", .id = UrlParameter.Optional, .slug = UrlParameter.Optional} _
)
''# Catch All InValid (NotFound) Routes
routes.MapRoute( _
"NotFound", _
"{*url}", _
New With {.controller = "Error", .action = "NotFound"})
End Sub
Мой маршрут "NotFound" ничего не делает.
Ответы
Ответ 1
Нашел мой ответ по моему другому вопросу SO. Большое спасибо Anh-Kiet Ngo для решения.
protected void Application_Error(object sender, EventArgs e)
{
Exception exception = Server.GetLastError();
// A good location for any error logging, otherwise, do it inside of the error controller.
Response.Clear();
HttpException httpException = exception as HttpException;
RouteData routeData = new RouteData();
routeData.Values.Add("controller", "YourErrorController");
if (httpException != null)
{
if (httpException.GetHttpCode() == 404)
{
routeData.Values.Add("action", "YourErrorAction");
// We can pass the exception to the Action as well, something like
// routeData.Values.Add("error", exception);
// Clear the error, otherwise, we will always get the default error page.
Server.ClearError();
// Call the controller with the route
IController errorController = new ApplicationName.Controllers.YourErrorController();
errorController.Execute(new RequestContext(new HttpContextWrapper(Context), routeData));
}
}
}
Ответ 2
Вы можете попробовать:
<customErrors mode="On" redirectMode="ResponseRewrite">
<error statusCode="404" redirect="~/Error.aspx"/>
</customErrors>
http://msdn.microsoft.com/en-us/library/system.web.configuration.customerrorssection.redirectmode.aspx
Если для свойства RedirectMode установлено значение ResponseRewrite, пользователь отправляется на страницу с ошибкой, а исходный URL-адрес в браузере не изменяется.
Ответ 3
Маршруты - это совпадения с шаблонами. Ваш маршрут не найден, потому что шаблон неправильного URL-адреса соответствует более раннему маршруту.
Итак:
''# Default Catch All Valid Routes
routes.MapRouteLowercase( _
"Default", _
"{controller}/{action}/{id}/{slug}", _
New With {.controller = "Events", .action = "Index", .id = UrlParameter.Optional, .slug = UrlParameter.Optional} _
)
''# Catch All InValid (NotFound) Routes
routes.MapRoute( _
"NotFound", _
"{*url}", _
New With {.controller = "Error", .action = "NotFound"})
Если вы введете: http://example.com/asdf-, то это соответствует маршруту "По умолчанию" выше - MVC ищет asdf-Controller
и может ' t найти его, поэтому исключение выбрано.
Если вы перейдете к http://example.com/asdf-/action/id/slug/extra, то "Default" больше не будет соответствовать, и вместо него будет следовать маршрут "NotFound".
Вы можете добавить фильтр для всех ваших известных контроллеров к маршруту "По умолчанию", но это будет больно поддерживать при добавлении новых контроллеров.
Вам не нужно вообще подключаться к событию Application_Error
, но я еще не нашел лучшего пути к отсутствующему контроллеру - я спросил его как еще один вопрос.
Ответ 4
Я получил это для работы, просто вернув действие, определенное в базовом контроллере, вместо того, чтобы перенаправлять его.
[HandleError]
public ActionResult NotFound()
{
Response.StatusCode = 404;
Response.TrySkipIisCustomErrors = true;
return View("PageNotFound", SearchUtilities.GetPageNotFoundModel(HttpContext.Request.RawUrl));
}
(бит "SearchUtilities.GetPageNotFoundModel" - это генерация предложений путем подачи URL-адреса в нашу поисковую систему)
В любом методе действия, который наследует базу, я могу просто называть это:
return NotFound();
... всякий раз, когда я обнаруживаю недопустимый параметр. И все это делает все то же самое.
Ответ 5
Установите его в веб-конфигурации:
<system.web>
<customErrors mode="On" defaultRedirect="error.html"/>
</system.web>
error.html - это ваша пользовательская страница, на которой вы можете отобразить любой произвольный HTML для пользователя.
Ответ 6
Это большая миссия из структуры ASP.NET MVC, потому что вы не можете настроить (реальная настройка - это не просто одно-ошибка-страница-для-ничего) 404 страницы без "хрустов", например 1 ответ. Вы можете использовать одну ошибку 404 для всех неподтвержденных причин, или вы можете настроить несколько 500 страниц ошибок с помощью [HandleError], но вы НЕ МОЖЕТЕ настроить 404 ошибки декларативно. 500 ошибок ошибочны из-за причин SEO. Ошибки 404 - хорошие ошибки.