I'm building an ASP.NET Core 5.0 Web API application as I mentioned in the title I have an issue when trying to delete a record from the database; I'm getting an error 405 Method Not Allowed response from HttpDelete request.
PS: I have added services.AddCors() and app.UseCors() with default policy.
This is the delete method code
public bool deleteLivreById(int id)
{
Livre l = _db.Livres.Find(id);
_db.Livres.Remove(l);
_db.SaveChanges();
return true;
}
And this is the HttpDelete method inside the controller
[HttpDelete("{id}/delete")]
public bool deleteLivreById(int id)
{
return _objGererLivre.deleteLivreById(id);
}
Finally this is a picture from console when navigating to HttpDelete Url
Edit: This is full code of my controller
namespace GestionLivre.Controllers
{
[ApiController]
[Route("test")]
public class LivreController : Controller
{
private IGererLivre _objGererLivre;
public LivreController(IGererLivre gererLivre)
{
_objGererLivre = gererLivre;
}
[HttpGet]
public JsonResult getLivres()
{
return Json(_objGererLivre.getLivres());
}
[HttpDelete("{id}/delete")]
public bool deleteLivreById(int id)
{
return _objGererLivre.deleteLivreById(id);
}
}
}
I opened the screenshot and noticed that you have selected 'GET' as http verb and method type is 'Delete'. Could you please change that and try.
As I understand by default when you're trying to access URL in browser it uses GET method. So we should to pass in header appropriate method(POST,GET,DELETE,PATCH,PUT) If you want to test HTTP methods I'll recommend you to use Postman or Swagger. Postman much easier to use whether than Swagger which you should to add to service configuration and middleware.
Example of Postman:
And than configure body like that to return response.
Also recommend you to use REST Best Practices. And name resources properly. https://restfulapi.net/resource-naming/#:~:text=2.-,Best%20Practices,-2.1.%20Use%20nouns
I would like to return only standardized error responses from my Web API (Asp.net Core 2.1), but I can't seem to figure out how to handle model binding errors.
The project is just created from the "ASP.NET Core Web Application" > "API" template. I've got a simple action defined as:
[Route("[controller]")]
[ApiController]
public class MyTestController : ControllerBase
{
[HttpGet("{id}")]
public ActionResult<TestModel> Get(Guid id)
{
return new TestModel() { Greeting = "Hello World!" };
}
}
public class TestModel
{
public string Greeting { get; set; }
}
If I make a request to this action with an invalid Guid (eg, https://localhost:44303/MyTest/asdf), I get back the following response:
{
"id": [
"The value 'asdf' is not valid."
]
}
I've got the following code in Startup.Configure:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
JsonErrorMiddleware.CreateSingleton(env);
if (!env.IsDevelopment())
{
app.UseHsts();
}
app
.UseHttpsRedirection()
.UseStatusCodePages(async ctx => { await JsonErrorMiddleware.Instance.Invoke(ctx.HttpContext); })
.UseExceptionHandler(new ExceptionHandlerOptions() { ExceptionHandler = JsonErrorMiddleware.Instance.Invoke })
.UseMvc()
}
JsonErrorMiddleware is simply a class that converts errors to the correct shape I want to return and puts them into the response. It is not getting called at all for the model binding errors (no Exception is thrown and UseStatusCodePages is not called).
How do I hook into the model binding to provide a standardized error response across all actions in my project?
I've read a bunch of articles, but they all seem to either discuss global exception handling or validation errors.
It's worth mentioning that ASP.NET Core 2.1 added the [ApiController] attribute, which among other things, automatically handles model validation errors by returning a BadRequestObjectResult with ModelState passed in. In other words, if you decorate your controllers with that attribute, you no longer need to do the if (!ModelState.IsValid) check.
Additionally, the functionality is also extensible. In Startup, you can add:
services.Configure<ApiBehaviorOptions>(o =>
{
o.InvalidModelStateResponseFactory = actionContext =>
new BadRequestObjectResult(actionContext.ModelState);
});
The above is just what already happens by default, but you can customize the lambda that InvalidModelStateResponseFactory is set to in order to return whatever you like.
Testing my web API (nuget package Microsoft.AspNetCoreAll 2.0.5) I run into strange issues with the model validation using annotations.
I have (for example) this controller:
[HttpPost]
public IActionResult Create([FromBody] RequestModel request)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
// create
request.Name.DoSomething();
return Created(...);
}
I defined my RequestModel as follows:
public class RequestModel
{
[Required]
public string Name {get; set};
}
My problem although I defined RequestModel.Name as [Required] it is null (if Name is not present in the json from the body. Which I thought should not happen since it is marked as [Required] and be automatically appear as ModelState error.
Given this link to the specs they use Bind(....).
So my question?
Do I have to enable it everytime or should it work out of the box or how is it intended to be used?
If I annotate it with [Required] I would assume that at least ModelState.IsValid returns false if it is not present.
Using Bind in the link seems a bit complicated for me in cases where I have multiple objects nested into each other.
Edit 1: created a MVC data validation test bed
To better visualize what I mean and so everyone can easily experiment on their own I created the small demo .NET Core MVC data validation test bed on GitHub.
You can download the code, start it with VS 2017 and try it out your own using the swagger ui.
Having this model:
public class StringTestModel2
{
[Required]
public string RequiredStringValue { get; set; }
}
And testing it with that controller:
[HttpPost("stringValidationTest2")]
[SwaggerOperation("StringValidationTest2")]
public IActionResult StringValidationTest2([FromBody] StringTestModel2 request)
{
LogRequestModel("StringValidationTest2", request);
if (!ModelState.IsValid)
{
LogBadRequest(ModelState);
return BadRequest(ModelState);
}
LogPassedModelValidation("StringValidationTest2");
return Ok(request);
}
The results are far way from expected:
Giving a null (not the string "null") is allowed and return 200 OK
Giving an int is allowed an returns 200 OK (it gets converted to a string)
Giving a double is allowed and returns 200 OK (if possible it gets converted to string, if not convertible (mixing points and semicolons return 400 Bad Request)
if you just send empty curly brackets and leave RequiredStringValue undefined it passes and returns 200 OK (with the string as null).
Leaving me (for now) with one of the follwoing conclusions:
either MVC data validation does not work out of the box
either does not work as expected (if one marks a property as required it should be made sure it is there)
either MVC data validation is broken
either MVC data validation is completly useless
we are missing some important point (like the Bind[])
You get ModelValidation automatically as part of using/deriving from controller (I believe it is in the MVC middleware) but, unfortunately, this does not include null checks. So you need to explicitly check the parameter is NULL as well as the ModelState check.
[HttpPost]
public IActionResult Create([FromBody] RequestModel request)
{
if (request == null || !ModelState.IsValid)
{
return BadRequest(ModelState);
}
...
I assume you use
services.AddMvc();
so it should work by default.
But it doesn't work just as you expect: instead of returning 400 status code it invalidates model state and lets you manage action result.
You can create an attribute class to automatically return "Bad request"
internal class ValidateModelAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
if (!context.ModelState.IsValid)
{
context.Result = new BadRequestObjectResult(
new ApiError(
string.Join(" ",
context.ModelState.Values
.SelectMany(e => e.Errors)
.Select(e => e.ErrorMessage))));
}
}
}
where ApiError is a custom ViewModel for error results.
Now you can mark controllers or actions with this attribute to achieve a behavior you expect to have by default.
If you want this behavior for all methods just change your AddMvc line to something like this:
services.AddMvc(config => config.Filters.Add(new ValidateModelAttribute()));
After further experimenting around I found the answer.
Does the data validation need to be activated?
Answer: it depends on your configure services method:
No, it does not need to be activated if you use
services.AddMvc();
Yes, it needs to be activated if you use
services.AddMvcCore()
.AddDataAnnotations(); //this line activates it
This article brought me to the answer.
We are putting an angular front end on an existing asp.net c# MVC applicaiton. In our server code, we extensilvely use custom exceptions to return buisness rule errors.
Is there a best practice or slickest way to handle an exception on an mvc controller or an webApi controller (actually bullbing up from the buisness layer) and getting it across to angular and displaying it in a "user error" popup? How are folks solving this problem?
Other guys already gave great answers, but I want to elaborate my approach since I guess it will be covering both ends (frontend and server) with more details.
Here's my complete approach to error and exception handling in WebAPI + AngularJS applications.
Step 1. WebApi controllers in Server side
I have a specific DTO for communicating Validation Errors to the client, since I believe they are different from Exceptions. An exception will result in a 500 error, where a validation result should result in 400 (Bad Request) error.
So, here's my ApiValidationResult class:
public class ApiValidationResult
{
public List<ApiValidationError> Errors { get; set; }
public static ApiValidationResult Failure(string errorKey)
{
return new ApiValidationResult {Errors = new List<ApiValidationError> {new ApiValidationError(errorKey)}};
}
// You can add a bunch of utility methods here
}
public class ApiValidationError
{
public ApiValidationError()
{
}
public ApiValidationError(string errorKey)
{
ErrorKey = errorKey;
}
// More utility constructors here
public string PropertyPath { get; set; }
public string ErrorKey { get; set; }
public List<string> ErrorParameters { get; set; }
}
I always use my own base class for WebApi (and MVC) controllers, so I can use them to add handy result method, such as this:
public abstract class ExtendedApiController : ApiController
{
protected IHttpActionResult ValidationError(string error)
{
return new ValidationErrorResult(ApiValidationResult.Failure(error), this);
}
// More utility methods can go here
}
It uses a custom IHttpActionResult that I've created specifically for this purpose:
public class ValidationErrorResult : NegotiatedContentResult<ApiValidationResult>
{
public ValidationErrorResult(ApiValidationResult content, IContentNegotiator contentNegotiator, HttpRequestMessage request, IEnumerable<MediaTypeFormatter> formatters)
: base(HttpStatusCode.BadRequest, content, contentNegotiator, request, formatters)
{
}
public ValidationErrorResult(ApiValidationResult content, ApiController controller)
: base(HttpStatusCode.BadRequest, content, controller)
{
}
}
As a result, I can cleanly use codes such as this in my controller actions:
[HttpPost]
public IHttpActionResult SomeAction(SomeInput input)
{
// Do whatever...
if (resultIsValid)
{
return Ok(outputObject);
}
return ValidationResult(errorMessage);
}
Step 2. Handling unexpected exceptions
As I said, I believe that only real unhandled Exceptions should result in a 500 (Internal server error) responses.
Such unhandled exceptions are automatically converted to a 500 result by WebApi. The only thing I need to do about them, is to log them. So, I create an implementation of IExceptionLogger interface and register it like this:
GlobalConfiguration.Configuration.Services.Add(typeof(IExceptionLogger), new UnhandledExceptionLogger());
Step 3. Intercepting and showing errors in Client side
AngularJS allows intercepting all HTTP calls sent from $http service. I use this to centralize all message popups. Here's my interceptor code:
appModule.factory("errorsHttpInterceptor", [
"$q", "$rootScope", "$injector",
($q: ng.IQService, $rootScope: IAppRootScopeService, $injector) => {
return {
'responseError': rejection => {
// Maybe put the error in $rootScope and show it in UI
// Maybe use a popup
// Maybe use a 'toast'
var toastr = $injector.get('toastr');
toastr.error(...);
return $q.reject(rejection);
}
};
}
]);
You can do all sorts of things in the interceptor, such as logging debug messages, or applying key to display-string translation of error codes. You can also distinguish between 500 and 400 errors, and display different types of error messages.
I use toastr library which I think shows a nice UI and is very handy in API level.
Finally, I register the interceptor like this:
appModule.config([
'$httpProvider',
($httpProvider: ng.IHttpProvider) => {
$httpProvider.interceptors.push('errorsHttpInterceptor');
}
]);
The syntax is in TypeScript, which is very similar to JavaScript and I'm sure you can figure out what it means.
Typically, I Have been doing this kind of thing within our WEB API, returning the correct status code is key with this, this is of course completely agnostic as to which of the many front end frameworks you want to use.
public IHttpActionResult Get(DateTime? updatesAfter = null)
{
try
{
// Do something here.
return this.Ok(result);
}
catch (Exception ex) // Be more specific if you like...
{
return this.InternalServerError(ex);
throw;
}
}
The helper methods that are now shipped with Web Api v2 ApiControllers are excellent...
this.BadRequest()
this.InternalServerError()
this.Ok()
this.Unauthorized()
this.StatusCode()
this.NotFound()
Some of them (such as InternalServerError) allow you to pass an exception or message (or simply an object) as a param.
Typically as with any front end framework or library there will be a fail or error callback that you can provide when initialising the ajax call to your API method, this will be called in scenarios where error status codes are returned.
We have just finished a large MVC app with an Angular frontend.
We just let errors flow, eg any webpages just get an error has but without the stack trace (not the yellow screen, the nice Error has *** but within your master page etc)
Web API calls just return the correct HTTP status. They can include some details if you wish.
But, you dont want to lose these errors, so we just installed elmah with
Install-Package elmah
and, it JUST WORKS, errors just end up in the log, users get told something as not worked etc.. NO extra work needed
To make our UI nicer we did the following, for
Unhandled errors
MVC Pages
Just let MVC front end do its job, it will tell the user in a nice way something has gone wrong.
Angular web calls
in the .error function alert the user eg
}).error(function (data, status, headers, config) {
$scope.addAlert('danger', 'Error deleting autosave details');
}
Let errors stack, if you don't to lose an error due to an error overwriting it. addAlert just writes to an array that is data bound to on the front end.
Handled Errors
If you are handling them, then you have managed what happens, but to log these
MVC
If you wish to just log them, the elmah API has a single call for this
ErrorSignal.FromCurrentContext().Raise(exception );
If you are using error attributes then you can use this
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new ElmahHandledErrorLoggerFilter());
filters.Add(new HandleErrorAttribute());
}
}
public class ElmahHandledErrorLoggerFilter : IExceptionFilter
{
public void OnException(ExceptionContext context)
{
// Log only handled exceptions, because all other will be caught by ELMAH anyway.
if (context.ExceptionHandled)
ErrorSignal.FromCurrentContext().Raise(context.Exception);
}
}
Also, for general logging to the ELMAH framework checkout https://github.com/TrueNorthIT/Elmah
Another approach is returning Content.
Here is how I do it (end-to-end). From my API:
return Content(HttpStatusCode.<statuscode>, "ResponseContent: " + "my_custom_error");
Here, HttpStatusCode. and "my_custom_error" can be the response returned from another API Layer. In that case, I simply read the response from that layer and pass it to the client side.
//If I'm getting output from another API/Layer then I pass it's output like this
var output = response.Content.ReadAsStringAsync().Result;
return Content(response.StatusCode, "ResponseContent: " + output);
For more details on HttpStatusCodes, please refer HttpStatusCode Enumeration
And in the Angular code, I read it like this:
$http({ method: methodType, url: endpoint })
.then(function (response) {
response.status; //gets you the HttpStatusCode to play with
response.data; //gets you the ReponseContent section
}, function (response) {
response.status; //gets you the HttpStatusCode
response.data; //gets you the ReponseContent section
});
Make sure while making http calls the responseType is not set to 'JSON'. Since the data returned by the API is not in JSON format at this stage.
From $http service in AngularJS, the response object has these properties:
data – {string|Object} – The response body transformed with the
transform functions.
status – {number} – HTTP status code of the response.
headers – {function([headerName])} – Header getter function.
config – {Object} – The configuration object that was used to
generate the request.
statusText – {string} – HTTP status text of the response.
For my API Controllers I return HttpResponseMessage. Please see my example below. I hope this helps.
On the response message you can also pass back your object to the front end.
WEB API
// Get all
[HttpGet]
public HttpResponseMessage Get()
{
try
{
return Request.CreateResponse(HttpStatusCode.OK, myObject);
}
catch (Exception e)
{
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, "Error Message");
}
}
Angular JS
// Get Request on Page Load
$http({
url: '/api/department/',
method: 'GET',
}).success(function (data) {
$scope.departments = data;
}).error(function (error) {
$scope.error = error;
});
HTML
<div class="alert alert-danger animate-show" role="alert" ng-show="error != null">{{ error }} </div>
<div class="alert alert-success animate-show" role="alert" ng-show="success != null">{{ success }}</div>
So there is a heap of examples around but finding ones that are relevant to the rtm bits seems to be a little harder to find.
I have 2 projects one is an WebApi & the other is MVC4 .net 4.5 application.
I want to make a make an update to an item
I have a controller within my API that does something like
[HttpPut]
public MyModel Update(MyModel model)
{
//make update
return model;
}
Is this correct? should I be using a HttpResponseMessage instead of just using my MyModel class? I want to return the correct httpstatus details as much as possible as I am wanting to open up this api to 3rd parties not just my application
Calling this api from my mvc application from my controller how do I do this?
The beste way is to use HttpResponseMessage like this:
[HttpPut]
public HttpResponseMessage Update(MyModel model)
{
if(notfound)
{
return this.Request.CreateResponse(HttpStatusCode.NotFound);
}
//make update
return this.Request.CreateResponse<MyModel>(HttpStatusCode.OK, Model);;
}
I mostly use EasyHttp if I want want to call a WebApi method from my MVC app:
var model = new ExpandoObject(); // or use a stronly typed class.
model.Id = 1,
model.Name = "foo"
var http = new HttpClient();
http.Post("url", model, HttpContentTypes.ApplicationJson);
If you want to respond with httpstaus code you have to return HttpResponseMessage.
You may choose to have a common method returning your BOs and call it from the Action and from your other mvc application code. Then your rest calls would always be wrapped with a status code and other calls get an object.
[HttpPut]
public MyModel Update(MyModel model)
{
return base.Request.CreateResponse<MyModel>(HttpStatusCode.OK, UpdateModel(model));;
}
[NonAction]
internal MyModel UpdateModel(MyModel model)
{
//make update
return model;
}