Hello i am working on asp.net core 2.2 web api , my get request is working fine but i am having problem in HTTPDELETE request, my code for the delete request is as follows
[Route("api/[controller]")]
[ApiController]
public class PatientController : ControllerBase
{
IPatientManager _patientManager;
IEnumerable<Patient> patientList;
public PatientController(IPatientManager patientManager)
{
_patientManager = patientManager;
}
[HttpGet]
public IEnumerable<Patient> Get()
{
return (patientList = _patientManager.GetAllPatients());
}
// DELETE api/values/5
[HttpDelete("api/Patient/{id}")]
public bool Delete(long id)
{
if (_patientManager.DeletePatient(id))
return true;
else
return false;
}
}
}
when i put the request in URL as localhost:3, n922/api/Patient/444373 it gives me HTTP ERROR 404 , my startup.cs file is using the below code for MapRoute
app.UseMvc(opt =>
{
opt.MapRoute("Default",
"{controller=Patient}/{action=Get}/{id?}");
});
to start the my PatientController instead of ValuesController, Please help what is problem where i am doing wrong? TIA
You have a route prefix defined on your controller as api/[controller], which translates to /api/Patient. Then, your route on your action is defined as api/Patient/{id}, which makes the entire route to this action: /api/Patient/api/Patient/{id}. That's obviously not right and is the source of your 404. Change the route to just {id}.
[HttpDelete("{id}")]
public bool Delete(long id)
Related
I remember from ASP.NET Web API that it's sufficient to prefix Web API REST method names with HTTP commands (e.g. GetList() => HTTP GET, Delete() => HTTP DELETE) to have incoming calls appropriately routed.
I also remember that in ASP.NET Web API parameter matching takes place so that even Get(int id) and Get(int id, string name) get automatically and appropriately routed without requiring any attributes.
public class MyController
{
public ActionResult Get(int id) => ...
public ActionResult Get(int id, string name) => ...
public ActionResult DeleteItem(int id) => ...
}
Isn't this all available in ASP.NET Web API Core?
You just need to add the Route to the top of your controller.
Specify the route with api, controller and action:
[Route("api/[controller]/[action]")]
[ApiController]
public class AvailableRoomsController : ControllerBase
{
...
}
Neither could we do action overloads nor prefix action name as Http verb.The way routing works in ASP.NET Core is different than how it did in ASP.NET Web Api.
However, you can simply combine these actions and then branch inside, since all params are optional if you send as querystring
[HttpGet]
public ActionResult<string> Get(int id, string name)
{
if(name == null){..}
else{...}
}
Or you need to use attribute routing to specify each api if you send in route data:
[HttpGet("{id}")]
public ActionResult<string> Get(int id)
{
return "value";
}
[HttpGet("{id}/{name}")]
public ActionResult<string> Get(int id, string name)
{
return name;
}
Refer to Attribute Routing,Web Api Core 2 distinguishing GETs
The aspnetcore webapi controllers do not natively support inference of http verbs by naming convention, but allow you to create your own convention and achieve this behavior.
Create your convention
public class MyConvention : IApplicationModelConvention
{
public void Apply(ApplicationModel application)
{
foreach(var controller in application.Controllers)
{
foreach(var action in controller.Actions)
{
if (action.ActionName.StartsWith("Post"))
{
action.Selectors.First().ActionConstraints.Add(new HttpMethodActionConstraint(new[]{ "POST" }));
}
}
}
}
}
Then register it in Program/Startup:
builder.Services.AddControllers(configure => configure.Conventions.Insert(0, new MyConvention()));
This is available for Core 2 yes, but the way that I know how to do it is something like this
[Route("api/[controller]")]
[ApiController]
public class AvailableRoomsController : ControllerBase
{
private readonly ApplicationContext _context;
public AvailableRoomsController(ApplicationContext context)
{
_context = context;
}
// GET: api/AvailableRooms
[HttpGet]
public async Task<ActionResult<IEnumerable<AvailableRoom>>> GetAvailableRooms()
{
return await _context.AvailableRooms.ToListAsync();
}
// POST: api/AvailableRooms
[HttpPost]
public async Task<ActionResult<AvailableRoom>> PostAvailableRoom(AvailableRoom availableRoom)
{
_context.AvailableRooms.Add(availableRoom);
await _context.SaveChangesAsync();
return CreatedAtAction("GetAvailableRoom", new { id = availableRoom.Id }, availableRoom);
}
[HttpPut] .... etc
}
Now depending on what kind of REST action you specify and what type of model you send to "api/AvailableRooms" if the proper Action exists it will be chosen.
Visual Studio 2019 and I think 2017 can create a controller such as this automatically if you right click your Controllers folder and click Add->Controller and then choose "API Controller with actions, using Entity Framework" and choose one of your Model classes.
What I basically want to know is this:
Suppose I have a method annotated with #RequestMapping and the value "/test/ajax". Can I make that specific method accessible only to internal calls but not to the client? If I run an ajax request on that url from within the server it should work normally, but if I run it directly from the browser it should return a 403.
Is that in any way possible?
add the spring annotation #CrossOrigin on controller layer for example
also, follow the given link https://spring.io/blog/2015/06/08/cors-support-in-spring-framework
#CrossOrigin
#RestController
#RequestMapping("/account")
public class AccountController {
#GetMapping("/{id}")
public Account retrieve(#PathVariable Long id) {
// ...
}
#DeleteMapping("/{id}")
public void remove(#PathVariable Long id) {
// ...
}
}
If you allow only a method pass like this
#RestController
#RequestMapping("/account")
public class AccountController {
#CrossOrigin
#GetMapping("/{id}")
public Account retrieve(#PathVariable Long id) {
// ...
}
#DeleteMapping("/{id}")
public void remove(#PathVariable Long id) {
// ...
}
}
I have created an ASP.Net MVC project with WebApi option. Then modified the values controller with the code below:
public class ValuesController : ApiController
{
static List<string> data = initList();
private static List<string> initList()
{
var ret = new List<string>();
ret.Add("value1");
ret.Add( "value2" );
return ret;
}
// GET api/values
public IEnumerable<string> Get()
{
return data ;
}
// GET api/values/5
public string Get(int id)
{
return data[id];
}
// POST api/values
public void Post([FromBody]string value)
{
data.Add(value);
}
// PUT api/values/5
public void Put(int id, [FromBody]string value)
{
data[id] = value;
}
// DELETE api/values/5
public void Delete(int id)
{
data.RemoveAt(id);
}
}
When I am running the project and navigating to API/values URL, the following image is showing error.
.
The error description in text is:
<Error>
Authorization has been denied for this request.
</Error>
Have a look at the following article about
Authentication and Authorization in ASP.NET Web API
It will explain the different ways of how to use the [Authorize] and [AllowAnonymous] attribute on your controller/actions and any configurations you would need to do.
The following was taken from the linked article above:
Using the [Authorize] Attribute
Web API provides a built-in authorization filter,
AuthorizeAttribute. This filter checks whether the user is
authenticated. If not, it returns HTTP status code 401 (Unauthorized),
without invoking the action.
You can apply the filter globally, at the controller level, or at the
level of inidivual actions.
Globally: To restrict access for every Web API controller, add the
AuthorizeAttribute filter to the global filter list:
public static void Register(HttpConfiguration config){
config.Filters.Add(new AuthorizeAttribute());
}
Controller: To restrict access for a specific controller, add the
filter as an attribute to the controller:
// Require authorization for all actions on the controller.
[Authorize]
public class ValuesController : ApiController
{
public HttpResponseMessage Get(int id) { ... }
public HttpResponseMessage Post() { ... }
}
Action: To restrict access for specific actions, add the attribute to
the action method:
public class ValuesController : ApiController
{
public HttpResponseMessage Get() { ... }
// Require authorization for a specific action.
[Authorize]
public HttpResponseMessage Post() { ... }
}
Alternatively, you can restrict the controller and then allow
anonymous access to specific actions, by using the [AllowAnonymous]
attribute. In the following example, the Post method is restricted,
but the Get method allows anonymous access.
[Authorize]
public class ValuesController : ApiController {
[AllowAnonymous]
public HttpResponseMessage Get() { ... }
public HttpResponseMessage Post() { ... }
}
In the previous examples, the filter allows any authenticated user to
access the restricted methods; only anonymous users are kept out. You
can also limit access to specific users or to users in specific roles:
// Restrict by user:
[Authorize(Users="Alice,Bob")]
public class ValuesController : ApiController
{
}
// Restrict by role:
[Authorize(Roles="Administrators")]
public class ValuesController : ApiController
{
}
So, I've been dealing with this error for awhile.
I didn't understand it at first, so I just removed and lived with it.
I finally got sick of it, because it's rather stupid. Microsoft wants a user to be authorized before they have signed in.
My error was looking for GET method which asks for HomeTown. In my case, I had changed it to CityCode.
Since the user is not logged in, there is no CityCode to GET. So, you get either a 402 or a 500 Resource Not Found.
I still don't understand it so, I gave CityCode some default data. So, from MeController I put the following code:
Public Function [Get]() As GetViewModel
Dim userInfo As ApplicationUser = UserManager.FindById(User.Identity.GetUserId())
Return New GetViewModel() With {.CityCode = "94110"}
End Function
App loads completely error free now.
This is a quick fix, not a certified solution.
Why does the third route fail in my Web API ?
public class StudentCourseController : ApiController
{
// GET api/student
public IEnumerable<StudentCourse> Get()
{
return StudentCourseRepository.GetAll();
}
// GET api/student/5
public StudentCourse Get(int id)
{
return StudentCourseRepository.GetAll().FirstOrDefault(s => s.Id == id);
}
[Route("StudentAuto/{key}")] // Does not work
public IEnumerable<Student> StudentAuto(string key)
{
return StudentRepository.GetStudentsAuto(key);
}
When i request http://localhost:5198/api/StudentCourse/StudentAuto/mi I get a 404 error.
The detail error shows
Requested URL http://localhost:5198/api/StudentCourse/StudentAuto/mi
Physical Path C:\Users\deb\Desktop\StudentKO\KnockoutMVC\KnockoutMVC\api\StudentCourse\StudentAuto\mi
Logon Method Anonymous
Logon User Anonymous
Did i miss anything ?
thanks
Attribute routing on a method does not work in conjunction with the route constraints for the controller you put into your startup, e.g. "/api/{controller}".
Therefore your [Route("StudentAuto/{key}")] route literally maps to "/StudentAuto/{key}", not "/api/StudentCourse/StudentAuto/{key}".
You can get this to work as you want by adding a [RoutePrefix] (see msdn) to your controller:
[RoutePrefix("api/StudentCourse")]
public class StudentCourseController : ApiController
{
}
Alternatively just set the whole path in your Route attribute:
[Route("api/StudentCourse/StudentAuto/{key}")]
public IEnumerable<Student> StudentAuto(string key)
{
return StudentRepository.GetStudentsAuto(key);
}
I'm using asp.net mvc 4 and web api. My route is like this:
/api/{controller}/jqGrid/{action}/{id}
for example, if the route is :
/api/User/jqGrid/List
I hope it will route to the action name "jqGrid_List" of the User controller.
How can I achieve this?
hmm, I don't know if it's acceptable to answer my own question. I found out a solution.
First of all, I need to add a JqGridControllerConfiguration attribute to replace the default action selector applied to the controller with my one.
[JqGridControllerConfiguration]
public class UserController : ApiController
{
// GET: /api/User/jqGrid/List
[HttpGet]
public JqGridModel<User> jqGrid_List()
{
JqGridModel<User> result = new JqGridModel<User>();
result.rows = Get();
return result;
}
}
Here's the code of JqGridControllerConfiguration:
public class JqGridControllerConfiguration : Attribute, IControllerConfiguration
{
public void Initialize(HttpControllerSettings controllerSettings, HttpControllerDescriptor controllerDescriptor)
{
controllerSettings.Services.Replace(typeof(IHttpActionSelector), new JqGridActionSelector());
}
}
in JqGridActionSelector, the "action" is modified if a "jqGrid/" exists in the request URL.
public class JqGridActionSelector : ApiControllerActionSelector
{
public override HttpActionDescriptor SelectAction(HttpControllerContext controllerContext)
{
Uri url = controllerContext.Request.RequestUri;
if (url.Segments.Any(s => string.Compare(s, "jqGrid/", true) == 0))
{
controllerContext.RouteData.Values["action"] = "jqGrid_" + controllerContext.RouteData.Values["action"].ToString();
}
return base.SelectAction(controllerContext);
}
}
Not sure why you'd want to do this. But you can still create a "jqGrid_List" action in your User controller and set an ActionName for it, and it'll work.
UserController:
[HttpGet, ActionName("List")]
public string jqGrid_List()
{
return "WORKS";
}
Your Route:
routeTemplate: "api/{controller}/jqGrid/{action}/{id}"