12

我目前有一个继承自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”过滤器中执行此操作。

在此先感谢您的帮助。

注意:我绝对不想将用户重定向到 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

我的“未找到”路线什么也没做。

4

6 回答 6

9

在我的另一个 SO question 上找到了我的答案。非常感谢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));
        }
    }
}
于 2010-08-19T21:03:48.173 回答
3

你可以试试:

<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 不会更改。

于 2010-08-19T21:11:21.707 回答
1

我通过简单地返回基本控制器中定义的动作而不是重定向到它来实现这一点。

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

(“SearchUtilities.GetPageNotFoundModel”位是关于通过将 URL 输入我们的搜索引擎来生成建议)

在任何继承基础的动作方法中,我都可以简单地调用它:

return NotFound();

...每当我捕获到无效参数时。包罗万象的路线也是如此。

于 2011-10-18T10:39:23.867 回答
1

路由是模式匹配。您未找到的路由不起作用,因为您的错误 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事件,但我还没有找到解决丢失控制器的更好方法 - 我将其作为另一个问题提出

于 2011-04-18T11:14:51.800 回答
0

这是 ASP.NET MVC 框架的一大遗漏,因为您无法自定义(真正的自定义,我的意思不仅仅是一个错误页面 - 任何东西)没有像1 answer这样的“紧缩”的 404 页面。您可以对所有未找到的原因使用一个 404 错误,或者您可以通过 [HandleError] 自定义多个 500 错误页面,但您不能以声明方式自定义 404 错误。由于 SEO 原因,500 错误是不好的。404 错误是好的错误。

于 2010-12-23T08:57:34.940 回答
0

在网络配置中设置它:

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

error.html 是您可以向用户显示任意 HTML 的自定义页面。

于 2010-08-07T16:45:42.533 回答