Question

I have a Web API, that looks like the following...

public class LeaguesController : ApiController
{
    //api/Leagues/active/1
    //api/Leagues/complete/1
    //api/Leagues/both/1
    [GET("api/Leagues/{type}/{id}")]
    public List<Competition> Get([FromUri]int id, 
                                [FromUri]CompetitionManager.MiniLeagueType type)
    {
        return CompetitionManager.GetUsersMiniLeagues(id, true, type);
    }

    //api/Leagues/GetMiniLeagueTable/3
    [GET("api/Leagues/GetMiniLeagueTable/{id}")]
    public List<SportTableRow> GetMiniLeagueTable([FromUri]int id)
    {
        return SportManager.GetMiniLeagueTable("", id).TableRows;
    }
}

When I call the first method Get, this works fine. When I use fiddler or Chrome REST Client to call the second method GetMiniLeagueTable, I am getting the following error:

{ Message: "The request is invalid." MessageDetail: "The parameters dictionary contains a null entry for parameter 'type' of non-nullable type 'CompetitionManager+MiniLeagueType' for method 'System.Collections.Generic.List`1[Competition] Get(Int32, MiniLeagueType)' in 'LeaguesController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter." }

I am using AttributeRouting to decorate the methods, but this doesn't seem to work. It was working fine before I introduced MiniLeagueType.

Has anyone come across this issue, or can you point me to where I am going wrong?

Was it helpful?

Solution

I think that the cause is this url : api/Leagues/GetMiniLeagueTable/3. This url matches both routes, as it can be interpreted as such : api/Leagues?type=GetMiniLeagueTable&id=3. But it cannot convert GetMiniLeagueTable as a CompetitionManager.MiniLeagueType value, so it raises an error.

You should make more specific routes, for example api/Leagues/GetCompetitions/{type}/{id}, in order to prevent url matching 2 or more different routes.

Another possibility is to invert your action orders, as it will check first action's route before going for the next one if the url doesn't match.

OTHER TIPS

It looks like the url: /api/Leagues/GetMiniLeagueTable/3 would match both routes.

Assuming it matches the first route, it would then be unable to convert GetMiniLeagueTable to CompetitionManager.MiniLeagueType unless that was a valid enum value.

You second route probably needs to be tested first, and only if that fails to match the url, try the second.

Not having used attributerouting myself (though I have used the similar attribute routing in the latest web api) I'm guessing the ActionPrecedence will help.

Try

[GET("api/Leagues/{type}/{id}", ActionPrecedence = 2)]

And

[GET("api/Leagues/GetMiniLeagueTable/{id}", ActionPrecedence = 1)]
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top