Did a lot of reading around this but no existing fixes work for me.
I am trying to hit an api endpoint from a apiClient project but I keep getting the error message: No action was found on the controller 'UserApi' that matches the request.
I'm able to debug into the api controller but it just won't hit the method.
Client:
public async Task<bool> UserExists(UserDto dto)
{
var postUrl = $"{BaseUri}UserApi/user-exists";
var json = await PostAsync(new Uri(postUrl), dto);
return JsonConvert.DeserializeObject<bool>(json);
}
Api controller:
[Route("api/UserApi")]
public class UserApiController : ApiController
{
public UserApiController()
{
}
[HttpPost]
[Route("user-exists")]
public async Task<bool> UserExists([FromBody]UserDto dto)
{
return true;
}
Route config:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
routes.MapHttpRoute(
name: "ApiAction",
routeTemplate: "api/{controller}/{action}/{dto}",
defaults: new { dto = UrlParameter.Optional }
);
}
The bottom routing configuration is the one I'm trying to use. Any help is appreciated
the first comment on the original post solved half my issue - I was trying to configure routing two different ways. I removed all my code from RegisterRoutes and used
config.MapHttpAttributeRoutes();
in WebApiConfig.
I also needed to use the RoutePrefix attribute on the api controller instead of just Route - which is to be used on the controller methods. working now
1.In Global.asax.cs just comment
//RouteConfig.RegisterRoutes(RouteTable.Routes);
As you are using web api no need of this route configuration
2.In WebApiConfig.cs use below line only
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
i'm using asp.net web api. And my problem is "Multiple actions were found that match the request" but i set route template already and in my controller i have 2 POST action
**WebApiConfig**
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Formatters.JsonFormatter.SerializerSettings.Formatting = Newtonsoft.Json.Formatting.Indented;
config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
}
}
And this is my controller
1. [Route("{InsertRoadMap}")]
[HttpPost]
public mdRoadMapCallBack InsertRoadMap(mdEvent _mdEvent){
mdRoadMapCallBack _mdRoadMapCallBack = new mdRoadMapCallBack();
return _mdRoadMapCallBack;
}
2. [Route("{UpdateRoadMap}")]
[HttpPost]
public mdRoadMapCallBack UpdateRoadMap(mdEvent _mdEvent)
{
mdRoadMapCallBack _mdRoadMapCallBack = new mdRoadMapCallBack();
return _mdRoadMapCallBack;
}
What is wrong ? Please help. Thank you so much
The Route attribute doesn't seems to be implemented correctly.
Use it like this instead -
[Route("api/mycontroller/InsertRoadMap")]
[Route("api/mycontroller/UpdateRoadMap")]
Now you can browse like this - http://server/api/mycontroller/InsertRoadMap
You can also use RoutePrefix attribute at controller level so that you do not have to repeat api for every method.
[RoutePrefix("api")]
And then you can set routes like -
[Route("mycontroller/InsertRoadMap")]
[Route("mycontroller/UpdateRoadMap")]
See here and here some more information on attribute routing
I'm new to API designing with VS2017 and I'm trying to make my simple API work with few SQL objects in a DB.
I have a fairly simple project which looks like this :
WebApiConfig.cs :
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes
//config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
Which I believe is stock so should get me where I want to.
I have some controllers based on the same principles, here's one for example :
public class UsersController : Controller
{
private APIContext db = new APIContext();
// GET: Users
public ActionResult Index()
{
return View(db.Users.ToList());
}
// GET: Users/Details/5
public ActionResult Details(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Users users = db.Users.Find(id);
if (users == null)
{
return HttpNotFound();
}
return View(users);
}
}
There are more of them, but everything has been autogenerated so I don't think I have to show them.
The problem is that when I get to localhost/api/users, I get the 404 error page :
No HTTP resource was found that matches the request URI 'http://localhost:myport/api/users'.
Same thing when I'm trying to access a specific id with /api/users/1
Can anyone point me where I should try and change things ?
I'm lost in the jungle of the config files and routes !
Thanks !
EDIT :
After some good answers, here's some more information:
I'm wondering if the issue is not somewhere else. When I'm on the localhost/api, I get a "beautiful" error page but when I try to access the /api/users/index I get an XML response with a 404 message in it. Is that a sign of another problem ?
Something to note is that the Swagger UI shows absolutely nothing.
Your Routing configuration mentions only a Controller in the template without a default Action associated with.
Multiple choices are available to you, however, I would suggest to go for a simple one as in:
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes
//config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { action = "index", id = RouteParameter.Optional }
);
}
Now the Action is part of the template, with a default value of index, you will have the following:
http://localhost:myport/api/users redirecting to UsersController.Index
http://localhost:myport/api/users/index redirecting to UsersController.Index
http://localhost:myport/api/users/details redirecting to UsersController.Details
http://localhost:myport/api/users/details/123 redirecting to UsersController.Details
Edit After a second investigation, it appears that you are using an MVC Controller rather than a WebApi Controller. While they both have the same name, they belong to different namespaces and need their own config.
In order to configure your MVC controller route, ensure to have a class as follow in your App_Start folder:
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { action = "Index", id = UrlParameter.Optional }
);
}
}
Then, from the Global.asax, in Application_Start method, ensure to have the following call:
RouteConfig.RegisterRoutes(RouteTable.Routes);
as in:
protected void Application_Start()
{
RouteConfig.RegisterRoutes(RouteTable.Routes);
GlobalConfiguration.Configure(WebApiConfig.Register);
}
From this point, you can now access your controller via http://localhost:myport/users.
On the other end, if you want to do an API returning data rather than views, you would need your controller to inherit from ApiController.
Use http://localhost:yourport/users/index" instead.
The URL format is always Controller/Action/Parameters.
Add a new route with {action}
config.Routes.MapHttpRoute(
name: "MyNewRoute",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { type = RouteParameter.Optional }
URL: http://localhost:myport/api/users/details/123456
For supportability reasons I'm porting an application from .Net Core with ReactJs to .Net MVC.
This also uses Redux for state handling.
This seemed to be going ok but for some reason the WebAPI calls all fail with 404 errors.
I'm pretty sure the routing is correct as per the failing calls but clearly something is getting lost somewhere.
The default MVC controller that was added as an entry point works fine, it's just the ported WebAPI controllers that seem to fail.
I'm not allowed to post the entire code for commercial reasons but this is what the controller and one of the actions in question looks like:
namespace Api.Controllers
{
/// <summary>
/// Account management.
/// </summary>
[Authorize]
[System.Web.Http.RoutePrefix("api/account")]
public class AccountController : ApiController
{
// <snip>
/// <summary>
/// Current logged in account.
/// </summary>
// GET api/Account/UserInfo
[HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
[System.Web.Http.Route("userinfo")]
public async Task<UserInfoViewModel> GetUserInfo()
{
ExternalLoginData externalLogin = ExternalLoginData.FromIdentity(User.Identity as ClaimsIdentity);
var userName = User.Identity.GetUserName();
var account = new AccountRepresentation(await _context
.Accounts
.SingleOrDefaultAsync(acc => acc.Email == userName));
return new UserInfoViewModel
{
Account = account,
UserName = User.Identity.GetUserName(),
Email = User.Identity.GetUserName(),
HasRegistered = externalLogin == null,
LoginProvider = externalLogin != null ? externalLogin.LoginProvider : null,
Roles = await UserManager.GetRolesAsync(User.Identity.GetUserName())
};
}
// </snip>
}
}
(snip comments added by me)
Notice the routing attributes - it's a bit over the top as I'm trying everything, but as far as I can tell this should be ok.
However in the browser console I'm seeing this:
Failed to load resource: the server responded with a status of 404
(not found) http://localhost:49690/api/account/userinfo
The port number is correct for the default controller so unless it's different for the other controllers for some reason, this should be ok as well.
I've been playing with the RouteConfig.cs file which currently looks as follows:
namespace Api
{
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapMvcAttributeRoutes();
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
namespaces: new[] { "Api.Controllers" }
).DataTokens.Add("area", "UI");
routes.MapRoute(
name: "api",
url: "api/{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
namespaces: new[] { "Api.Controllers" }
).DataTokens.Add("area", "UI");
}
}
}
The WebApiConfig file looks as follows:
namespace Api
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
// Web API configuration and services
// Web API routes
// config.MapHttpAttributeRoutes();
// Configure Web API to use only bearer token authentication.
// config.SuppressDefaultHostAuthentication();
// config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
//config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
//config.Routes.MapHttpRoute(
// name: "DefaultApi",
// routeTemplate: "api/{controller}/{id}",
// defaults: new { id = RouteParameter.Optional }
//);
}
}
}
Application_Start() is like this:
namespace Api
{
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
//UnityConfig.RegisterComponents();
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
log4net.Config.XmlConfigurator.Configure();
}
}
}
What else could be missing or wrong that is preventing the API actions being found?
(Let me know if any other code would be helpful)
Other details:
Visual Studio version: Enterprise 2015 update 3
.NET version: 4.6.1
In .Net Core, attribute routing is now enabled by default. However, in MVC5, you are need to set it up. In your route config, add this:
routes.MapHttpAttributeRoutes();
Note that for normal MVC (i.e. not WebAPI) you need this command instead:
routes.MapMvcAttributeRoutes();
Note: MapHttpAttributeRoutes is an extension method in System.Web.Http so you will need a using System.Web.Http; statement.
if you Porting .net Core application from .net mvc you have add WebApiConfig file and register in global file. and it should be like this. First use Route Attribute because you have use Attribute routing.
public static void Register(HttpConfiguration config)
{
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
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;
}