Trevor Daniel
Trevor Daniel

Reputation: 3954

No action was found on the controller that matches the request

Please excuse my ignorance in this area. I have read many threads and still cannot get my routing correct.

I have a ProductsController like this:

public class ProductsController : ApiController
{
    [ActionName("GetListOfStudents")]
    public static List<Structures.StudentInfo> GetListOfStudents(string Username, string Password)
    {
        List<Structures.StudentInfo> si = StudentFunctions.GetListOfStudents(Username, Password);
        return si;
    }
}

I have a console test program where I have defined the route:

config.Routes.MapHttpRoute(
name: "ApiByAction",
routeTemplate: "api/products/GetListOfStudents",
defaults: new { controller = "products", action = "GetListOfStudents" });

But when I run call

GET http://localhost:8080/api/Products/GetListOfStudents

I get the error message:

MessageDetail=No action was found on the controller 'Products' that matches the name 'GetListOfStudents'.

I have been pulling my hair out and cannot work out what the correct route should be.

Would any kind person care to help me out?

Upvotes: 16

Views: 78789

Answers (8)

Adam Hey
Adam Hey

Reputation: 1691

One issue could be the order of the route declarations in your WebApiConfig.cs file. Have a look here about the precedence of routes. If you have two routes with the same amount of parameters, you may need to reorder the routes, or -- depending on how specific the route is -- hardcode the controller or action name

Upvotes: 0

dexiang
dexiang

Reputation: 1413

The most important is: ASP.Net's mvc not only seek action by name, also it will check method's signature, only the method is non-static, name matches and parameters matches, the action will be executed.

for your case, there are two ways to correct it. one way is declare default value, mvc will use default value when parametr not found.

public List<Structures.StudentInfo> GetListOfStudents(string Username = null, string Password = null)
{
    List<Structures.StudentInfo> si = StudentFunctions.GetListOfStudents(Username, Password);
    return si;
}

the second way is use override

public List<Structures.StudentInfo> GetListOfStudents()
{
   return GetListOfStudents(null, null);
}

public List<Structures.StudentInfo> GetListOfStudents(string Username, string Password)
{
    List<Structures.StudentInfo> si = StudentFunctions.GetListOfStudents(Username, Password);
    return si;
}

Upvotes: 6

Ahmadreza Farrokhnejad
Ahmadreza Farrokhnejad

Reputation: 2390

If you want to call GetListOfStudents method without parameter you must set default value for parameter. such as GetListOfStudents(string Username=null, string Password=null) Otherwise you must call method with Parameters. GET http://localhost:8080/api/Products/GetListOfStudents/Username/Password

Upvotes: 0

jmoreno
jmoreno

Reputation: 13561

I had this problem and solved it by including the verb as part of the action (i.e. GetThis, GetThat) and manually creating routes. I was attempting to create routes using attributes, but that did not work. This SO question may be the answer as to why the attributes aren't working, I haven't gotten that straightened out yet. As an additional note for anyone else having the same problem, when debugging it locally, IE was crashing when the "no action found" xml was returned. Once I gave up and switched to Chrome, the message detail was returned, and it was obvious that my controller at least was being found, it was just a matter of getting the action to work...

Upvotes: 0

Victor_Tlepshev
Victor_Tlepshev

Reputation: 510

When sending, encode the password with base64. Then when you about to use it decode it.

byte[] numArray = Convert.FromBase64String(password);
string Pass = Encoding.UTF8.GetString(numArray); 

List<Structures.StudentInfo> si = StudentFunctions.GetListOfStudents(Username, Pass);

Works fine for me.

Upvotes: -5

Trevor Daniel
Trevor Daniel

Reputation: 3954

Ok- thanks for the help peeps!

This what I did to get it working:

  1. Removed the "static" from the GetListOfStudents function.
  2. Added the route below.
config.Routes.MapHttpRoute(
  name: "ApiByAction",
  routeTemplate: "api/products/GetListOfStudents/{username}/{password}",
  defaults: new { controller = "products", action = "GetListOfStudents" }
);

Thanks everyone for your help!

Upvotes: 13

Yuval Itzchakov
Yuval Itzchakov

Reputation: 149538

When registering your global api access point, you should tell the config which route to use in the following manner:

config.Routes.MapHttpRoute(
name: "ApiByAction",
routeTemplate: "api/{controller}/{action}
defaults: new { controller = "products", action = "GetListOfStudents" });

In this sample you explicitly tell the controller it should only go to the "products" controller, you can make it generic without specifying the control or the action, just omit the defaults, like this:

config.Routes.MapHttpRoute(
name: "ApiByAction",
routeTemplate: "api/{controller}/{action}

That should do the job :)

Upvotes: 11

LB2
LB2

Reputation: 4860

Your GetListOfStudents action requires two parameters, username and password. Yet, the route definition contains neither specification in the route template where the values for those parameters should come from, nor specification for those parameter defaults in the defaults: parameter definition.

So when request comes in, routing is able to find your controller, but it is unable to find the action that it can call with the request and route context that it has because it has no information for the username and password parameters.

Upvotes: 6

Related Questions