Reputation: 75
I would like to restrict my Web API endpoints to certain HTTP methods, such as GET and POST. I have searched the internet and I found out that you can add either [HttpGet]
or [HttpPost]
above your method as follows:
[HttpPost]
public ActionResult Login(string userName, string password) {
// do login stuff
return View();
}
Now I want to test if the example above with [HttpPost]
really works so I use postman to send a HTTP request to my Web API. I fill in the URI and set the method to GET. The response I get is as follows:
{
"message": "The requested resource does not support http method 'POST'."
}
I'm able to verify that adding [HttpPost]
prevents me from using HTTP GET requests.
What I would like to do now is log the event whenever an user tries to sent GET requests when the application is expecting POST, and vice versa. I could implement something for every single method but this would take a lot of time and it wouldn't be easy to make changes once it's been implemented. So I would like to filter it globally or something.
For example something like:
class MethodRequestFilter : SomeGlobalMethodFilter
{
public override void Filter(SomeRequestContext requestContext)
{
if (usedRequestMethod.isNotValid == true)
{
//implementation for logging
}
}
}
But ofcourse I haven't been able to find this yet within the libraries of .Net. How can I log the event globally whenever a user tries to make a request that isn't a supported method?
Greetings,
Damien.
Upvotes: 1
Views: 1238
Reputation: 75
Thanks to the user div I was able to solve my problem by using a base controller that implements logging. These are the steps that I had to take:
Create a new controller class called BaseController
and inherit ApiController
:
Override the ExecuteAsync
method from ApiController
:
Add an implementation for logging in the catch clause
Inherit the new BaseController
in every controller class that you would like to have logging functionality.
The code that I used in my implementation:
public class BaseController : ApiController
{
public override async Task<HttpResponseMessage> ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken)
{
try
{
HttpResponseMessage response = await base.ExecuteAsync(controllerContext, cancellationToken);
return response;
}
catch (HttpResponseException ex)
{
if (ex.Response.StatusCode == HttpStatusCode.MethodNotAllowed)
{
//Logging implementation
}
return Request.CreateErrorResponse(ex.Response.StatusCode, ex.Message);
}
}
}
If there is any way to make my code better, please let me know :)
Upvotes: 1
Reputation: 7864
One way is to using common base controller, to implement you need to add one base controller which would inherited from ApiController
public class BaseController : ApiController
{
public override async Task<HttpResponseMessage> ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken)
{
try
{
HttpResponseMessage response = await base.ExecuteAsync(controllerContext, cancellationToken);
if (!response.IsSuccessStatusCode) // or if(response.StatusCode == HttpStatusCode.BadRequest)
{
//log here
}
return response;
}
catch(Exception ex)
{
return await InternalServerError(ex).ExecuteAsync(cancellationToken);
}
}
}
Now, let's assume that you're having ValuesController
and Login
method and it supports only POST, here your all other controllers inherit from BaseController
instead ApiController
public class ValuesController : BaseController
{
[HttpPost]
public void Login([FromBody]string value)
{
}
}
So, once you call your login method, it'll call BaseController method first and you will get response there.
Hope this helps!
Upvotes: 1