I'm trying to use the web api in c# so far its been working pretty well but i just have a route that doesn't want to work and i searched a bit around for people with similar problems but their solution didn't seem to work.
I'm trying to have a specific route and capturing an email address in the string, here is my Controller:
[Authorize]
[RoutePrefix("api/contact")]
public class ContactController : ApiController
{
[Route("list/{id:int}")]
[HttpGet]
public ContactList GetList(int id)
{
BasicAuthenticationIdentity identity = (BasicAuthenticationIdentity)this.User.Identity;
ContactModel contactModel = new ContactModel(identity.accountId);
return (contactModel.GetList(id));
}
[Route("list/{id:int}")]
[HttpPost]
public void PostList(int id)
{
BasicAuthenticationIdentity identity = (BasicAuthenticationIdentity)this.User.Identity;
// To be implemented
}
[Route("attribute/{contactKey}")]
[HttpGet]
public IEnumerable<ContactData> GetContactAttributeKey(string contactKey)
{
BasicAuthenticationIdentity identity = (BasicAuthenticationIdentity)this.User.Identity;
ContactModel contactModel = new ContactModel(identity.accountId);
return (contactModel.GetContactAttribute(contactKey));
}
}
The list route works well but when i try something like
http://localhost/api/contact/attribute/test#test.com i keep getting HTTP Error 404.0 - Not Found because it seems it can't find the route.
Is there something wrong in this?
I also have this in the webconfig
// Itinéraires de l'API Web
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
I tried to see if other routes could be set that are the same but there is no other, i just have an account and segment route other than that, if anyone got some suggestion i'm open to everything right now :/
You should use %40 instead of # symbol and %2E instead of ..
http://localhost/api/contact/attribute/test%40test%2Ecom
This is called URL encoding, some characters are not valid in URL.
Okay its a comibnation of the answer of dotctor (using the url encode) and also there is a need to enable this in your web.config
<configuration>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
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;
}
I have looked all over for some kind of soultion for this and it seems I have it setup correctly and followed all corrections in other questions.
When calling "http://localhost/en/api/cart/get" I get:
{"Message":"No HTTP resource was found that matches the request URI 'http://localhost/en/api/cart/get'.","MessageDetail":"No type was found that matches the controller named 'cart'."}
...when trying to access a ApiController setup in an EPiServer CMS/Commerce 7.5+ solution.
The Controller looks like this:
public class CartController : ApiController
{
[HttpGet]
public string Get()
{
return "OK";
}
}
In Global.asax.cs i have this:
protected void Application_Start()
{
RegisterApis(GlobalConfiguration.Configuration);
And the RegisterAPis looks like this:
public static void RegisterApis(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
"Api", // Route name
"api/{controller}/{action}/{id}", // URL with parameters
new { id = RouteParameter.Optional } // Parameter defaults
);
config.Routes.MapHttpRoute(
"LanguageAwareApi", // Route name
"{language}/api/{controller}/{action}/{id}", // URL with parameters
new { id = RouteParameter.Optional } // Parameter defaults
);
// We only support JSON
var appXmlType = GlobalConfiguration.Configuration.Formatters.XmlFormatter.SupportedMediaTypes.FirstOrDefault(t => t.MediaType == "application/xml");
GlobalConfiguration.Configuration.Formatters.XmlFormatter.SupportedMediaTypes.Remove(appXmlType);
}
On the same machine I have the EPiServer Commerce starterkit running i IIS and the code for registering the api controllers is the same. That site runs fine and the api calls can be made correctly but on my site all I get is 404.
So I am probably missing some configuration but I can't for my life figure out what it is. The weird part is that on my site I'm running the EPiServer ServiceApi which creates the /episerverapi Web Api mapping and that works just fine.
Anyone got any clues on why I can't get my APiControllers to work?
In Web API the http verb help the framework to find the right action to be executed and return a result. For sample, in a case of a get method, you just call the controller by get http verb:
http://localhost/en/api/cart
It will bind a Get action method in the Cart controller class. It is valid for a Post, Put, Delete methods too. Keep the default route of asp.net web api
routes.MapHttpRoute(
name: "API Default",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
Try calling just
http://localhost/en/api/cart
In WebAPI if the name of the method matches a HTTP verb then it calls that method when that verb is used on that controller.
I installed ASP.NET 4 Web API Help Page package via nuget to my Web Api project. For some reason it does not display all the api endpoints. I have the documentation set to use XML. Not sure why this is happening, any help is appreciated.
Here is an example controller
public class ProductController : BaseController
{
// GET api/Product/Get/5/43324
[AcceptVerbs("GET")]
public ApiProduct Get(int id, [FromUri]int productId)
{
//// logic
}
}
routes
config.Routes.MapHttpRoute(
name: "api-info",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional, action = RouteParameter.Optional }
);
Thanks
I figured out the issue, the problem here is, In Web API there is no action and methods are mapped to the verb and arguments directly, Updating my route to this fixed the problem and all the routes show up.
config.Routes.MapHttpRoute(
name: "apsi-info",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
If the above solution doesn't solve your problem - take a look and make sure you aren't defining BOTH the AcceptVerbs attribute and its shortcut:
public class ProductController : BaseController
{
// GET api/Product/Get/5/43324
[AcceptVerbs("GET")]
[HttpGet]
public ApiProduct Get(int id, [FromUri]int productId)
{
//// logic
}
}
Remove one of them and it should work.
Another reason why a HTTP method might not be available, either as an endpoint or not showing up in the autogenerated help:
The function might be private and not public.
Will show up:
[HttpGet]
[Route("api/projects")]
public IHttpActionResult GetCount()
{
return Ok(db.Projects.Count());
}
Won't show up:
[HttpGet]
[Route("api/projects")]
private IHttpActionResult GetCount()
{
return Ok(db.Projects.Count());
}
My answer might be helpful for someone with different problem statement, As I faced similar sort of issue and wasted few hours.
[PUT("Update/booking/{id}")]
public bool Put(id bookingId, [FromBody] BookingEntity bookingEntity)
This api endpoint won't appear in API help page.
If you observe parameter name is different in route that is {id} and method parameters "bookingId". Both should be same as specified in below code.
[PUT("Update/booking/{id}")]
public bool Put(id id, [FromBody] BookingEntity bookingEntity)
Using the new Api Controller in MVC4, and I've found a problem. If I have the following methods:
public IEnumberable<string> GetAll()
public IEnumberable<string> GetSpecific(int i)
This will work. However, if I want to retrieve some different data of a different type, it defaults to the GetAll method, even though the $.getJSON is set to the GetAllIntegers method:
public IEnumberable<int> GetAllIntergers()
(bad naming conventions)
Is it possible for me to be able to do this?
Can I only have a single GetAll method in the Web API controller?
I think it's easier to visualise what I'm trying to achieve. Here is a snippet of code to show what I'd like to be able to do, in a single ApiController:
public IEnumerable<string> GetClients()
{ // Get data
}
public IEnumerable<string> GetClient(int id)
{ // Get data
}
public IEnumerable<string> GetStaffMember(int id)
{ // Get data
}
public IEnumerable<string> GetStaffMembers()
{ // Get data
}
This is all in the routing. The default Web API route looks like this:
config.Routes.MapHttpRoute(
name: "API Default",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
With the default routing template, Web API uses the HTTP method to select the action. In result it will map a GET request with no parameters to first GetAll it can find. To work around this you need to define a route where the action name is included:
config.Routes.MapHttpRoute(
name: "ActionApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
After that you can star making requests with following URL's:
api/yourapicontroller/GetClients
api/yourapicontroller/GetStaffMembers
This way you can have multiple GetAll in Controller.
One more important thing here is that with this style of routing, you must use attributes to specify the allowed HTTP methods (like [HttpGet]).
There is also an option of mixing the default Web API verb based routing with traditional approach, it is very well described here:
Web API: Mixing Traditional & Verb-Based Routing
In case someone else faces this problem. Here's how I solved this. Use the [Route] attribute on your controller to route to a specific url.
[Route("api/getClient")]
public ClientViewModel GetClient(int id)
[Route("api/getAllClients")]
public IEnumerable<ClientViewModel> GetClients()