Anestis Kivranoglou
Anestis Kivranoglou

Reputation: 8164

ASP.NET Web API Controller Function Executes when entering not mapped action route

I have a controller function which accepts a strongly typed model as parameter. When i enter ANY url mapping to the controller but not on a specific action on the post request , then the controller executes this function instead of returning a 404 code.

When i Change the function's parameter to a primitive type variable then the problem does not occur. (i have tried using other strongly typed models as parameters and again the problem occurs)

Here's the function.

 public class PhoneApiController : ApiController
 {
    [HttpPost]
    public HttpResponseMessage RegisterApp(RegisterAppInfo appInfo)
    {


        var resp = Request.CreateResponse(HttpStatusCode.OK, new
        {
            Success = true,
            AppId = 1000,
            IdAlias = "QAUBC9",
            appInfo = appInfo 
        });
        return resp;

    }
}

So when i enter for example localhost:51464/Api/PhoneApi/Sajsdkasjdklajsasd

the function executes normally.!

I am using the default Route config

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

I don't know if this is a bug or i am doing something wrong.

Upvotes: 1

Views: 808

Answers (3)

TheAlbear
TheAlbear

Reputation: 5585

For MVC 4.5 this is the only thing that works

There is currently a bug about this.

Below is a work around in order to get the following route types work

api/{controller}/ //Get All
api/{controller}/{Id} //Get for id 
api/{controller}/{Id}/{Action}/  //Get all for action for controller with Id

you need to do the following.

Change your routing over to. (Note the default action..)

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

In your controller change the base methods over to

[ActionName("DefaultAction")]
public string Get()
{
}

[ActionName("DefaultAction")]
public string Get(int id)
{
}

[ActionName("SpaceTypes")]
public string GetSpaceTypes(int id)
{
}

Now everything should work as expected..

Thanks to Kip Streithorst full this, for a full explanation

Upvotes: 3

The URI /Api/PhoneApi/Sajsdkasjdklajsasd does match your route template api/{controller}/{id} with {controller} matching PhoneApi and {id} matching Sajsdkasjdklajsasd. I assume you are making a POST to this URI. So, Web API is mapping your request to the action method RegisterApp with [HttpPost] in the controller class PhoneApiController.

As far as the junk stuff in the URI, it gets mapped to {id}. But your parameter is RegisterAppInfo, which is a complex type and that gets bound from request body and not the URI. That's why it works when you have the complex type. The simple types are bound from URI, query string.

If you have the action method as public HttpResponseMessage RegisterApp(string id, Abc appInfo), you will see that this id parameter gets populated with "Sajsdkasjdklajsasd".

Upvotes: 3

Mike Wasson
Mike Wasson

Reputation: 6622

The way routing works in Web API is:

  1. First it matches the URI against route template. At this stage, it's not looking at your controller actions
  2. Then it looks for a matching controller
  3. Then it looks for a method where (a) the action matches (POST in this case) and (b) every simple parameter type is matched with a value from the URI.
  4. If there is a complex parameter type, it tries to read that from the request body.

By default, Web API tries to bind "simple" parameter types (like int) from the URI, and tries to read complex types from the request body.

See here for details: http://www.asp.net/web-api/overview/web-api-routing-and-actions/routing-and-action-selection

Upvotes: 0

Related Questions