如何在.NET MVC 2中实现正确的HTTPerror handling?

我一直在努力整天在我的ASP.NET MVC 2应用程序中实现error handling。 我已经看过各种技术,但都没有正常工作。 我正在使用MVC2和.NET 4.0(在MVC3发布之前启动了项目;我们将在我们发布初始版本后进行升级)。

在这一点上,我会很乐意妥善处理404和500错误 – 403(需要授权)也会很好,其次是各种其他具体的回应。 现在,我可以在404之前全部拿到404,全部500,全部302,在500之前全部拿到302。

这是我的要求(它应该非常接近HTTP的基本要求):

  • 如果找不到资源,则抛出一个404,并显示一个404请求的URL的特定页面。 不要像302那样返回一个中间响应代码。理想情况下,保持请求的URL,而不是像/Error/NotFound那样显示一个新的URL,但是如果后者显示,确保我们没有返回redirect响应来获取它。

  • 如果发生内部服务器错误,请抛出500,并显示一个500特定的错误,并指出错误的位置。 同样,不要返回中间响应代码,理想情况下不要更改URL。

以下是我想要的404:

  1. 找不到静态文件: /Content/non-existent-dir/non-existent-file.txt
  2. 未find控制器: /non-existent-controller/Foo/666
  3. find控制器,但未find操作: /Home/non-existent-action/666
  4. find控制器和操作,但操作无法find请求的对象: /Home/Login/non-existent-id

以下是我认为的500:

  1. 发布一个错误的值: POST /User/New/new-user-name-too-long-for-db-column-constraint
  2. 与数据无关的问题,如Web Service端点未响应

其中一些问题需要通过特定的控制器或模型来识别,然后控制器应该抛出相应的HttpException。 其余的应该更通用地处理。

对于404情况#2,我试图使用自定义的ControllerFactory来抛出404如果控制器无法find。 对于404情况#3,我试图使用一个自定义的基本控制器来覆盖HandleUnknownAction并抛出404。

在这两种情况下,我在404之前得到了一个302.而且,我从来没有得到500个错误; 如果我修改Web.config来在我的Web服务端点input一个拼写错误,我仍然得到一个302,然后一个404说不能find使用 Web服务的URL(控制器/操作)。 我也得到请求的URL作为(不需要的)查询string参数: /Error/NotFound?aspxerrorpath=/Home/non-existent-action

这两种技术来自http://www.niksmit.com/wp/?p=17 (如何使用ASP.Net MVC获得正常的404(页面未find)错误页面),从http:// richarddingwall指出。名称/ 2008/08/17 /为基础的战略,为资源-404-错误-在-ASPNET-MVC /

如果在Web.config中有<customErrors mode="On" defaultRedirect="~/Error/Unknown" redirectMode="ResponseRedirect" /> ,我会得到相应的响应代码,但是我的Error控制器永远不会被调用。 取出redirectMode属性让我的MVC错误的意见,但与一个介入302和一个更改的URL – 总是相同的控制器( Unknown = 500;如果我改变它NotFound一切看起来像一个404)。

以下是我已阅读并尝试实施的其他一些内容:

  • http://www.davidjuth.com/asp-net-mvc-error-handler.aspx
  • http://sanjayuttam.com/wordpress/index.php/c-sharp/c-sharp-code-examples/error-handling-in-asp-net-mvc-1-part-2-of-2/
  • http://blog.hebbink.com/post/2010/12/14/NET-custom-404-error-page-returns-302-for-http-status.aspx
  • http://blog.dantup.com/2009/04/aspnet-mvc-handleerror-attribute-custom.html
  • http://weblogs.asp.net/scottgu/archive/2008/07/14/asp-net-mvc-preview-4-release-part-1.aspx

..以及一堆StackOverflowpost。

在我看来,这种error handling对于Web应用程序来说是非常基本的,而MVC框架应该有默认的function,并且让其他人可以扩展它。 也许他们会在未来的版本中做到这一点。 与此同时,有人可以给我全面的细节,如何实施适当的HTTP响应?

这是你可以使用的一种技术。 定义一个将提供错误页面的ErrorsController

 public class ErrorsController : Controller { public ActionResult Http404() { Response.StatusCode = 404; return Content("404", "text/plain"); } public ActionResult Http500() { Response.StatusCode = 500; return Content("500", "text/plain"); } public ActionResult Http403() { Response.StatusCode = 403; return Content("403", "text/plain"); } } 

然后在Global.asax您可以订阅Application_Error事件,您可以在其中loggingexception并执行ErrorsController的相应操作:

 protected void Application_Error(object sender, EventArgs e) { var app = (MvcApplication)sender; var context = app.Context; var ex = app.Server.GetLastError(); context.Response.Clear(); context.ClearError(); var httpException = ex as HttpException; var routeData = new RouteData(); routeData.Values["controller"] = "errors"; routeData.Values["exception"] = ex; routeData.Values["action"] = "http500"; if (httpException != null) { switch (httpException.GetHttpCode()) { case 404: routeData.Values["action"] = "http404"; break; case 403: routeData.Values["action"] = "http403"; break; case 500: routeData.Values["action"] = "http500"; break; } } IController controller = new ErrorsController(); controller.Execute(new RequestContext(new HttpContextWrapper(context), routeData)); } 

现在剩下的就是开始抛出适当的例外:

 public class HomeController : Controller { public ActionResult Index() { throw new HttpException(404, "NotFound"); } } 

对于HTTP 404错误(无redirect),看看我的博客文章的主题。 这可能会给你一些好主意:

http://hectorcorrea.com/blog/returning-http-404-in-asp-net-mvc/16

这不能回答你的问题,但重要的是要注意,HTTP状态500表明服务器出了问题,所以你的例子:

 POST /User/New/new-user-name-too-long-for-db-column-constraint 

是不是有效的理由扔500,其数据validation问题,应该由MVC数据注释或jQueryvalidation框架或等处理。只是在文本框旁边显示一个错误消息说“用户名太长”是好多了。