0
votes

I'm trying to use RoutePrefix, but ASP.NET is partially ignoring it. Given the following controller (method bodies and class fields removed):

[RoutePrefix("api/users/sharepoint")]
public class SharePointController : ApiController
{


    public SharePointController(ISharePointUserRepository repo, IAzureUserRepository otherRepo)
    {

    }

    [HttpGet]
    public ExternalUser Get(int id)
    {

    }

    [HttpGet]
    public ExternalUser Get(Guid guid)
    {

    }

    [HttpGet]
    public IEnumerable<ExternalUser> Get()
    {

    }

    [HttpGet]
    public ExternalUser Get(string username)
    {

    }

    [HttpGet]
    public IEnumerable<ExternalUser> GetByPersonalEmail(string email)
    {

    }

    [HttpGet]
    [Route("GetWithDifferences")]
    public IEnumerable<ExternalUser> GetWithDifferences()
    {

    }

    [HttpGet]
    [Route("GetUnique")]
    public IEnumerable<ExternalUser> GetUnique()
    {


    }

    [HttpPost]
    [Route("search")]
    public IEnumerable<ExternalUser> Search([FromBody] ExternalUserSearchModel model)
    {

    }

I get the following API (via host/help):

SharePoint

GET api/users/sharepoint/GetWithDifferences
GET api/users/sharepoint/GetUnique
POST api/users/sharepoint/search
GET api/SharePoint/{id}
GET api/SharePoint?guid={guid}
GET api/SharePoint
GET api/SharePoint?username={username}
GET api/SharePoint?email={email}

Which, when tested, works as advertised.

As you can see the RoutePrefix is ignored when I don't specify a [Route(..)] for the exposed methods. However I want default actions on GET, so I don't want to specify any additional routing for these.

How can I enforce the RoutePrefix, or, alternatively, how can I maintain default GET and POST behavior with [Route(..)]?

1

1 Answers

1
votes

RoutePrefixAttribute alone does not define any route, it will just add the chosen prefix to any route defined in the class decorated with such attribute.

You need to make a choice then: use only attribute routing (and define a route for each method) so you may benefit from RoutePrefix, or keeping the code as is, and define another convention routing which complies with your URIs.

Sample using attribute routing:

[HttpGet]
[Route("{id:int}"]
public ExternalUser Get(int id)
{ }

[HttpGet]
[Route(""]
public ExternalUser Get(Guid guid)
{ }

[HttpGet]
[Route("")]
public IEnumerable<ExternalUser> Get()
{ }

[HttpGet]
[Route("")]
public ExternalUser Get(string username)
{ }

And here it is another example for the second approach:

public static void Register(HttpConfiguration config)
{
    config.MapHttpAttributeRoutes();

    config.Routes.MapHttpRoute(
        name: "MyCustomApi",
        routeTemplate: "api/users/sharepoint/{id}",
        defaults: new { controller = "SharePoint", id = RouteParameter.Optional }
    );

    config.Routes.MapHttpRoute(
        name: "DefaultApi",
        routeTemplate: "api/{controller}/{id}",
        defaults: new { id = RouteParameter.Optional }
    );
}