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

本文关键字:控制器 错误 不存在 API Web 文件 | 更新日期: 2023-09-27 18:11:23

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

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

这篇博文教你如何处理ASP中的404错误。. Net Web API: http://weblogs.asp.net/imranbaloch/handling-http-404-error-in-asp-net-web-api

假设您正在使用ASP开发一个HTTP RESTful应用程序。. NET Web API框架。在此应用程序中,您需要在集中位置处理HTTP 404错误。从ASP。. NET Web API点的你,你需要处理这些情况,

  • 没有路由匹配。
  • 路由匹配,但没有找到{controller}。
  • 未找到具有{控制器}名称的类型。
  • 在选定的控制器中没有找到匹配的操作方法,因为没有以请求HTTP方法动词开头的操作方法或没有找到具有IActionHttpMethodProviderRoute实现属性的操作方法或没有找到具有{action}名称的方法或没有找到具有匹配{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());