Sunil Thakur
Sunil Thakur

Reputation: 97

Asp.Net WebApi - Multiple actions were found that match the request

With the routeTemplate defined as "api/{controller}/{id}" and having below methods in my controller (ValuesController)

    [HttpGet]
    public IEnumerable<string> GetX()
    {
        return new string[] { "xx1", "xx2" };
    }

    [HttpGet]
    public IEnumerable<string> GetY([FromUri]Customer c)
    {
        return new string[] { "c1", "c2" };
    }

     public class Customer
     {
        public bool IsMarried { get; set; }
        public string CustName { get; set; }
     }

Using the url - "/api/values?IsMarried=false&CustName=aa" results in error - "Multiple actions were found that match the request..." . I am not able to fix above issue without changing the routeTemplate to something like "api/{controller}/{action}/{id}". If anyone knows how to fix above without changing the routeTemplate kindly suggest.

Upvotes: 0

Views: 3621

Answers (3)

Petre T
Petre T

Reputation: 472

Use simple types and map them in the controller:

[HttpGet]
public IEnumerable<string> GetY(bool IsMarried, string CustName)
{
    var cust = new Customer {IsMarried = IsMarried, CustName = CustName};
    return new string[] { "c1", "c2" };
}

Note that you will lose functionalities like ModelState.IsValid so you would need to invoke the validators manually.

Take a look at Action Selection section to see how it works for simple vs complex params.

Upvotes: 1

Igor
Igor

Reputation: 62213

If you cant specify action names then you have two options.

Action based on Parameter

Create an overload that takes a default (null for reference type) parameter. Depending on the state o the parameter do the approriate action. As your sample is very abstract I have no idea if this would work for you or not.

[HttpGet]
public IEnumerable<string> GetY([FromUri]Customer c = default(Customer))
{
    if(c == null /* or some other state */)
        return new string[] { "xx1", "xx2" };
    return new string[] { "c1", "c2" };
}

New Controller

Create a new Controller and define your additional action there. If the actions are very different in nature this might be a better solution. No code sample here is needed, just create a new controller and move the existing method.

Upvotes: 1

Michael
Michael

Reputation: 3631

Solution one: Routing

[RoutePrefix("api")]
public class FooController : ApiController
{
    [Route("Foo/getall")]
    [HttpGet]
    public IEnumerable<string> GetX()
    {
        return new string[] { "xx1", "xx2" };
    }

    [Route("foo/search")]
    [HttpGet]
    public IEnumerable<string> GetY([FromUri]Customer c)
    {
        return new string[] { "c1", "c2" };
    }

    public class Customer
    {
        public bool IsMarried { get; set; }
        public string CustName { get; set; }
    }
}

Remember to add attribute route mapping:

configuration.MapHttpAttributeRoutes();

Solution two: Optional parameters

[RoutePrefix("api")]
public class FooController : ApiController
{
    [HttpGet]
    public IEnumerable<string> GetY([FromUri]Customer c)
    {
        if(c == null)
           // no parameters where set.

        if(c.IsMarried != null)
           // do stuff
        // etc....
        return new string[] { "c1", "c2" };
    }

    public class Customer
    {
        public bool? IsMarried { get; set; }
        public string CustName { get; set; }
    }
}

Upvotes: 1

Related Questions