What's the difference between [HttpGet] and [HttpGet("{id}")]? - asp.net

What are the differences between HTTPGET method and HTTPGET("{id}") method?
What is the API method that is used to update table columns?
[HttpGet]
public IActionResult Get()
{
return new JsonResult(users);
}
// GET api/values/5
[HttpGet("{id}")]
public IActionResult Get(string id)
{
return new JsonResult(response);
}

You should take a look at Attribute Routing in Web API.
The first method is routing to a clean api:
/api/controller
The second specifies route value in the attribute and will be called via the following url:
/api/controller/5
The second one is normally used to update existing queries, as you specify specific value in the route whilst the first specifies nothing.

Related

How to create a basic web api to get data

Trying to create a basic web api for my database table where anyone can view my table data using a URL (JSON format?). My understanding is that I should be able to get my data by typing in table name in URL.
my database table name is myTable which is mapped to model class My_Model
Issue: There are no errors but when i try to type in url https://localhost:7048/myTable/ it return page not found
[Route("[controller]")]
[ApiController]
public class My_Controller : Controller
{
public My_Services _services { get; }
public My_Controller(My_Services services)
{
this._services = services;
}
// Database Table Name = "myTable"
[HttpGet]
public IQueryable<My_Model> Get()
{
return (IQueryable<My_Model>)_services.Get_All_Data();
}
public IActionResult Index()
{
return View();
}
}
My_Services class - where get all data from table
public async Task<IQueryable<My_Model>> Get_All_Data()
{
IQueryable<My_Model> Query = from x in _context.My_DbSet
select x;
return Query;
}
My understanding is that I should be able to get my data by typing in
table name in URL.
No, this is not how it works. You should check Routing to controller actions in ASP.NET Core. In your example you should be able to access your data using this url: https://localhost:7048/My_. The reason is that your controller has the attribute [Route("[controller]")]. [controller] is a special value which means that the route should be the controller class name without the Controller suffix so My_ in this case.
If you want to have access using this url: https://localhost:7048/myTable then you need to either change the attribute to this: [Route("myTable")] or to change the controller class name to MyTableController.
Also your Get method looks wrong. You should await the _services.Get_All_Data method instead of casting to IQueryable<My_Model>:
[HttpGet]
public async Task<IQueryable<My_Model>> Get()
{
return await _services.Get_All_Data();
}

Multiple Get methods in Rest API controller

Hello I have added an extra get method in a API controller.
original Get
[HttpGet]
[Route("GetParticipants")]
public IActionResult GetParticipants([FromQuery] Guid conversationId, [FromQuery] ContextServiceModel context)
{
... stuff ...
}
New Get
[HttpGet]
[Route("GetThreadParticipants")]
public IActionResult ThreadParticipants([FromQuery] Guid parentMessageId)
{
... stuff ...
}
My question is does this follow Rest? Is it okay to route them this way and have different parameters?
You can have as many Action methods as you want in your controller until and unless no action methods have same routes.
Routing
Conventional Routing
Defined in WebAPI.config
Attribute Routing
Directly defined on action method
More on attribute routing
Attribute routing Web API's

Route all Web API requests to one controller method

Is it possible to customize ASP.NET Web API's routing mechanism to route all requests to the API to one controller method?
If a request comes in to
www.mysite.com/api/products/
or
www.mysite.com/api/otherResource/7
All would be routed to my SuperDuperController's Get() method?
I ran into a case where I needed to do this. (Web API 2)
I first looked into creating custom IHttpControllerSelector and IHttpActionSelectors. However, that was a bit of a murky way around. So I finally settled on this dead simple implementation. All you have to do is setup a wildcard route. Example:
public class SuperDuperController : ApiController
{
[Route("api/{*url}")]
public HttpResponseMessage Get()
{
// url information
Request.RequestUri
// route values, including "url"
Request.GetRouteData().Values
}
}
Any GET request that starts with "api/" will get routed to the above method. That includes the above mentioned URLs in your question. You will have to dig out information from the Request or context objects yourself since this circumvents automatic route value and model parsing.
The good thing about this is you can still use other controllers as well (as long as their routes don't start with "api/").
I don't konw why you would want to do this and I certainly wouldn't recommend routing everything through one controller, however you could achieve this as follows. Assuming you are only ever going to have a resource with an optional id in your calls, add this to your WebApiConfig:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{resource}/{id}",
defaults: new { controller = "SuperDuper", id = RouteParameter.Optional }
);
}
}
Then define your controller method as follows:
public class SuperDuperController : ApiController
{
public IHttpActionResult Get(string resource, int? id = null)
{
return Ok();
}
}
You would need to decide on an appropriate IHttpActionResult to return for each different type of resource.
Alternatively using Attribute Routing, ensure that config.MapHttpAttributeRoutes() is present in your WebApiConfig and add the following attributes to your controller method:
[RoutePrefix("api")]
public class SuperDuperController : ApiController
{
[Route("{resource}/{id?}")]
public IHttpActionResult Get(string resource, int? id = null)
{
return Ok();
}
}

Attribute Routing failing - Web Api

I have two actions on a controller called JobController that has this Route Prefix
[RoutePrefix("API/Job")]
1st Action (In order of precedence in controller)
[Route("{jobId}/{user}"), System.Web.Http.HttpPost]
public HttpResponseMessage AssignUser(long jobId, string user)
2nd Action
[HttpPost]
[Route("{id}/comment/")]
public HttpResponseMessage SaveComment(string commentText, long id)
Doing a post with Postman to this Route - MyDomain/API/Job/11/Comment - with a commentText value of "foo" matches against the first route, not the one i want it to.
Any ideas why this is happening?
Only guessing, but I think WebAPI cannot distinguish between route 1 and 2 because "comment" could also be a user-name. You could change the first route to something like:
[Route("{jobId}/users/{user}"), System.Web.Http.HttpPost]
public HttpResponseMessage AssignUser(long jobId, string user)
The problem here, is that both actions have the same action (POST), the same number of parameters and same type for these parameters, so which comes first that matches the route will win.
Your route need to have something unique distinguish between the two routes, so you need to change your routes to either have different actions (POST vs PUT for example) or you change one route to be something like this
[HttpPost]
[Route("{id}/comments/{comment}")]
public HttpResponseMessage SaveComment(long id, string comment)
hope this helps.
In the end I just created separate ViewModels
[HttpPost]
[Route("comment")]
public HttpResponseMessage SaveComment([FromBody] JobCommentViewModel viewModel)
public class JobCommentViewModel
{
public long JobId { get; set; }
public string Comment { get; set; }
}

Ambigous Routes Using ASP.Net MVC

So far I still have the standard routing. What I tried to do is
public Foo : Controller
{
public ActionResult Index(int id)
{
return View("List", repo.GetForId(id));
}
public ActionResult Index()
{
return View("List", repo.GetAll());
}
}
The URL I entered was
localhost/Foo/Index.
I was under the asumption that it was smart enough to figure out which method I wanted. All I get though is an error telling me that the call is ambigous. From reading the route tutorial I thought that this would work. What am I missing?
Sorry:
Duplicate. I am voting to close.
Method overloading (two actions with the same name) resolution is based on the HTTP verb. This means that if you want to have two actions with the same name you need to differentiate them by the HTTP verb they accept:
public ActionResult Index(int id)
{
return View("List", repo.GetForId(id));
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Index()
{
return View("List", repo.GetAll());
}
Thus when you call GET /Home/Index the first action will be invoked and when you call POST /Home/Index the second one will be invoked.
Also note that you should probably use nullable integer as the id argument because if no parameter is passed in the request, the model binder will fail.
A RESTful way to handle this, following conventions that I would suggest you is this:
public ActionResult Index()
{
return View(repo.GetAll());
}
public ActionResult Show(int id)
{
return View(repo.GetForId(id));
}
which will allow you to handle both /Home/Index and /Home/Show/10 requests. You probably will have different views as well because the first one will be strongly typed to IEnumerable<T> while the second one to T.

Resources