Subrato M
Subrato M

Reputation: 169

What is wrong with the order of these Web API routes

So I have few routes added in WebApiConfig.cs file and I can get first & second call to work but can't get GADailyAPI calls to work. I get a 404. When the code was first written first two lines of routes were at the bottom and they would throw 404. I have tried changing the order but I can't get all of them to work. Any ideas? Note: This is not my code, so I don't want to to modify much of API code if I can. If I can figure out the routing order and fix it that would be the best solution

        config.Routes.MapHttpRoute(
            name: "GAMonthlyApiNetworkStats",
            routeTemplate: "api/{controller}/{action}/{Year}/{Month}",
            defaults: new { controller = "GAMonthlyAPI", action = "NetworkStats" }
        );

        config.Routes.MapHttpRoute(
            name: "GAMonthlyApiAllStats",
            routeTemplate: "api/{controller}/{action}/{Year}/{Month}",
            defaults: new { controller = "GAMonthlyAPI", action = "AllStats", }
        );

        config.Routes.MapHttpRoute(
            name: "GADailyApiNetworkStats",
            routeTemplate: "api/{controller}/{action}/{StartDate}/{EndDate}",
            defaults: new { controller = "GADailyAPI", action = "NetworkStats" }
        );

        config.Routes.MapHttpRoute(
            name: "GADailyApiAllStats",
            routeTemplate: "api/{controller}/{action}/{StartDate}/{EndDate}",
            defaults: new { controller = "GADailyAPI", action = "AllStats" }
        );

        config.Routes.MapHttpRoute(
            name: "GAMonthlyApiGroupStats",
            routeTemplate: "api/{controller}/{action}/{Year}/{Month}/{GroupID}",
            defaults: new { controller = "GAMonthlyAPI", action = "GroupStats" }
        );
        config.Routes.MapHttpRoute(
            name: "GAMonthlyApiSiteStats",
            routeTemplate: "api/{controller}/{action}/{Year}/{Month}/{SiteID}",
            defaults: new { controller = "GAMonthlyAPI", action = "SiteStats" }
        );

        config.Routes.MapHttpRoute(
            name: "GADailyApiGroupStats",
            routeTemplate: "api/{controller}/{action}/{StartDate}/{EndDate}/{GroupID}",
            defaults: new { controller = "GADailyAPI", action = "GroupStats" }
        );
        config.Routes.MapHttpRoute(
            name: "GADailyApiSiteStats",
            routeTemplate: "api/{controller}/{action}/{StartDate}/{EndDate}/{SiteID}",
            defaults: new { controller = "GADailyAPI", action = "SiteStats" }
        );

Upvotes: 1

Views: 1128

Answers (2)

Joe
Joe

Reputation: 539

Try adding the httpMethod and constraints , It may help:

routes.MapHttpRoute(
name: "ApiPut", 
routeTemplate: "api/{controller}/{id}",
defaults: new { action = "Put" }, 
constraints: new { httpMethod = new HttpMethodConstraint("Put") }
);

Upvotes: 0

NightOwl888
NightOwl888

Reputation: 56869

There is nothing wrong with the order because the first match always wins, so regardless of what order you put a route with 5 segments starting with /api only the first route will be reached. This is because a placeholder like {action} can literally be any string. So you are basically saying:

Match if the url is: /api/<anything>/<anything>/<anything>/<anything>

in all of the first 4 routes and:

Match if the url is: /api/<anything>/<anything>/<anything>/<anything>/<anything>

in the rest.

To fix this, you need to constrain the routes in some way so the routing framework will skip the first route when it doesn't match, then move on to the next route and try to match that one.

    config.Routes.MapHttpRoute(
        name: "GAMonthlyApiNetworkStats",
        routeTemplate: "api/{controller}/NetworkStats/{Year}/{Month}",
        defaults: new { controller = "GAMonthlyAPI", action = "NetworkStats" }
    );

    config.Routes.MapHttpRoute(
        name: "GAMonthlyApiAllStats",
        routeTemplate: "api/{controller}/AllStats/{Year}/{Month}",
        defaults: new { controller = "GAMonthlyAPI", action = "AllStats", }
    );

Now a URL such as /api/GAMonthlyAPI/AllStats/2012/09 will skip the first route because the AllStats segment doesn't match the 3rd segment and will match the second route because the 3rd segment is the same as the value passed.

Reference: Why map special routes first before common routes in asp.net mvc?

Upvotes: 4

Related Questions