I tried to call the update web api on Postman but it seems that it doesn't pass the id param to the asp.net core controller (asp.net core 2.0)
public class ShoppingCartController : BaseController
{
[HttpPut("{id}")]
[Route("api/ShoppingCart/UpdateShoppingCartItem")]
public IActionResult UpdateShoppingCartItem(long id)
{
return new NoContentResult();
}
}
You have to use [FromBody].
[HttpPut("{id}")]
[Route("api/ShoppingCart/UpdateShoppingCartItem")]
public IActionResult UpdateShoppingCartItem([FromBody]long id)
{
return new NoContentResult();
}
In Postman you must use a simple number.
Replace:
{
"id":87908908
}
with
87908908
Default behaviour of param parsing: From Url.
Use [FromBody] before your method param to let asp parse this param from the Body.
Can you try changing method UpdateShoppingCartItem to the following:
public IActionResult UpdateShoppingCartItem([FromBody] long id)
HttpPut now accepts the route as parameter, so you can combine your attributes.
public class ShoppingCartController : BaseController
{
[HttpPut("api/ShoppingCart/UpdateShoppingCartItem")]
public IActionResult UpdateShoppingCartItem(long id)
{
return new NoContentResult();
}
}
The model binder should infer the value of id from the body.
Using [HttpPut("{id}")] would mean that a put request to localhost:44342/65465 would be a valid action.
Related
I am coming from a heavy Java/Spring background and trying to transition some knowledge over to ASP.NET Core 6.
In Spring, on a RestController, I am able to route the request based on the presence of a query parameter.
So a HttpRequest with the uri: /students?firstName=Kevin can be routed to a different controller method than a HttpRequest with the uri: /students.
In ASP.NET Core 6, I am unable to determine if the equivalent is possible after working through some examples and reading the documentation for Web API.
Here is what I am trying to achieve, is this possible using two methods and routing configuration that will discern which controller method to invoke based on the query parameter?
[ApiController]
[Route("Students")]
public class StudentHomeProfileController : ControllerBase
{
[HttpGet] //Route here when no parameters provided
public async Task<ActionResult<IEnumerable<Student>>> GetStudentAsync()
{
/* Code omitted */
}
[HttpGet] //Route here when firstName query param provided
public async Task<ActionResult<IEnumerable<Student>>> SearchStudentAsync([FromQuery] string firstName)
{
/* Code omitted */
}
}
While filtering by query parameters does not come with ASP.NET Core out of the box, it's not too hard to supply this functionality on your own.
When it comes to extensibility, ASP.NET has some superpowers, one of them is IActionConstraint, which
Supports conditional logic to determine whether or not an associated action is valid to be selected for the given request. (Source)
Creating an annotation to filter for query parameters is as easy as
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class QueryParameterConstraintAttribute : Attribute, IActionConstraint
{
private readonly string _parameterName;
public QueryParameterConstraintAttribute(string parameterName)
{
this._parameterName = parameterName;
}
public bool Accept(ActionConstraintContext context)
{
return context.RouteContext.HttpContext.Request.Query.Keys.Contains(this._parameterName);
}
public int Order { get; }
}
All that's left is annotating your controller method with that constraint
[HttpGet] //Route here when firstName query param provided
[QueryParameterConstraint("firstName")]
public async Task<ActionResult<IEnumerable<Student>>> SearchStudentAsync([FromQuery] string firstName)
{
/* Code omitted */
}
In a quick test I was able to confirm that it seems to work as intended, even if you add multiple of those attributes for different query parameters (if all conditions match, the route is called).
(Please note, this was tested with .NET Core 2.1. Anyway, it shuold be pretty much the same with .NET 6)
I think you are looking for something like this, you need to specify the parameter in the "HttpGet" attribute
https://learn.microsoft.com/en-us/aspnet/core/mvc/controllers/routing?view=aspnetcore-6.0#attribute-routing-with-http-verb-attributes
[Route("api/[controller]")]
[ApiController]
public class Test2Controller : ControllerBase
{
[HttpGet] // GET /api/test2
public IActionResult ListProducts()
{
return ControllerContext.MyDisplayRouteInfo();
}
[HttpGet("{id}")] // GET /api/test2/xyz
public IActionResult GetProduct(string id)
{
return ControllerContext.MyDisplayRouteInfo(id);
}
[HttpGet("int/{id:int}")] // GET /api/test2/int/3
public IActionResult GetIntProduct(int id)
{
return ControllerContext.MyDisplayRouteInfo(id);
}
[HttpGet("int2/{id}")] // GET /api/test2/int2/3
public IActionResult GetInt2Product(int id)
{
return ControllerContext.MyDisplayRouteInfo(id);
}
}
You are trying to differentiate API calls using query params. this is not the way to do this. if you want to separate the calls you should probably use path params instead.
Read more about Routing in ASP.NET Core - https://learn.microsoft.com/en-us/aspnet/core/fundamentals/routing?view=aspnetcore-6.0
As far as I can understand, the conventional routing in .NET Core MVC is [controller]/[action]/{id?}
However, I have the following POST request I'm trying to catch which looks like this:
myDomain/MyController/MyAction/userID/anotherID/myInfo
I have tried the following, but it doesn't seem to be working:
public class MyController : Controller
{
[HTTPPost]
[Route("MyAction/{userID:minlength(2)}/{anotherID:int}/myInfo")]
public IActionResult MyAction([FromRoute] string userID, [FromRoute] int anotherID, [FromBody] string stuffIWant)
{
return Ok();
}
}
Obviously I'm not handling the routing correctly, but I'm not sure how I would get userID and anotherID from that route. I've published this action to my site, and tried to do a test post with the same URL, but didn't get a response.
Change to:
public class MyController : Controller
{
[HTTPPost]
[Route("MyAction/{userID:minlength(2)}/{anotherID:int}/myInfo")]
public IActionResult MyAction(string userID, int anotherID, [FromBody] string stuffIWant)
{
return Ok();
}
}
I have two projects, one is SPA and the other one is ASP.NET aspx project.
Normally those two projects communicate with each other via web API.
There is a running method like this (from SPA to ASP.NET)
[HttpPost]
[Route("DenyInvoice/{approvalId:long}")]
public IHttpActionResult DenyInvoice(long approvalId)
{
string exMsg = "";
if (DenyInvoice(approvalId, this.UserId, this.Email, out exMsg))
return Ok();
return BadRequest(exMsg);
}
This method works as I wanted, but I want to write a method that accepts a DTO variable like;
[HttpPost]
[Route("InvoiceDetailUpdate/{invoices : invoiceDetailDtoModel}")]
public IHttpActionResult InvoiceDetailUpdate(invoices : invoiceDetailDtoModel)
{
....
}
Is it possible? How should I do this?
Can you help?
Thank you..
Use [FromBody] to pass in the POST parameter. See https://learn.microsoft.com/en-us/aspnet/core/tutorials/first-web-api#implement-the-other-crud-operations for more details.
[HttpPost]
[Route("InvoiceDetailUpdate")]
public IHttpActionResult InvoiceDetailUpdate([FromBody]InvoiceDetailDtoModel invoices)
{
....
}
You want to retrieve parameter via post so there is no required for get parameter routing.
[HttpPost]
[Route("InvoiceDetailUpdate")]
public IHttpActionResult InvoiceDetailUpdate(InvoiceDetailDtoModel invoices)
{
....
}
Also, be careful with the name convention of a class.
In the following code, you can use like this :
public class BooksController : ApiController
{
[Route("api/books")]
public IEnumerable<Book> GetBooks() { ... }
[Route("api/books/{id:int}")]
public Book GetBook(int id) { ... }
[Route("api/books")]
[HttpPost]
public HttpResponseMessage CreateBook(Book book) { ... }
}
Now , you can see this link attribute-routing-in-web-api-2
and change your code to above figure
[Route("api/YourController/InvoiceDetails")]
public IHttpActionResult InvoiceDetailUpdate(InvoiceDetails invoiceDetailsDto)
Is it possible to achieve url parameter and attribute based versioning with same Controller methods. To explain that, suppose I have one controller like,
[RoutePrefix("api/{apiVersion:apiVersionConstraint(v2)}/values")]
public class ValuesController : ApiController
{
// GET api/v2/values
[Route("")]
public IEnumerable<string> Get()
{
return new string[] { "v2-value1", "v2-value2" };
}
// GET api/v2/values/5
[Route("{id}")]
public string Get(int id)
{
return "v2-value-" + id;
}
}
Now, I want to access the API endpoint by both of the following URL's:
http://hostname/context/api/v1/values
http://hostname/context/api/values?v=1
Is it possible?
N.B. I'm using the example at WebApiNamespaceVersion in GitHub
I am doing a Web API 2 application and I have controller named NCT_ProcessSettings and already I have two GET methods as below.
1. public IEnumerable<Process_Settings> Get()
2. public HttpResponseMessage Get(int id)
Now I want to have third one as below (Same as first one but inside I will write different logic).
3. public IEnumerable<Process_Settings> Get() //Compiler will confuse which to pick?
I tried as below.
[HttpGet]
[Route("GetGlobalSettings")]
public IEnumerable<NCT_Process_Settings> GetGlobalSettings()
{
return entityObject.NCT_Process_Settings.Where(c => c.project_id == 0).ToList();
}
Below is my angularcode to call api.
var url = '/api/NCT_ProcessSettings/GetGlobalSettings';
May I have some idea how to fix this? Any help would be appreciated?
Enable attribute routing in WebApiConfig.cs before convention-based routes.
config.MapHttpAttributeRoutes();
Next update controller to use routing attributes. (note the route prefix)
[RoutePrefix("api/NCT_ProcessSettings")]
public class NCT_ProcessSettingsController : ApiController {
//GET api/NCT_ProcessSettings
[HttpGet]
[Route("")]
public IEnumerable<Process_Settings> Get() { ... }
//GET api/NCT_ProcessSettings/5
[HttpGet]
[Route("{id:int}")]
public HttpResponseMessage Get(int id) { ... }
//GET api/NCT_ProcessSettings/GetGlobalSettings
[HttpGet]
[Route("GetGlobalSettings")]
public IEnumerable<NCT_Process_Settings> GetGlobalSettings() { ... }
}
Read up more documentation here Attribute Routing in ASP.NET Web API 2
Used Action Name attribute
[ActionName("Get")]
public IEnumerable<Process_Settings> Get1()//used any name here
{
}