Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Web API 2.2 return custom 404 when resource (url) not found

I want to be able to take over the 404 response from web api (iis) when the resource does not exist.

I have done my research and came across only one solution that made this work, but i am not sure how "safe" it is since the "routeTemplate" is just {*url}

This post is kinda to ask for help and explanation.

My App uses MVC and WebAPI... would this template affect MVC as well? Is there a way to add "api" with {*url} in the template? (to make sure only requests with ".../api/..." get affected)

config.Routes.MapHttpRoute("Error404", "{*url}", new { controller = "Error", action = "Handle404" });

Has anyone come across a cleaner way of doing this and handling 404 in web api?

EDIT 1

The above code DOES affect my MVC routes. How can i add "api" to "{*url}"?... if tried many different ways and no dice.

like image 240
Gustavo Avatar asked Feb 25 '15 12:02

Gustavo


1 Answers

Had the exact same issue. After some research and trial and error, I was able to find a working solution.

I went with a RoutePrefix solution and I tried to implement something similar to how the MVC controllers used HandleUnknownAction in a base controller.

With the help from this post: .NET WebAPI Attribute Routing and inheritance to allow for route inheritance, I created a base controller for my web APIs with a HandleUnknownAction method like this:

public abstract class WebApiControllerBase : ApiController {

    [Route("{*actionName}")]
    [AcceptVerbs("GET", "POST", "PUT", "DELETE")]//Include what ever methods you want to handle
    [AllowAnonymous]//So I can use it on authenticated controllers
    [ApiExplorerSettings(IgnoreApi = true)]//To hide this method from helpers
    public virtual HttpResponseMessage HandleUnknownAction(string actionName) {
        var status = HttpStatusCode.NotFound;
        //This is custom code to create my response content
        //....
        var message = status.ToString().FormatCamelCase();
        var content = DependencyService
            .Get<IResponseEnvelopeFactory>()
            .CreateWithOnlyMetadata(status, message);
        //....
        return Request.CreateResponse(status, content);
    }
}

If you don't want to go down the inheritance path, you can always put the method directly into the controller you want to apply the functionality on.

This allows me to use route prefixes that handle custom not found messages that pertain to specific controllers as I have both back-office and public public facing APIs.

If a URL does not apply to an ApiController the default Error controller will handle the not found as usual.

like image 65
Nkosi Avatar answered Sep 19 '22 22:09

Nkosi