ASP.NET MVC - Как скинуть страницу 404, похожую на ту, что на StackOverflow - PullRequest
12 голосов
/ 07 августа 2010

В настоящее время у меня есть класс 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 в такте (т. Е. Не перенаправлять на любую другую страницу), а просто отобразить представление «NotFound» и нажать HttpStatusCode.NotFound для клиента.

ДляНапример, просто зайдите https://stackoverflow.com/asdf, где вы увидите пользовательскую страницу 404 и увидите URL, оставленный в такте.

Очевидно, что я что-то упустил, но не могу понять.Поскольку «asdf» на самом деле не указывает ни на один контроллер, мой базовый класс контроллеров не включается, поэтому я не могу сделать это в фильтре «HandleError».

Заранее спасибо заhelp.

Примечание. Я абсолютно не хочу перенаправлять пользователя на страницу 404.Я хочу, чтобы они оставались по существующему URL, и я хочу, чтобы MVC выдал пользователю 404 ВИД.

Редактировать:

Я также попытался выполнить следующее безрезультатно.

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

Мой маршрут "Не найден" ничего не делает.

Ответы [ 6 ]

9 голосов
/ 20 августа 2010

Нашел мой ответ на мой другой ТАК вопрос . Большое спасибо 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));
        }
    }
}
3 голосов
/ 20 августа 2010

Вы можете попробовать:

<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-адрес в браузере не изменяется.

1 голос
/ 18 октября 2011

Я заставил это работать, просто возвращая действие, определенное в базовом контроллере, вместо перенаправления на него.

[HandleError]
public ActionResult NotFound()
{
    Response.StatusCode = 404;
    Response.TrySkipIisCustomErrors = true;     
    return View("PageNotFound", SearchUtilities.GetPageNotFoundModel(HttpContext.Request.RawUrl));          
}

(бит "SearchUtilities.GetPageNotFoundModel" предназначен для генерации предложений путем подачи URL в нашу поисковую систему)

В любом методе действия, который наследует базу, я могу просто вызвать это:

return NotFound();

... всякий раз, когда я ловлю неверный параметр.И универсальный маршрут делает то же самое.

1 голос
/ 18 апреля 2011

Маршруты соответствуют шаблонам. Ваш не найденный маршрут не работает, потому что шаблон вашего неверного 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 и не может его найти, поэтому выдается исключение.

Если вы перейдете на http://example.com/asdf-/action/id/slug/extra, то значение «По умолчанию» больше не будет совпадать, и вместо него будет следовать маршрут «Не найден».

Вы можете добавить фильтр для всех ваших известных контроллеров в маршрут «по умолчанию», но это будет непросто поддерживать, когда вы добавляете новые контроллеры.

Вам вообще не нужно подключаться к событию Application_Error, но я пока не нашел лучшего способа обойти пропавший контроллер - я задал его как другой вопрос .

0 голосов
/ 23 декабря 2010

Это большая ошибка в ASP.NET MVC Framework, потому что вы не можете настроить (настоящая настройка, я имею в виду не просто одна ошибка для страницы), 404 страницы без «хрустов», как 1 ответ .Вы можете использовать одну ошибку 404 для всех не найденных причин или настроить несколько страниц ошибок 500 с помощью [HandleError], но НЕ МОЖЕТЕ декларативно настраивать ошибки 404.500 ошибок плохи по причинам SEO.404 ошибки - это хорошие ошибки.

0 голосов
/ 07 августа 2010

Настройте его в веб-конфигурации:

<system.web>
      <customErrors mode="On" defaultRedirect="error.html"/>
</system.web>

error.html - это ваша пользовательская страница, на которой вам может понадобиться отобразить произвольный HTML-код пользователю.

...