0

I cannot for the life of me understand why this isn't working.

I have a simple ASP.Net MVC Web API controller, with 2 get methods. I have an AngularJS service with 2 corresponding functions. The GetAllRisks works perfectly well. However, the GetRiskByID comes back with an error saying "No HTTP request was found that matches the request "http://localhost:49376/api/RiskApi/GetRiskByID/6" and "No action can be found on the RiskApi controller that matches the request."

The URL is being passed correctly. I have tried various options for the API routing but can't get anywhere. I am sure I am missing something simple but can't see it.

I would really appreciate any thoughts.

Thanks,

Ash

RiskApiController

public class RiskApiController : ApiController
{
    private readonly IRiskDataService _riskDataService;

    public RiskApiController(IRiskDataService riskDataService)
    {
        _riskDataService = riskDataService;
    }

    // GET api/RiskApi
    [HttpGet]
    public IEnumerable<IRisk> GetAllRisks()
    {
        return _riskDataService.GetAllRisks().Take(20);
    }

    // GET api/RiskApi/5
    [HttpGet]
    public IRisk GetRiskByID(int riskID)
    {
        IRisk risk = _riskDataService.GetRiskByID(riskID);
        if (risk == null)
        {
            throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound));
        }
        return risk;
    }
}

service.js

app.service('OpenBoxExtraService', function ($http) {

//Get All Risks
this.getAllRisks = function () {
    return $http.get("/api/RiskApi/GetAllRisks");
}

//Get Single Risk by ID
this.getRisk = function (riskID) {
    var url = "/api/RiskApi/GetRiskByID/" + riskID;
    return $http.get(url);
}
});

WebApiConfig

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        config.Routes.MapHttpRoute(
            name: "ActionRoute",
            routeTemplate: "api/{controller}/{action}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );
    }
}
11
  • [drive by...you might have another layer of problems, but this stood out to me] You can't give the HttpRouteCollection multiple routes with the same name. Change your second route's name value from 'DefaultApi' to "Foo" and it might work. Commented Dec 1, 2015 at 15:27
  • well....your optional routeParameters are going to be in conflict. Which route should be chosen if you provide /api/RiskApi/foo? It would match the api/{controller}/{id} as well as the api/{controller}/{action}/{id} route since you've got {id} optional on both. The router won't be able to tell if foo is an {id} or an {action} value. It naturally won't be able to send "foo" in as an int for the id, but I'm not sure if the router is intelligent enough to infer that the {action} based route is the one you want. I think it will just fail to route. Commented Dec 1, 2015 at 15:41
  • I am not sure what you meant by routes with the same name as they have different names (ActionRoute and DeafultApi). I take your point about the conflicts, but thought that would manifest itself in possibly choosing the wrong route, rather than not finding a route at all. I will look into the RoutingAttributes. Thanks for the pointer. Commented Dec 1, 2015 at 15:46
  • ...oh wow. I totally read both of those Route names as "DefaultApi" when I wrote the comment. Commented Dec 1, 2015 at 15:47
  • ...so, is this new dev? It doesn't really make sense to build this on first-gen Web API and MVC 4 unless you're maintaining an existing first-gen Web API product. Why did you decide to anchor your system down to obsolete technology? Is it only because you're wanting to use VS2010? Commented Dec 1, 2015 at 15:50

2 Answers 2

3

Try changing your WebApiConfig class to:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{action}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );
    }
}

And change your param: riskID to id.

// GET: api/RiskApi/GetRiskByID/5
[HttpGet]
public IRisk GetRiskByID(int id)
{
    IRisk risk = _riskDataService.GetRiskByID(id);
    if (risk == null)
    {
        throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound));
    }
    return risk;
}

Then, you could use:

// GET: api/RiskApi/GetAllRisks
// GET: api/RiskApi/GetRiskByID/5
Sign up to request clarification or add additional context in comments.

7 Comments

That is my first route already. And I am using the URL you suggested in my service.
Yeah, but it's about your WebApiConfig class.
Tried that but it resulted in the same error (as I thought it might as it was already my first route). Thanks anyway.
Hmm, did you try changing your param: riskID to id?
@DannyFardyJhonstonBermúdez lol...that's gonna be it. switch riskID to id in your controller method or change id to riskID in your route configuration.
|
0

...try junking your config's HttpRoute Mapping and introduce the route mapping with Attributes.

Since this is first-gen Web API, you'll need to pull in the AttributeRouting.WebAPI NuGet package, and you'll likely want to refer here(strathweb) for straightforward guidance on how to implement.

Note that you have a mapping problem in your current implementation on your {id} parameter: you declare it to be id in the route configuration, but then you identify it as riskID inside the controller's method; these need to match. Switch your controller's method to have its incoming routeParameter be named id. You could optionally switch your config to declare the {riskID} parameter in your routes, but that would couple your global configuration to the semantics of a specific controller and you'd likely need to implement more routing constraints to have other controllers not named "Risk" make sense.

public class RiskApiController : ApiController
{
   private readonly IRiskDataService _riskDataService;

   public RiskApiController(IRiskDataService riskDataService)
   {
       _riskDataService = riskDataService;
   }

   // GET api/RiskApi
   [HttpGet]
   [Route("api/RiskApi")]
   public IEnumerable<IRisk> GetAllRisks()
   {
       return _riskDataService.GetAllRisks().Take(20);
   }

   // GET api/RiskApi/5
   [HttpGet]
   [Route("api/RiskApi/{id}")]
   public IRisk GetRiskByID(int id)
   {
       IRisk risk = _riskDataService.GetRiskByID(id);
       if (risk == null)
       {
           throw new    HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound));
       }
       return risk;
   }
}

3 Comments

(I was wondering why you were fully qualifying this as "ASP.NET MVC Web API" ...I didn't see your tag) It works by default with Web API 2. It won't work by default in "pre-2", but you can make it work with Nuget packages. strathweb.com/2012/05/…
@TheDumbRadish what are you hosting in? ...IIS? ...Console?
IIS. Using my local machine as in the early stages of development at the moment.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.