不存在的目录/文件Web API(不是控制器)的自定义错误页面

时间:2015-09-06 23:55:10

标签: c# asp.net iis web-config asp.net-web-api2

我知道我可以为不存在的控制器或错误的路由设置自定义错误页面但是如果用户试图下载某个目录中不存在的文件,我该如何显示自定义错误页面?我根本无法工作。它仍然显示默认错误页面。

1 个答案:

答案 0 :(得分:2)

此博客文章将指导您处理ASP.Net Web API中的404错误:http://weblogs.asp.net/imranbaloch/handling-http-404-error-in-asp-net-web-api

  

让我们假设您正在使用ASP.NET Web API框架开发HTTP RESTful应用程序。在此应用程序中,您需要在集中位置处理HTTP 404错误。从ASP.NET Web API的角度来看,您需要处理这些情况,

     
      
  • 没有匹配的路线。
  •   
  • 路线已匹配,但路线上未找到{controller}。
  •   
  • 找不到包含{controller}名称的类型。
  •   
  • 在所选控制器中找不到匹配的操作方法,因为没有操作方法以请求HTTP方法动词开始,或者没有找到IActionHttpMethodProviderRoute实现属性的操作方法或没有找到{action} name的方法或没有匹配{action的方法找到名字。
  •   
     

现在,让我们使用Handle404动作方法创建一个ErrorController。此操作方法将用于上述所有情况,以便向客户端发送HTTP 404响应消息。

public class ErrorController : ApiController
{
    [HttpGet, HttpPost, HttpPut, HttpDelete, HttpHead, HttpOptions, AcceptVerbs("PATCH")]
    public HttpResponseMessage Handle404()
    {
        var responseMessage = new HttpResponseMessage(HttpStatusCode.NotFound);
        responseMessage.ReasonPhrase = "The requested resource is not found";
        return responseMessage;
    }
}
  

您可以轻松更改上述操作方法,以发送一些其他特定的HTTP 404错误响应。如果HTTP服务的客户端向资源(uri)发送请求,并且在服务器上没有与此uri匹配的路由,则可以使用自定义路由将请求路由到上述Handle404方法。将此路线放在路线配置的最底部,

routes.MapHttpRoute(
    name: "Error404",
    routeTemplate: "{*url}",
    defaults: new { controller = "Error", action = "Handle404" }
);
  

现在,当匹配的路由中没有{controller}或没有找到{controller}名称的类型时,您需要处理这种情况。您可以轻松处理这种情况,并使用自定义IHttpControllerSelector将请求路由到上面的Handle404方法。这是自定义IHttpControllerSelector的定义,

public class HttpNotFoundAwareDefaultHttpControllerSelector : DefaultHttpControllerSelector
{
    public HttpNotFoundAwareDefaultHttpControllerSelector(HttpConfiguration configuration)
    : base(configuration)
    {
    }
    public override HttpControllerDescriptor SelectController(HttpRequestMessage request)
    {
        HttpControllerDescriptor decriptor = null;
        try
        {
            decriptor = base.SelectController(request);
        }
        catch (HttpResponseException ex)
        {
            var code = ex.Response.StatusCode;
            if (code != HttpStatusCode.NotFound) throw;
            var routeValues = request.GetRouteData().Values;
            routeValues["controller"] = "Error";
            routeValues["action"] = "Handle404";
            decriptor = base.SelectController(request);
        }
        return decriptor;
    }
}
  

接下来,如果由于上面讨论的原因在所选控制器中找不到匹配的动作方法,则还需要将请求传递给上述Handle404方法。这种情况也可以通过自定义IHttpActionSelector轻松处理。这是自定义IHttpActionSelector的来源,

public class HttpNotFoundAwareControllerActionSelector : ApiControllerActionSelector
{
    public HttpNotFoundAwareControllerActionSelector()
    {
    }

    public override HttpActionDescriptor SelectAction(HttpControllerContext controllerContext)
    {
        HttpActionDescriptor decriptor = null;
        try
        {
            decriptor = base.SelectAction(controllerContext);
        }
        catch (HttpResponseException ex)
        {
            var code = ex.Response.StatusCode;
            if (code != HttpStatusCode.NotFound && code != HttpStatusCode.MethodNotAllowed) throw;
            var routeData = controllerContext.RouteData;
            routeData.Values["action"] = "Handle404";
            IHttpController httpController = new ErrorController();
            controllerContext.Controller = httpController;
            controllerContext.ControllerDescriptor = new HttpControllerDescriptor(controllerContext.Configuration, "Error", httpController.GetType());
            decriptor = base.SelectAction(controllerContext);
        }
        return decriptor;
    }
}
  

最后,我们需要注册自定义IHttpControllerSelector和IHttpActionSelector。打开global.asax.cs文件并添加这些行,

configuration.Services.Replace(typeof(IHttpControllerSelector), new HttpNotFoundAwareDefaultHttpControllerSelector(configuration));
configuration.Services.Replace(typeof(IHttpActionSelector), new HttpNotFoundAwareControllerActionSelector());