Search code examples
asp.netvb.netasp.net-web-apidotnetnukedotnetnuke-8

multiple web api routes not working


I am building a custom module for DNN 8.

I have built modules with multiple routes declared in a controller class. For some reason with this particular controller class, any module routes declared after the first one just returns the following error:

No HTTP resource was found that matches the request URI No action was found on the controller 'ServiceName' that matches the request.

If I change the order of my routes, the first one declared works, but all the following ones do not.

This controller class is VERY simple. Here it is:

    Public Class BranchServiceController
    Inherits DnnApiController
    Implements IServiceRouteMapper

    ''REGISTER SERIVCE ROUTES / URL
    Const moduleName As String = "ModuleName"

    Public Sub RegisterRoutes(routeManager As IMapRoute) Implements IServiceRouteMapper.RegisterRoutes

        routeManager.MapHttpRoute(moduleName,
                                  "branches",
                                  "{controller}/{action}/{DepID}",
                                  New String(){"ModuleName.Services.Controllers"})

        routeManager.MapHttpRoute(moduleName,
                                  "locations",
                                  "{controller}/{action}/{BranchID}",
                                  New String() {"ModuleName.Services.Controllers"})

    End Sub

    <HttpGet>
    <ActionName("locations")>
    <AllowAnonymous>
    Public Function GetLocation(BranchID As Int32) As List(Of BranchLocation)
        Try

            Dim locationCtl As New BranchLocationController

            ''get Branch based on supplied id
            Dim lBranch As List(Of BranchLocation) = locationCtl.GetBranchLocations(BranchID)

            Return lBranch

        Catch ex As Exception
            LogException(ex)
            Return Nothing
        End Try

    End Function

    <HttpGet>
    <ActionName("branches")>
    <AllowAnonymous>
    Public Function GetBranch(DepID As Int32) As List(Of Branch)
        Try

            Dim branchCtl As New BranchController

            ''get Branch based on supplied id
            Dim lBranch As List(Of Branch) = branchCtl.GetBranchs(DepID)

            Return lBranch

        Catch ex As Exception
            LogException(ex)
            Return Nothing
        End Try

    End Function

End Class

if the branches route is first then it works, if the locations route is declared first it works. All I am doing is copying and pasting to change the order so I know the routes are accurate.

I have never come across this before.

WHAT I TRIED:

So I broke each of these routes out into their own class. Now the same problem occurs. I was able to add multiple routes to other controller classes in my project. There is something about these two routes that are conflicting.

I can see in the log4net file that the routes are declared separately and correctly

2016-04-07 22:20:32,595 [][Thread:37][TRACE] DotNetNuke.Web.Api.Internal.ServicesRoutingManager - Mapping route: moduleName-locations-0 @ DesktopModules/moduleName/API/{controller}/{action}/{BranchID}
2016-04-07 22:20:32,598 [][Thread:37][TRACE] DotNetNuke.Web.Api.Internal.ServicesRoutingManager - Mapping route: moduleName-branches-0 @ DesktopModules/moduleName/API/{controller}/{action}/{DepID}

what is weird is if I comment out the routeManager.MapHttpRoute for the locations route in the separate class, the branches route will work.

Question

Can someone help me figure out why this branches route won't work when the locations route is created?


EDIT 1:

What I have tried:

  1. I thought that maybe there was an issue because my action name matched the name of hte peta poco class the object is defined in. So I changed the action name to something random and that DID NOT fix it.
  2. I thought maybe there was an issue with multiple routes following the same pattern as {controller}/{action}/{DepID} so I made sure that all routes had a different ending parameter name - DID NOT FIX
  3. I made sure the parameter names of the route and function matched - this was not the issue
  4. I moved every route into its own Controller class so each route has a different controller portion of the uri. DID NOT FIX

Further detail, I have one route that always works - and then four that do not. Of those 4, the first route that is defined works, but the following three do not. I have a log4net log that logs the route creation:

2016-04-08 11:31:35,358  - Mapping route: KrisisShifts-locations-0 @ DesktopModules/KrisisShifts/API/{controller}/{action}/{BranchID}
2016-04-08 11:31:35,363  - Mapping route: KrisisShifts-branches-0 @ DesktopModules/KrisisShifts/API/{controller}/{action}/{DepartmentID}
2016-04-08 11:31:35,369  - Mapping route: KrisisShifts-ranks-0 @ DesktopModules/KrisisShifts/API/{controller}/{action}/{ID}
2016-04-08 11:31:35,373  - Mapping route: KrisisShifts-GetMonthCal-0 @ DesktopModules/KrisisShifts/API/{controller}/{action}/{CalID}/{DepID}/{MonthID}/{iYear}
2016-04-08 11:31:35,378  - Mapping route: KrisisShifts-department-0 @ DesktopModules/KrisisShifts/API/{controller}/{action}/{portalID}
2016-04-08 11:31:35,402  - Registered a total of 14 routes

The GetMonthCal route works without error every time. Locations returns a result while the remaining 3 (branches, ranks, department) all return the no action found ... error

If I comment out locations, then branches will work but the remaining two will not. If i comment out locations and branches then ranks work but not the last one.

Here are the route declarations from each class:

        routeManager.MapHttpRoute(moduleName, "branches", "{controller}/{action}/{DepartmentID}", New String() {"Krisis.Modules.KrisisShifts.Services.Controllers"})
        routeManager.MapHttpRoute(moduleName, "GetMonthCal", "{controller}/{action}/{CalID}/{DepID}/{MonthID}/{iYear}", New String() {"Krisis.Modules.KrisisShifts.Services.Controllers"})
        routeManager.MapHttpRoute(moduleName, "department", "{controller}/{action}/{portalID}", New String() {"Krisis.Modules.KrisisShifts.Services.Controllers"})
        routeManager.MapHttpRoute(moduleName, "locations", "{controller}/{action}/{BranchID}", New String() {"Krisis.Modules.KrisisShifts.Services.Controllers"})
        routeManager.MapHttpRoute(moduleName, "ranks", "{controller}/{action}/{ID}", New String() {"Krisis.Modules.KrisisShifts.Services.Controllers"})

I know that the route structure is working because I get results

There is obviously some kind of conflict going on here that I can not find. The controller is getting hit because the routes are created, but the action can not be found for some reason.


Solution

  • The reasoning behind this is that your routes are actuall all the same when it comes to pattern matching.

    Yes, you out a different name at the end. But if you look at the URL that would be used. You get something similar to the following abbreviated URL

    Controller/Action/My-branch Or Controller/Action/My-Department

    There is no way that the routing system would know that the top one is a branch and that the bottom one is a department.

    The typical recommendation is to keep with just an id parameter. Otherwise you will need to change the signature. Possibly something like

    {controller}/{action}/b/{branchName}

    That would differentiate the route. Then you could replace the /b with /d for department.