I keep getting this error when I try to have 2 "Get" methods
Multiple actions were found that match the request: webapi
I been looking around at the other similar questions about this on stack but I don't get it.
I have 2 different names and using the "HttpGet" attribute
[HttpGet]
public HttpResponseMessage Summary(MyVm vm)
{
return null;
}
[HttpGet]
public HttpResponseMessage FullDetails()
{
return null;
}
Your route map is probably something like this in WebApiConfig.cs:
routes.MapHttpRoute(
name: "API Default",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional });
But in order to have multiple actions with the same http method you need to provide webapi with more information via the route like so:
routes.MapHttpRoute(
name: "API Default",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional });
Notice that the routeTemplate now includes an action. Lots more info here: http://www.asp.net/web-api/overview/web-api-routing-and-actions/routing-in-aspnet-web-api
Update:
Alright, now that I think I understand what you are after here is another take at this:
Perhaps you don't need the action url parameter and should describe the contents that you are after in another way. Since you are saying that the methods are returning data from the same entity then just let the parameters do the describing for you.
For example your two methods could be turned into:
public HttpResponseMessage Get()
{
return null;
}
public HttpResponseMessage Get(MyVm vm)
{
return null;
}
What kind of data are you passing in the MyVm object? If you are able to just pass variables through the URI, I would suggest going that route. Otherwise, you'll need to send the object in the body of the request and that isn't very HTTP of you when doing a GET (it works though, just use [FromBody] infront of MyVm).
Hopefully this illustrates that you can have multiple GET methods in a single controller without using the action name or even the [HttpGet] attribute.
Update as of Web API 2.
With this API config in your WebApiConfig.cs file:
public static void Register(HttpConfiguration config)
{
//// Web API routes
config.MapHttpAttributeRoutes(); //Don't miss this
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = System.Web.Http.RouteParameter.Optional }
);
}
You can route our controller like this:
[Route("api/ControllerName/Summary")]
[HttpGet]
public HttpResponseMessage Summary(MyVm vm)
{
return null;
}
[Route("api/ControllerName/FullDetails")]
[HttpGet]
public HttpResponseMessage FullDetails()
{
return null;
}
Where ControllerName is the name of your controller (without "controller"). This will allow you to get each action with the route detailed above.
For further reading: http://www.asp.net/web-api/overview/web-api-routing-and-actions/attribute-routing-in-web-api-2
In Web API (by default) methods are chosen based on a combination of HTTP method and route values.
MyVm looks like a complex object, read by formatter from the body so you have two identical methods in terms of route data (since neither of them has any parameters from the route) - which makes it impossible for the dispatcher (IHttpActionSelector) to match the appropriate one.
You need to differ them by either querystring or route parameter to resolve ambiguity.
After a lot of searching the web and trying to find the most suitable form for routing map
if have found the following
config.Routes.MapHttpRoute("DefaultApiWithId", "Api/{controller}/{id}", new { id =RouteParameter.Optional }, new { id = #"\d+" });
config.Routes.MapHttpRoute("DefaultApiWithAction", "Api/{controller}/{action}");
These mapping applying to both action name mapping and basic http convention (GET,POST,PUT,DELETE)
This is the answer for everyone who knows everything is correct and has checked 50 times.....
Make sure you are not repeatedly looking at RouteConfig.cs.
The file you want to edit is named WebApiConfig.cs
Also, it should probably look exactly like this:
using System.Web.Http;
namespace My.Epic.Website
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
// api/Country/WithStates
config.Routes.MapHttpRoute(
name: "ControllerAndActionOnly",
routeTemplate: "api/{controller}/{action}",
defaults: new { },
constraints: new { action = #"^[a-zA-Z]+([\s][a-zA-Z]+)*$" });
config.Routes.MapHttpRoute(
name: "DefaultActionApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
}
I could have saved myself about 3 hours.
It might be possible that your webmethods are being resolved to the same url. Have a look at the following link :-
http://www.asp.net/web-api/overview/web-api-routing-and-actions/routing-in-aspnet-web-api
So, you might need to add your methodname to your routing table.
Without using actions the options would be:
move one of the methods to a different controller, so that they don't clash.
use just one method that takes the param, and if it's null call the other method from your code.
This solution worked for me.
Please place Route2 first in WebApiConfig. Also Add HttpGet and HttpPost before each method and include controller name and method name in the url.
WebApiConfig =>
config.Routes.MapHttpRoute(
name: "MapByAction",
routeTemplate: "api/{controller}/{action}/{id}", defaults: new { id = RouteParameter.Optional });
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional });
Controller =>
public class ValuesController : ApiController
{
[HttpPost]
public string GetCustomer([FromBody] RequestModel req)
{
return "Customer";
}
[HttpPost]
public string GetCustomerList([FromBody] RequestModel req)
{
return "Customer List";
}
}
Url =>
http://localhost:7050/api/Values/GetCustomer
http://localhost:7050/api/Values/GetCustomerList
I found that that when I have two Get methods, one parameterless and one with a complex type as a parameter that I got the same error. I solved this by adding a dummy parameter of type int, named Id, as my first parameter, followed by my complex type parameter. I then added the complex type parameter to the route template. The following worked for me.
First get:
public IEnumerable<SearchItem> Get()
{
...
}
Second get:
public IEnumerable<SearchItem> Get(int id, [FromUri] List<string> layers)
{
...
}
WebApiConfig:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}/{layers}",
defaults: new { id = RouteParameter.Optional, layers RouteParameter.Optional }
);
It is possible due to using MVC controller instead of Web API controller.
Check the namespace in Web API controller it should be as following
using System.Net;
using System.Net.Http;
using System.Web.Http;
If the namespace are as following then it is give above error in web api controller method calling
using System.Web;
using System.Web.Mvc;
Please check you have two methods which has the different name and same parameters.
If so please delete any of the method and try.
I've stumbled upon this problem while trying to augment my WebAPI controllers with extra actions.
Assume you would have
public IEnumerable<string> Get()
{
return this.Repository.GetAll();
}
[HttpGet]
public void ReSeed()
{
// Your custom action here
}
There are now two methods that satisfy the request for /api/controller which triggers the problem described by TS.
I didn't want to add "dummy" parameters to my additional actions so I looked into default actions and came up with:
[ActionName("builtin")]
public IEnumerable<string> Get()
{
return this.Repository.GetAll();
}
for the first method in combination with the "dual" route binding:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { action = "builtin", id = RouteParameter.Optional },
constraints: new { id = #"\d+" });
config.Routes.MapHttpRoute(
name: "CustomActionApi",
routeTemplate: "api/{controller}/{action}");
Note that even though there is no "action" parameter in the first route template apparently you can still configure a default action allowing us to separate the routing of the "normal" WebAPI calls and the calls to the extra action.
In my Case Everything was right
1) Web Config was configured properly
2) Route prefix and Route attributes were proper
Still i was getting the error. In my Case "Route" attribute (by pressing F12) was point to System.Web.MVc but not System.Web.Http which caused the issue.
You can add [Route("api/[controller]/[action]")] to your controller class.
[Route("api/[controller]/[action]")]
[ApiController]
public class MySuperController : ControllerBase
{
...
}
I know it is an old question, but sometimes, when you use service resources like from AngularJS to connect to WebAPI, make sure you are using the correct route, other wise this error happens.
Make sure you do NOT decorate your Controller methods for the default GET|PUT|POST|DELETE actions with [HttpPost/Put/Get/Delete] attribute. I had added this attibute to my vanilla Post controller action and it caused a 404.
Hope this helps someone as it can be very frustrating and bring progress to a halt.
For example => TestController
[HttpGet]
public string TestMethod(int arg0)
{
return "";
}
[HttpGet]
public string TestMethod2(string arg0)
{
return "";
}
[HttpGet]
public string TestMethod3(int arg0,string arg1)
{
return "";
}
If you can only change WebApiConfig.cs file.
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/",
defaults: null
);
Thats it :)
And Result :
Have you tried like:
[HttpGet("Summary")]
public HttpResponseMessage Summary(MyVm vm)
{
return null;
}
[HttpGet("FullDetails")]
public HttpResponseMessage FullDetails()
{
return null;
}
Related
I am make POST call into my Web API using Postman. I get the error: "The requested resource does not support http method 'GET'."
I am not making a GET call. If I do call one of my GET methods, it works fine and returns the expected result.
My controller class:
[RoutePrefix("api/login")]
public class LoginController : ApiController
{
ModelContext db = new ModelContext();
[HttpPost]
[Route("validate")]
public HttpResponseMessage Validate([FromBody] LoginViewModel login)
{
try
{
var message = Request.CreateResponse(HttpStatusCode.OK);
return message;
}
catch (Exception ex)
{
var message = Request.CreateErrorResponse(HttpStatusCode.BadRequest, ex.Message);
return message;
}
}
}
I have the Web API running locally and call with this URL:
http://localhost:44303/api/login/validate
This url returns:
<Error>
<Message>
The requested resource does not support http method 'GET'.
</Message>
</Error>
My routing in WebApiConfig.cs
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
While this controller message returns HttpResponseMessage, I have tested by changing the response to "string" and just returning a string value, but I get the same error.
I have read through so many SO posts but none appear to fix my issue. I am at a total loss to explain this behavior. I appreciate any ideas.
EDIT
I have tested GETs in other controllers and they are returning data as expected.
EDIT FOR CONTEXT 6/3/2020
This method in the default ValuesController works:
[Route("api/values")]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
These 2 methods in the SAME controller do not work:
// GET api/values/5
public string Get(int id)
{
return "value";
}
// POST api/values
public void Post([FromBody]string value)
{
}
EDIT #2 6/3/2020
Now all of my api methods are working for the default ValuesController. I do not know why.
My custom POST methods in other controllers such as the Post method above are still not working. Here is my current WebApiConfig.cs:
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "Api_Get",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional, action = "Get" },
constraints: new { httpMethod = new HttpMethodConstraint(HttpMethod.Get) }
);
config.Routes.MapHttpRoute(
name: "Api_Post",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional, action = "Post" },
constraints: new { httpMethod = new HttpMethodConstraint(HttpMethod.Post) }
);
}
I do not have any middleware or special routing that I know of. Any exception handling would be simple try-catch.
I am trying to use attribute routing vs convention but that seems to be an issue.
You don't need to create a route table by HttpMethods because you have [HttpPost] attribute.
Replace all config.Routes.MapHttpRoute by
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
It's preferable to use Attribute Routing for Web API project. It will reduce the chances of errors because in RouteConfig class there can be any mistake while creating a new custom route. Also, you don’t have to take care of the routing flow i.e, from most specific to most general. All here is the attribute you use the action method.
I've been trying to figure out why Swagger-Net does not show the endpoint methods in a controller.
The C# project is using a Web API template based on .Net framework 4.6.1.
I get the same result when I use SwashBuckler, so it's not Swagger-Net that's the issue, but something that is not configured or missing.
The SwaggerConfig looks like this
public class SwaggerConfig
{
/// <summary>
///
/// </summary>
public static void Register()
{
var thisAssembly = typeof(SwaggerConfig).Assembly;
GlobalConfiguration.Configuration
.EnableSwagger(c =>
{
c.SingleApiVersion("v1", nameof(ConsentResponseApp));
c.AccessControlAllowOrigin("*");
c.IncludeAllXmlComments(thisAssembly, AppDomain.CurrentDomain.BaseDirectory);
})
.EnableSwaggerUi(c =>
{
c.UImaxDisplayedTags(100);
c.UIfilter("''");
});
}
}
I'm at a dead end at the moment since I have no idea why Swagger cannot read the methods action names.
The answer:
The WebApiConfig route is not by default configured to route with action
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
it has to be changed to
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
Building on Leon's comment. You need to specify a Route as Leon showed above.
I'm not sure [ActionName()] is what you need at all since it will allow your API's consumer to specify the URI with characters .NET may not allow or using a different signature than your actual controller method.
See this post for the reason behind [ActionName()].
You need a route, not an actionname
[Route("SaveConsent")]
Besides that, it is advisable to add expected responses like so:
[SwaggerResponse(HttpStatusCode.OK, "OK", typeof(User))] [SwaggerResponse(HttpStatusCode.BadRequest, "Error", typeof(string))] [SwaggerResponse(HttpStatusCode.NotFound, "Notfound", typeof(string))]
[Route("SaveConsent")]
[HttpPost]
Hi Guys i am new with web api routes and i have this issue where my call will pick up the more generic one over the specific one.
The ajax call i have is
$.getJSON("/api/solutions/GetSolutionByCategory/" + categoryId,
function (data) {//..some other functions}
Within the solutions controller there are 2 methods
[HttpGet]
public IHttpActionResult GetSolutionByCategory(int cateogryId)
{
List<Solution> solutions = _context.Solutions.Where(s => s.CategoryId == cateogryId).ToList();
return Ok(solutions.Select(Mapper.Map<Solution, SolutionDto>));
}
[HttpGet]
public IHttpActionResult GetSolutions()
{
return Ok(_context.Solutions.ToList().Select(Mapper.Map<Solution, SolutionDto>));
}
And then i have the following 3 routes
config.Routes.MapHttpRoute(
name: "WithAction",
routeTemplate: "api/{controller}/GetIssuesByFlag/{flag}",
defaults: new {flag = 3}
);
config.Routes.MapHttpRoute(
name: "SolutionByCategory",
routeTemplate: "api/{controller}/GetSolutionByCategory/{categoryId}",
defaults: new {categoryId = -1}
);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new {id = RouteParameter.Optional}
);
What happens is that my ajax call will ignore the 2nd one that is the one i want it to hit and goes to the 3rd one there for instead of calling the GetSolutionsByCategory it hits the generic GetSolutions
What am i doing wrong here?
There is a typo in your action parameter name, its int cateogryId instead of int categoryId - public IHttpActionResult GetSolutionByCategory(int categoryId).
However, I would suggest you to go for attribute routing instead of adding lots of route configurations. Enable attribute routing in your web api config class - config.MapHttpAttributeRoutes(); and in your controller:
[RoutePrefix("api")]
public class SolutionsController:ApiController
{
[HttpGet]
[Route("GetSolutionByCategory/{categoryId})"]
public IHttpActionResult GetSolutionByCategory(int categoryId)
{
....
}
[HttpGet]
[Route("GetSolutions")]
public IHttpActionResult GetSolutions()
{
...
}
}
Using Attribute routing we can have same controller with multiple get and post methods. We need to add the routing on the action methods.
We can provide the constraints as well with attribute routing.
I have one api Controller with two different routes:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "downloadApi",
routeTemplate: "api/{controller}/{download}/{id}"
);
I want to have these actions with these routes:
1 - For downloading a file: public GetFile()
GET /api/v1/documents/download/id
2 - For getting file info: public GetFileInfo()
GET /api/v1/documents/id
So in my controller I want to have these actions:
public class DocumentsController : apiController
{
// triggers with GET /api/v1/documents/download/id
public HttpResponseMessage GetFile(){}
// triggers with GET /api/v1/documents/id
public HttpResponseMessage GetFileInfo(){}
}
How can I do this?
Thanks
Here's an example to explain my comment. Rather than defining a route in your WebApiConfig.cs that applies to some routes, but not others (which I don't think you can do, but I've never tried so maybe you can), use the Route method attribute to define the route used at the method level.
public class DocumentsController : apiController
{
// triggers with GET /api/v1/documents/download/id
[HttpGet]
[Route("api/v1/documents/download/{id}")]
public HttpResponseMessage GetFile(int id){}
// triggers with GET /api/v1/documents/id
[HttpGet]
[Route("api/v1/documents/{id}")]
public HttpResponseMessage GetFileInfo(int id){}
}
Untested, but it should work
I am getting to following exception when i am trying to call a GET function in MVC WebAPI
{"$id":"1","Message":"An error has occurred.",
"ExceptionMessage":"Multiple actions were found that match the request:
\r\nSystem.Xml.XmlNode Get(Int32, System.String)
I think the problem is cause due to two get function
I have defined two functions:
One:
[HttpGet]
public XmlNode Get(int id, string Tokken)
{
//Do something
}
Second One
[HttpGet]
public List<UsersAnswers> GetUsersInteractions(int? activityID, string Tokken)
{
// Do Something
}
The route configuration
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
Now i am getting the exception when i try to call to the second function:
{SiteURL}/api/Activities/GetUsersInteractions?activityID=32&Tokken=r54e54353
As you can see the route engine sent the request to the first function instead of the second.
How can i define two get operation and to call each one separately?
With the default routing template, Web API uses the HTTP method to select the action. However, you can also create a route where the action name is included in the URI:
routes.MapHttpRoute(
name: "ActionApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
In this route template, the {action} parameter names the action method on the controller. With this style of routing, use attributes to specify the allowed HTTP methods. For example, suppose your controller has the following method:
public class ProductsController : ApiController
{
[HttpGet]
public string Details(int id);
}
In this case, a GET request for “api/products/details/1” would map to the Details method. This style of routing is similar to ASP.NET MVC, and may be appropriate for an RPC-style API.
You can override the action name by using the ActionName attribute. In the following example, there are two actions that map to "api/products/thumbnail/id. One supports GET and the other supports POST:
public class ProductsController : ApiController
{
[HttpGet]
[ActionName("Thumbnail")]
public HttpResponseMessage GetThumbnailImage(int id);
[HttpPost]
[ActionName("Thumbnail")]
public void AddThumbnailImage(int id);
}
You are not calling the second function - the second function is named InsertUserRecord and is a POST method. The function you're calling via GET is GetUserInteractions. As there's no such function for GET, the engine may map this to the only GET function there is, but actually it should throw a "no such function" error.