I would like to register API Endpoints in ASP.NET by just adding few methods in ApiController. A new method there means a new API.
In a random example below:
public class ProductController : ApiController
needs to serve the following Endpoints:
/
/price
/price/discount
Problem here is all endpoints are having a GET request to /, and result in same output as /.
Reference URL and Service Contract
You can place Route annotation at method for which you want to use custom route.
public class CustomersController : ApiController
{
// this will be called on GET /Customers or api/Customers can't remember what default
//config is
public List<Customer> GetCustomers()
{
...
}
// this will be called on GET /My/Route/Customers
[HttpGet, Route("My/Route/Customers)]
public List<Customer> GetCustomersFromMyRoute()
{
...
}
}
Related
i am new to webapi and MVC in general. If I wanted to group my service URLs like this
/api/account/create
/api/account/login
/api/account/resetpass
Am I able to put all 3 method calls in the same controller file and somehow map a particular request to the right method?
Create a Controller named Account and Create 3 [GET, POST, PUT, DELETE] method and name them create , login ,resetpass.
By Default, this is the routing for MVC / API(Id can be optional)
route Template: "api/{controller}/{id}",
Example :
public class AccountController : ApiController
{
[HttpPost]
public string Create()
{
// CODE
}
[HttpPost] // or [HttpGet]
public string Login ()
{
// CODE
}
[HttpPost]
public string Resetpass()
{
// CODE
}
}
if you had trouble calling them, try to give them a specific route :
[HttpGet("GetSubject/{subject}")]
public int GetSubjectId(String subject)
{
//CODE
}
Please if you get any error or misunderstanding, don't hesitate to post a comment
In my spring boot project i wanted to do a redirection from http://localhost:8080 to http://localhost:8080/birdspotting. This is the code of the Home controller:
#RestController
public class HomeController {
#GetMapping("/")
public String showHomePage() {
return "redirect:/birdspotting";
}
}
The result of going to http://localhost:8080 is a print of redirect:/birdspotting
Basically RestController = Controller + RequestBody
Which will send json response but we are expecting view resolver to return the page or redirect url.
So use #Controller instead of #RestController to fix the issue.
Update:
If you want to use both in Same controller then use #Controller on class level and then wherever you want to return API call response put #ResponseBody on method and wherever you want to return web browser page don't put #ResponseBody.
You have to create the other endpoint like:
#GetMapping("/")
public String showHomePage() {
return "redirect:/birdspotting";
}
#GetMapping("/birdspotting")
public String birdspottingPage() {
return "birdspotting";
}
It's expect you have birdspotting.html in your templates.
I am using .NET Core 2.2 and I have the controller below
[Route("api/[controller]")]
[ApiController]
public class CarsController : ControllerBase
{
[HttpPost]
[Route("api/cars/search")]
[ActionName("search")]
public ActionResult<IEnumerable<string>> SearchForCar([FromBody] SearchCriteria searchCriteria)
{
return new string[] { "value1", "value2" };
}
}
I am new to pure web api controllers.
I am confused about why when I post json to
http://localhost:51285/api/cars/search
I get 405 method not allowed?
I would normally have a route of
[Route("api/[controller]/action")]
That does work (once I remove route from the method attributes), but this wasn't the default provided in the template
Could someone let me know what I am missing?
Am I breaking convention by changing to
[Route("api/[controller]/[action]")]
Cheers
Paul
Since you not using the root slash in your action "/", the MVC middleware will search concatenating the route for controller and the action, should work like this
[Route("/api/[controller]/[action]")] // Check the root slash as first character
public ActionResult<IEnumerable<string>> SearchForCar([FromBody]
SearchCriteria searchCriteria)
Or like this
[Route("api/[controller]/[action]")] [ApiController] public class
CarsController : ControllerBase
Or
In controller:
[Route("api/[controller]")] [ApiController] public class
CarsController : ControllerBase
In action:
[Route("search")] // [action] Takes the method name
public <ActionResult<IEnumerable<string>>
SearchForCar([FromBody] SearchCriteria searchCriteria)
I have web api controller that has multiple post methods with the same name but with different parameters; when i run the application, i got an error:-
Multiple actions were found that match the request
note:- I don't want to use Action Routing as i want to unify my clients who use my web api
public Customer Post(Customer customer)
{
}
public Product Post(Product product)
{
}
The problem is that there's no way to distinguish between those two Post methods based on the URL that's getting passed to the web api.
The way to handle this would be to use a separate controller. One controller would be "api/Customer" and would have Post method that takes a Customer:
public class CustomerController : ApiController
{
public Customer Post(Customer customer) { }
}
The other would be "api/Product" and take a Product:
public class ProductController : ApiController
{
public Product Post(Product product) { }
}
If you really really wanted to pass both into one controller, you could create a class that has all the properties of both Customer and Product, and then look at the properties to figure out what just got passed into your controller. But... yuck.
public class EvilController : ApiController
{
public ProductOrCustomer Post(ProductOrCustomer whoKnows)
{
// Do stuff to figure out if whoKnows has
// Product properties or Customer properties
}
}
You could use a single controller, with a single method taking a parameter of an interface type that both classes implement. Then call private handlers based on runtime type.
I am playing around with the idea of having a base controller that uses a generic repository to provide the basic CRUD methods for my API controllers so that I don't have to duplicate the same basic code in each new controller. But am running into problems with the routing attribute being recognized when it's in the base controller. To show exactly what the problem I'm having I've created a really simple WebAPI controller.
When I have a Get method in the main Controller and it inherits from the ApiController directly I don't have any problems and this works as expected.
[RoutePrefix("admin/test")]
public class TestController : ApiController
{
[Route("{id:int:min(1)}")]
public string Get(int id)
{
return "Success";
}
}
When I move the Get method into a base controller it is returning the contents of the 404 page.
[RoutePrefix("admin/test")]
public class TestController : TestBaseController
{
}
public class TestBaseController : ApiController
{
[Route("{id:int:min(1)}")]
public string Get(int id)
{
return "Success";
}
}
Some more interesting notes:
I can access the action at GET /Test/1. So it is finding it based on the default route still.
When I try to access POST /admin/test, it returns the following JSON
{
"Message":"No HTTP resource was found that matches the request URI 'http://test.com/admin/test'.",
"MessageDetail":"No type was found that matches the controller named 'admin'."
}
Does anyone know of a way to get the routing to work with attributes from a base controller?
Attribute routes cannot be inherited. This was a deliberate design decision. We didn't feel right and didn't see valid scenarios where it would make sense to inherit them.
Could you give a more realistic scenario as to where you would want to use this?
[Update(3/24/2014)]
In the upcoming 5.2 release of MVC Web API, there is going to be an extensibility point called System.Web.Http.Routing.IDirectRouteProvider through which you can enable the inheritance scenario that you are looking for here. You could try this yourself using the latest night builds(documentation on how to use night builds is here)
[Update(7/31/2014)]
Example of how this can be done in Web API 2.2 release:
config.MapHttpAttributeRoutes(new CustomDirectRouteProvider());
//---------
public class CustomDirectRouteProvider : DefaultDirectRouteProvider
{
protected override IReadOnlyList<IDirectRouteFactory>
GetActionRouteFactories(HttpActionDescriptor actionDescriptor)
{
// inherit route attributes decorated on base class controller's actions
return actionDescriptor.GetCustomAttributes<IDirectRouteFactory>
(inherit: true);
}
}
Using Web API 2.2, you can:
public class BaseController : ApiController
{
[Route("{id:int}")]
public string Get(int id)
{
return "Success:" + id;
}
}
[RoutePrefix("api/values")]
public class ValuesController : BaseController
{
}
config.MapHttpAttributeRoutes(new CustomDirectRouteProvider());
public class CustomDirectRouteProvider : DefaultDirectRouteProvider
{
protected override IReadOnlyList<IDirectRouteFactory>
GetActionRouteFactories(HttpActionDescriptor actionDescriptor)
{
return actionDescriptor.GetCustomAttributes<IDirectRouteFactory>
(inherit: true);
}
}
as outlined here: http://www.asp.net/web-api/overview/releases/whats-new-in-aspnet-web-api-22
Got it.
[Route("api/baseuploader/{action}")]
public abstract class BaseUploaderController : ApiController
{
[HttpGet]
public string UploadFile()
{
return "UploadFile";
}
}
[Route("api/values/{action}")]
public class ValuesController : BaseUploaderController
{
[HttpGet]
public string Get(int id)
{
return "value";
}
}
One caveat here is that the route action paramter must be the same as the action name. I could not find a way to get around that. (You cannot rename the route with a RouteAttribute)