http://localhost:2000/api/{Controller}
I need to create index page.
URI : http://localhost:2000/api
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "api",
routeTemplate: "api"
);
And the api
[RoutePrefix("api")]
public class Api
{
[HttpGet]
public HttpResponseMessage Get()
{
var result = new HttpResponseMessage(HttpStatusCode.OK);
result.Content = new ByteArrayContent(Encoding.ASCII.GetBytes("API"));
return result;
}
}
But when I open http://localhost:2000/api, it's not working.
No HTTP resource was found that matches the request URI http://localhost:2000/api.
Need to make sure you follow the suggested syntax for API controllers.
[RoutePrefix("api")]
public class MyApiController: ApiController {
[HttpGet]
[Route("")] // GET api
public IHttpActionResult Get() {
return Ok("API");
}
}
Which includes having your controller derived from ApiController.
If using attribute routing with route prefix you still need to provide a route on the action.
[Route("")] in this case above will act as the default rout for that controller.
Related
I am having some trouble understanding how Web API 2 handles routing.
I have created a PostsController that works just fine in terms of the standard actions, GET, POST, etc.
I tried to add a custom route that is a PUT action called Save() that takes a model as an argument.
I added [HttpPut] and [Route("save")] in front of the custom route. I also modified the WebAPIConfig.cs to handle the pattern api/{controller}/{id}/{action}
However, if I go to http://localhost:58385/api/posts/2/save in Postman (with PUT) I get an error message along the lines of No action was found on the controller 'Posts' that matches the name 'save'. Essentially a glorified 404.
If i change the route to be [Route("{id}/save")] the resulting error remains.
What am I doing incorrectly?
WebAPIConfig.cs
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}/{action}",
defaults: new { id = RouteParameter.Optional, action = RouteParameter.Optional, }
);
PostController.cs
// GET: api/Posts
public IHttpActionResult Get()
{
PostsStore store = new PostsStore();
var AsyncResult = store.GetPosts();
return Ok(AsyncResult);
}
// GET: api/Posts/5
public IHttpActionResult Get(string slug)
{
PostsStore store = new PostsStore();
var AsyncResult = store.GetBySlug(slug);
return Ok(AsyncResult);
}
// POST: api/Posts
public IHttpActionResult Post(Post post)
{
PostsStore store = new PostsStore();
ResponseResult AsyncResult = store.Create(post);
return Ok(AsyncResult);
}
// PUT: api/Posts/5 DELETED to make sure I wasn't hitting some sort of precedent issue.
//public IHttpActionResult Put(Post post)
// {
// return Ok();
//}
[HttpPut]
[Route("save")]
public IHttpActionResult Save(Post post)
{
PostsStore store = new PostsStore();
ResponseResult AsyncResponse = store.Save(post);
return Ok(AsyncResponse);
}
If using [Route] attribute then that is attribute routing as apposed to the convention-based routing that you configure. You would need to also enable attribute routing.
//WebAPIConfig.cs
// enable attribute routing
config.MapHttpAttributeRoutes();
//...add other convention-based routes
And also the route template would have to properly set.
//PostController.cs
[HttpPut]
[Route("api/posts/{id}/save")] // Matches PUT api/posts/2/save
public IHttpActionResult Save(int id, [FromBody]Post post) {
PostsStore store = new PostsStore();
ResponseResult AsyncResponse = store.Save(post);
return Ok(AsyncResponse);
}
Reference Attribute Routing in ASP.NET Web API 2
I'm trying to get this method to work:
public class DocumentenController : ApiController
{
[HttpPost]
[Route("DeleteDocument/{name}/{planId}")]
public IHttpActionResult DeleteDocument(string name, int planId)
{
_documentenProvider.DeleteDocument(planId, name);
return Ok();
}
}
This is the WebApiConfig :
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "ActionApi",
routeTemplate: UrlPrefix + "/{controller}/{action}/{id}",
defaults: new {id = RouteParameter.Optional}
);
But I get a 404 when I call it like this using a post:
http://localhost/QS-documenten/api/documenten/deletedocument/testing/10600349
What is the proper way do solve this?
The URL in example does not match attribute route on controller.
To get
http://localhost/QS-documenten/api/documenten/deletedocument/testing/10600349
to work, assuming that http://localhost/QS-documenten is the host and root folder, and that api/documenten is the api prefix then add a route prefix to the controller...
[RoutePrefix("api/Documenten")]
public class DocumentenController : ApiController {
//eg POST api/documenten/deletedocument/testing/10600349
[HttpPost]
[Route("DeleteDocument/{name}/{planId}")]
public IHttpActionResult DeleteDocument(string name, int planId) {
_documentenProvider.DeleteDocument(planId, name);
return Ok();
}
}
Source: Attribute Routing in ASP.NET Web API 2 : Route Prefixes
You must send your request as follows:
http://localhost/QS-documenten/deletedocument/testing/10600349
When you use route attribute, the custom route override default api routing configuration.
I am trying to post to the following Web API:
http://localhost:8543/api/login/authenticate
LoginApi (Web API) is defined below:
[RoutePrefix("login")]
public class LoginApi : ApiController
{
[HttpPost]
[Route("authenticate")]
public string Authenticate(LoginViewModel loginViewModel)
{
return "Hello World";
}
}
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 }
);
}
Here is the error I get:
Request URL:http://localhost:8543/api/login/authenticate
Request Method:POST
Status Code:404 Not Found
Remote Address:[::1]:8543
Your controller name "LoginApi" needs to end in "Controller" in order for the framework to find it. For example: "LoginController"
Here is a good article which explains routing in ASP.NET Web API: http://www.asp.net/web-api/overview/web-api-routing-and-actions/routing-in-aspnet-web-api
You are using login as your route prefix on your controller so trying to call
http://localhost:8543/api/login/authenticate
will not be found as this code
[RoutePrefix("login")]
public class LoginApi : ApiController
{
//eg:POST login/authenticate.
[HttpPost]
[Route("authenticate")]
public string Authenticate(LoginViewModel loginViewModel)
{
return "Hello World";
}
}
will only work for
http://localhost:8543/login/authenticate
You need to change your route prefix to
[RoutePrefix("api/login")]
public class LoginApi : ApiController
{
//eg:POST api/login/authenticate.
[HttpPost]
[Route("authenticate")]
public string Authenticate(LoginViewModel loginViewModel)
{
return "Hello World";
}
}
Notice you are using both attribute routing on the controller/action and convention routing with config.Routes.MapHttpRoute.
config.Routes.MapHttpRoute will map the routes as per your definition "api/{controller}/{id}".
While attribute routing, will map the routes based on how you've defined them: /login/authenticate.
Also, since you are using both attribute routing and convention routing, attribute routing takes presendence. I would stick to using one or the other. Having both adds a bit of confusion as to what route will be used to access an action method.
For my API, I want to be able to handle scenarios where the call is made using an incorrect URL (i.e. URL that does not match any controller or action.)
For this I have implemented routing so that it matches any route:
config.Routes.MapHttpRoute(
name: "CatchAll",
routeTemplate: "{*any}",
defaults: new { controller = "Error", action = "Handler" }
);
And I have implemented the controller - action as follows:
[Route("api/v1/Handler")]
[ActionName("Handler")]
public HttpResponseMessage Get() {...}
When I give an incorrect URL, I get the message:
No action was found on the controller 'Error' that matches the name 'Handler'
Not sure where the mistake is.
Simple approach:
You need to match the action name. So either rename Get to Handler in the ErrorController and remove attributes as they will conflict with conventions you mapped .
public HttpResponseMessage Handler(string any) {...}
or change action from Handler to Get in the Catch all MapHttpRoute
config.Routes.MapHttpRoute(
name: "CatchAll",
routeTemplate: "{*any}",
defaults: new { controller = "Error", action = "Get" }
);
Not so simple approach:
Here is how I handled the same thing in my web api using attribute routing and inheritance.
First I created a base api controller that will handler unknown actions.
public abstract class WebApiControllerBase : ApiController {
[Route("{*actionName}")]
[AcceptVerbs("GET", "POST", "PUT", "DELETE")]
[AllowAnonymous]
[ApiExplorerSettings(IgnoreApi = true)]
public virtual HttpResponseMessage HandleUnknownAction(string actionName) {
var status = HttpStatusCode.NotFound;
var message = "[Message placeholder]";
var content = new { message = message, status = status};
return Request.CreateResponse(status, content);
}
}
My Api controllers all inherit from this base controller.
[RoutePrefix("api/customers")]
public class CustomersApiController : WebApiControllerBase {...}
Given that your question included RouteAttribute you should already be using MapHttpAttributeRoutes in your web api config.
But there's more. To get the framework to recognize the inherited attributes you need to override the DefaultDirectRouteProvider as outlined here
and used in an answer here
WebAPI controller inheritance and attribute routing
public class WebApiCustomDirectRouteProvider : DefaultDirectRouteProvider {
protected override System.Collections.Generic.IReadOnlyList<IDirectRouteFactory>
GetActionRouteFactories(System.Web.Http.Controllers.HttpActionDescriptor actionDescriptor) {
// inherit route attributes decorated on base class controller's actions
return actionDescriptor.GetCustomAttributes<IDirectRouteFactory>(inherit: true);
}
}
and apply that to the web api configuration.
// Attribute routing. (with inheritance)
config.MapHttpAttributeRoutes(new WebApiCustomDirectRouteProvider());
Hope this helps
Refer to the official ASP.NET attribute routing documentation, it seems that Route attribute can be used without RoutePrefix.
But, in my webapi controller, below cases are happened.
1. Not working. (error: No matched http route found)
public class GroupController : ApiController
{
[Route("api/group/{id}/register")]
public IHttpActionResult Post(int id, InputModel model)
{
return Ok();
}
}
2. Working good.
[RoutePrefix("api/group")]
public class GroupController : ApiController
{
[Route("{id}/register")]
public IHttpActionResult Post(int id, InputModel model)
{
return Ok();
}
}
Is it right that Route attribute should be used with RoutePrefix, or what am I missing?
In addition, below code is my WebApi route config in WebApiConfig.Register class.
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}/{subId}",
defaults: new { id = RouteParameter.Optional, subId = RouteParameter.Optional }
);