-->

Web API 2 routing attributes work in one controlle

2019-05-14 13:20发布

问题:

Using .NET 4.5.1, Web API 2, Visual Studio 2013:

I have a Web API which has the following routes...

  • /api/providers/specialties
  • /api/providers/specialties/123
  • /api/providers/specialties/medicine

These work as expected... the first one gets a list of all specialties, the second one gets specialty ID 123, and the third gets all specialties with "medicine" in the name.

I also have these routes...

  • /api/locations/specialties
  • /api/locations/specialties/123
  • /api/locations/specialties/ortho

Only the last two work... the first one returns this error:

No HTTP resource was found that matches the request URI [...]
No route providing a controller name was found to match request URI 'http://mysite/api/locations/specialties'

How can this be? It will hit other routes in that controller, just not the base one.

(I also have two other controllers with the routes /api/providers and /api/locations by themselves, which work fine.)

Here is the ProviderSpecialtyController.cs code:

[RoutePrefix("api/providers/specialties")]
public class ProviderSpecialtyController : ApiController
{
    private ProviderEntities db = new ProviderEntities();

    /// <summary>
    /// Get ALL specialties, sorted by name.
    /// </summary>
    [Route("")]
    public IQueryable<ProviderSpecialty> Get()
    {
        return db.ProviderSpecialties.OrderBy(s => s.Name);
    }

    /// <summary>
    /// Get a specific specialty.
    /// </summary>
    /// <param name="id">The ID of a particular specialty.</param>
    [Route("{id:int}")]
    public ProviderSpecialty Get(int id)
    {
        return db.ProviderSpecialties.Where(s => s.Id == id).FirstOrDefault();
    }

    /// <summary>
    /// Get all specialties that contain a keyword.
    /// </summary>
    /// <param name="keyword">The keyword to search for in a specialty name.</param>
    [Route("{keyword:alpha}")]
    public IQueryable<ProviderSpecialty> Get(string keyword)
    {
        return db.ProviderSpecialties.Where(s => s.Name.Contains(keyword)).OrderBy(s => s.Name);
    }
}

And here is the LocationSpecialtyController.cs code:

[RoutePrefix("api/locations/specialties")]
public class LocationSpecialtyController : ApiController
{
    private ProviderEntities db = new ProviderEntities();

    /// <summary>
    /// Get ALL specialties, sorted by name.
    /// </summary>
    [Route("")]
    public IQueryable<LocationSpecialty> Get()
    {
        return db.LocationSpecialties.OrderBy(s => s.Name);
    }

    /// <summary>
    /// Get a specific specialty.
    /// </summary>
    /// <param name="id">The ID of a particular specialty.</param>
    [Route("{id:int}")]
    public LocationSpecialty Get(int id)
    {
        return db.LocationSpecialties.Where(s => s.Id == id).FirstOrDefault();
    }

    /// <summary>
    /// Get all specialties that contain a keyword.
    /// </summary>
    /// <param name="keyword">The keyword to search for in a specialty name.</param>
    [Route("{keyword:alpha}")]
    public IQueryable<LocationSpecialty> Get(string keyword)
    {
        return db.LocationSpecialties.Where(s => s.Name.Contains(keyword)).OrderBy(s => s.Name);
    }
}

As you can see, they are nearly identical except for the route prefix. Why does the provider controller work as expected but location controller does not?

I have enabled tracing and the following is observed when trying to hit /api/locations/specialties:

System.Web.Http.Request: GET http://localhost:49565/api/locations/specialties/: Category=System.Web.Http.Request, Level=Info Begin   http://localhost:49565/api/locations/specialties/
System.Web.Http.Controllers: GET http://localhost:49565/api/locations/specialties/: Category=System.Web.Http.Controllers, Level=Info Begin DefaultHttpControllerSelector SelectController Route='MS_SubRoutes:System.Web.Http.Routing.IHttpRouteData[]'
[...]
System.Web.Http.Controllers: GET http://localhost:49565/api/locations/specialties/: Category=System.Web.Http.Controllers, Level=Error End DefaultHttpControllerSelector SelectController Processing of the HTTP request resulted in an exception. Please see the HTTP response returned by the 'Response' property of this exception for details.

回答1:

This was simpler than it seemed, but determining why was made more difficult by poor debugging (which was filed and verified as a bug in Codeplex by Kiran Challa. This should be fixed as of Web API 2.1.

I had a controller with this route:

/api/locations/keyword

Which would do a keyword search on keyword.

I had another controller with these routes:

/api/locations/specialties
/api/locations/specialties/123
/api/locations/specialties/keyword

The API engine was confused, because I had two controllers with essentially the same route. I removed one and the problem was fixed.

According to the Codeplex issue tracker, the issue was verified, closed and a new error message was added in Web API 2.1.