Is there a way to handle 404 (resource not found) generically, or do I have to write logic for each action? A simple example of what I am currently doing:
//single-read
public HttpResponseMessage Get(Guid guid)
{
School school = new School(guid);
if (school == null)
{
return Request.CreateResponse(HttpStatusCode.NotFound);
//bonus-question: would it be better to instead: throw new HttpResponseException(HttpStatusCode.NotFound);
}
//bonus-bonus-question: what is the benefit of using a typed response?
return Request.CreateResponse<School>(HttpStatusCode.OK, school);
}
If possible, I would like the "not found" logic to be handled elsewhere so that I didn't need to repeat those few lines of checking for each action. For example, I'd like it if it could be reduced to:
//single-read
public HttpResponseMessage Get(Guid guid)
{
School school = new School(guid);
return Request.CreateResponse<School>(HttpStatusCode.OK, school);
}
You can implement an IActionFilter on your controller which will be called everytime an action is about to be executed and also when an action has finished execution. You can then perform your checking logic there. See documentation. You would annotate the controller class itself with your filter and it would be called for all actions.
In terms of the error handling, if you don't throw an exception, then you won't pay the cost of exceptions (which I'd like to pretend to be negligible), but more importantly, you won't allow any exception handlers to kick in and that may be something you actually want. Take a look at IExceptionFilter for example that gets called whenever an exception is thrown. If there is a part of your application that relies on that (for example logging errors), that component won't know that there was an error when you don't throw an exception, so it's a design call.
Related
I got an API with a controller and a service, when invoking one of the action in the controller I must apply a validation, this validation need to check the data in DB to validate that is correct.
As far as I can see there are two ways of handling this
1- Validate before calling the "update" to prevent the error
public IActionResult UpdateCustomer(CustomerDto customer)
{
if (!customerService.Validate(customer))
{
return Send400BadRequest();
}
customerService.Update(customer);
return Send200Ok();
}
2- Call the update validate inside and throw an Exception.
public IActionResult UpdateCustomer(CustomerDto customer)
{
customerService.Update(customer);
return Send200Ok();
}
In customer service
public void Update(CustomerDto customer)
{
if (!Validate(customer)
throws new CustomValidationException("Customer is not valid");
//Apply update
}
We already have an ActionFilter to handle the CustomValidationException so it will return a BadRequest.
1)
Pros
+Don't use Exception to use the running flow
Cons
-Controller is more fat, has more decision on each case it will decide which is the output
2)
Pros
+Operation is more atomic, all logic is inside the service.
+Easier to test
+Every use of the method will be validated.
Cons
-Use exception to manage the flow.
Which is a better solution?
I really need arguments to defend one or the other.
If you have a Business Logic Layer and a Service Layer, I prefer to keep all Business Logic Rules including Business Logic Validations in Business Logic Layer and use Service Layer as a wrapper around Business Logic Layer and throw Exception in Business methods.
When deciding about whether to use Exception for Business Validation rules or not, you can consider:
1) It's better that your Business methods be a Unit of Work. They should perform a complete task. So it's better they contain also validation rules. This way you can reuse such Business Logic Layer across different Service Layers or use the same Unit of Work in different methods of the same Service Layer. If you throw a Business Validation Exception in Business Logic Layer, you will not face with risk of forgetting validation or using another validation rule by mistake and each service method / action will perform a single task for you and will be as lightweight as possible.
Think about when you may need to expose a WCF service for some clients or for example if you may use ASP.NET MVC without using WebAPI or iff you want to use the same logic in another Action method in the same WebAPI.
If you put Business Logic validations in Web API controller, when creating WCF service methods or creating MVC Actions or other service methods, you may forget to apply validations or may apply wrong validations with different rules in the new Service Layer.
2) Considering the first benefit, can you return a meaningful value from methods that shows success, failure, or contain suitable information about failure reason in output?
I believe it's not suitable to use out put of method for all these goals. The method output is method output, it should be data in such business application. It should not be sometimes a status, sometimes data or some times message. Throwing exception will solve this problem.
I am going against the other opinions on here and saying that the first method both clearly illustrates what the intent of your method is and if you ever decide to not return a 400 error, its a bit easier to pull that off in scenario #1.
Additionally, some thoughts on exceptions. Exceptions should be exceptional, meaning unexpected events that occur in your code. A company not passing a validation check is not an exception-al event, it either does pass or does not pass. Passing a User object into the ValidateCompany() method should throw an exception.
Here is a good answer on the similar topic of exception throwing. It uses an easy example problem to determine when in that case an exception should be thrown or not.
In regards to "Easier to test" - I don't see how. Your controller will have two tests with any option you choose, a valid company and an invalid company. Your service will have two tests with any option you choose, a valid company and an invalid company (obviously simplifying your service layer a bit here). In any case you want to ensure both your controller action and your service layer can handle an invalid and valid company object.
I would prefer 2 :)
Because I think service might be called from another node not only the asp.net controller so it would be nice for me if all validation logic is handled in the single layer like Service layer.
i think handling exception by using httpresponse message is much better then any one else. Atleast you got the proper error response with proper http response message as output.
public HttpResponseMessage TestException()
{
try
{
//if your code works well
return Request.CreateResponse(HttpStatusCode.OK);
}
catch (Exception ex)
{
return Request.CreateErrorResponse(HttpStatusCode.ExpectationFailed, ex.ToString());
}
}
I would do it this way:
public IActionResult UpdateCustomer(CustomerDto customer)
{
try
{
consumerService.Update (customer);
}
catch (CustomValidationException)
{
return Send400BadRequest ();
}
return Send200Ok ();
}
And in your CustomerService:
public void Update(CustomerDto customer)
{
if (!Validate(customer))
throw new CustomValidationException("Customer is not valid");
}
This way your service has the validation logic. So any other callers to your service will also have their inputs validated before attempting an update and hence will get proper error messages.
Your controller will not have any validation code. And moreover, having the try-catch block means you can gracefully handle any other errors the Update call might throw. Hope that helps.
Receive a validatable customer model, pass this model to the data service layer, and perform exception
handling in the controller if the data service layer fails.
Customer model
Implement IValidatableObject to trap business logic related errors.
public class CustomerModel : IValidatableObject
{
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
// example validation
if ( Balance < 100 )
yield return new ValidationResult("Balance >= 100 req.", new [] { nameof(Balance) });
}
public string Name { get; set; }
public double Balance { get; set; }
}
API Controller
Receive a CustomerModel in your public facing UpdateCustomer API method, then reference ModelState to determine if the customer is valid.
public IActionResult UpdateCustomer(CustomerModel customer)
{
if(ModelState.IsValid) // model validation succeeded
{
try
{
customerService.Update(customer);
}
catch (ServiceUpdateException svcEx)
{
// handled failure at the service layer
return Conflict();
}
catch (Exception ex)
{
// unhandled error occured
return InternalServerError(ex);
}
// update succeeded
return Ok();
}
// invalid model state
return BadRequest();
}
Service (Data Layer)
public void Update(Customer customer)
{
//Apply update
try
{
database.Update(customer);
}
catch (DataStorageException dbEx)
{
throw new ServiceUpdateException(dbEx);
}
catch
{
throw;//unknown exception
}
}
I think that you should validate in both the controller and the service, but validate slightly different things. Especially if what starts off as just an api turns into an api, with a mvc site and a wpf admin interface as often happens.
Using Validation Attributes and Model Binding gives the data a quick "once over" check. Did they supply the id for the customer to update? Did they submit foreign key value for a related entity? Is the price between 0 and 1,000,000? If you have a website then you also get client validation out of the box. Crucially there no need to connect to the database at all, as the data is "obviously" wrong.
Validation in the service is also required as you may end up with 3 or 4 applications calling this service, and you want to write the business logic once. Some validation eg. referencing foreign keys can only be done in the database, but there is nothing wrong in throwing an exception. Consumers of your api should have access to the range of valid values, users of the website should be choosing from a drop down etc, so this circumstance should be exceptional
Grails makes it very easy for a Controller to call into a Service and for a Controller to forward a request onto another Controller.
So suppose you have a service method as such
List<String> updateNames() {
...
}
You can call it very easily from any controller.
I am wondering, say if you have an edge case where you realise there is a validation problem in your service method. You don't want to throw an Exception back to your controller, because it is not really an exceptional case. But you can't return back an error message from your Service to the Controller that called because that will mean you have to use some wrapper object instead of a nice List
Is there anyway for these cases, you can get the Service to do a server side forward onto another Controller which could return an Error response to user?
Thanks.
Grails already have a structure for validation in your beans, called Errors (comming form Spring). For example, if you have a service to upload files, you could easily attach validation errors in your bean:
class UploadService {
void doUpload(MultipartFile file, MyDomainClass domainClassInstance) {
if(validationsFail) {
domainClassInstance.errors.rejectValue("myUploadField","my.i18n.code")
}
}
}
If it's not a domain class, you can consider using a command object since they're validateable too.
In your controller, it's just a metter of checking if your instance has errors:
def upload() {
MyDomainClass instance = ...
uploadService.doUpload(request.getFile('file'), instance)
if(!instance.hasErrors()) {
//save and go on...
}
}
Another option is to work with exceptions like #Joshua Moore answered. Just remember to extend RuntimeException. If you don't, your transaction will not be rolledback automatically.
Services are not aware of the web/http request context in this way. I won't get into how this line is blurred with session or request scoped services since it still doesn't apply to what you are asking about. Plus, you really don't want your service to even be aware that it's dealing with a web/http request, since you want to separate responsibilities and have a good/clean design.
So, back to your question. This is exactly the case for raising an exception from your service and letting your controller handle the result of that exception. If it's a validation error on an instance then you should be able to access the errors collection of the instance in your controller (provided of course that it was an input into your service).
As a side note about exceptions from services. Stack traces are expensive to fill in. This is even more so in Grails since there are a lot of pieces at work. I highly recommend if you are going to raise your own business logic exceptions from your services that you override the fillInStackTrace method on your exception to avoid this cost.
Here is an example:
package com.example
class MyBusinessException extends RuntimeException {
List<String> argList = []
public MyBusinessException (String message, List<String> args){
super(message)
argList = args
}
public MyBusinessException (String message){
super(message)
}
/**
* Don't fill in the stack trace because we want things to be faster.
**/
#Override
public Throwable fillInStackTrace() {
// do nothing
return this
}
}
When I do Ajax.BeginForm posts to my actions returning a partial view I send error info in a ViewData item.
Currently in order to handle all errors I must wrap all of the method in a try catch statement.
[HttpPost, ValidateAntiForgeryToken]
public virtual ActionResult Save(int id, FormCollection form)
{
MyModel model;
try
{
...do stuff...
}
catch(Exception ex)
{
...log...
ViewData["ResultInfo"] = new ResultInfo(false, Resource.SAVE_NOT_SAVED, someErrorMessage);
}
return PartialView("Folder/SomeView", model);
}
I would like to do this with a custom HandleError attribute, but I realize that there must be many gotchas waiting to bite. Has anyone tried and want to share their experiences?
EDIT:
I've ended up doing error handling in a controller base class.
This ErrorHandlingController has 2 methods; RegisterErrorHandler and RegisterModel. If the error handler is found registered when an error is found in the base class OnException I just add the ResultInfo and marks the error as handled and uses the view and error caption I've set in RegisterErrorHandler.
This way it's very easy to get the model to the error handler and it's natural to use Resources directly since the error handler is registered as the first row inside the method as opposed to an attribute outside it.
I think the answer to this question will help you along: How to handle model state errors in ajax-invoked controller action that returns a PartialView.
I got a generic repository - should the repository be able to throw exceptions or should I keep it dumb? If I chose to throw exceptions from it, should the service layer then catch it and throw an exception with a more friendly message before it goes to the Controller?
Pos1: Repository (Throw) => Service(Catch, Throw new) => Controller(Catch)
Pos2: Repository => Service(Throw) => Controller(Catch)
Definitely Option 1.
I would also replace the term "dumb" with "separation of concerns" in your thinking. There is no reason for a Repository to be dumb. It has a job to do and that will involve exceptions.
It will also involve throwing them for two reasons:
To package a real error that has happened for the consuming code.
To throw an exception under given conditions that violate what you want this class to do. These conditions might not involve an exception thrown by the framework and can be solely related to the "intelligence" you want your Repository to have.
The Repository has to involve encapsulating ALL of this intelligence, leaving the calling code to simply need to know how to deal with a limited set of exceptions. Otherwise, your calling code needs to deal with, for example, the full panoply of LINQ exceptions, coupling it to a technology that should be the exclusive domain of the Repository.
So part of the Repositiory's intelligence has to be throwing a well known, but limited set of exceptions related to its specific purpose.
The same reasoning applies to the Service Layer, if you have one. It needs to deal with exceptions in exactly the same way: encapsulating the "intelligence" that is specific to its task. And again, the same happens with the controller. It should interpret the exceptions it receives from the Service Layer (if there is one) according to its own purposes and concerns.
So separation of concerns, but never dumb. Not even Mute: each layer needs to squeal when it has to.
Should the repository be able to throw
exceptions or should I keep it dumb?
Yes - the repository should be able to throw exceptions. Keeping something 'dumb' doesn't mean it's not comletely self-aware :)
The caveat that 'exceptions should be exceptional' still applies - you might find this "Creating More Exceptional Exceptions" article of interest and it's also of relevance to your question.
If I chose to throw exceptions from
it, should the service layer then
catch it and throw an exception with a
more friendly message before it goes
to the Controller?
Generally, I've not re-thrown exceptions although there's merit in doing that. A pragmatic half-way-house would be to do that for exception types which you want to handle gracefully for some reason.
If you're using something like the Ms Ent Libs Application Logging Block you can set a policy (via config) that allows you to control what happens when exceptions occur - re-throwing them or otherwise; so that would be a useful approach to stop hard-coding yourself into a specific result.
Also this might be of interest: Are exceptions really for exceptional errors?
Generally speaking, you should simply return null from your repository if your query returns no data. You can then test for the null in the repository, if you wish, before sending the data to your view.
public ActionResult Details(int id) {
Dinner dinner = dinnerRepository.FindDinner(id);
if (dinner == null)
return View("NotFound");
else
return View("Details", dinner);
}
http://nerddinnerbook.s3.amazonaws.com/Part4.htm
For edits I would let your Data Access Layer or your repository throw an exception, and catch it in the controller, like this:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(int id, FormCollection formValues) {
Dinner dinner = dinnerRepository.GetDinner(id);
try {
UpdateModel(dinner);
dinnerRepository.Save();
// Success!
return RedirectToAction("Details", new { id=dinner.DinnerID });
}
catch {
// Old-school data validation from ASP.NET MVC 1.0
foreach (var issue in dinner.GetRuleViolations()) {
ModelState.AddModelError(issue.PropertyName, issue.ErrorMessage);
}
// Return original view, so user can correct errors.
return View(dinner);
}
}
http://nerddinnerbook.s3.amazonaws.com/Part5.htm
I am using the built-in forms authentication that comes with asp.net mvc. I added all the necessary tables to Sql Server using aspnet_regsql wizard and I have it all integrated and working perfect. Now I can add users, log in, perform control Authorization and all these things.
The next step is to add some basic logs when a user performs an action. For example, I want to log who has deleted an user from the database using the UserAdministration, or when someone has visited a view with restricted information (these are just examples).
I've seen that with the authentication comes a table called aspnetWebEventEvents but seems that it is intended only to store exceptions occurred on the website and it is configured with web.config and it's all performed automatically. I would like just to call a class to log custom actions without having to fill manually all the fields:
Logger.Log("Action performed");
And store automatically the user, time and all these fields.
I'm sure there has to be an already implemented class to do this stuff and I don't want to rewrite something that it is already done.
I tried using SqlWebEventProvider, that seems to be the one that is called internally but this class seems to be internal so it is not intended to be used.
Maybe I'm wrong, this is not intended to log custom actions and I should better create my own table with custom actions...
I dont know if you can accomplish that with aspnetWebEventEvents, it sound like you want to log specific situations which i don't think is the intention of this buld in feature.
Have you tried ActionFilters?, you can do really specific logging with this, for example you can check the Result Type to see what happened when the user try to use that action, and you have access to the RouteData Values through the ActionExecutedContext:
public class LogActionFilter : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (filterContext.Exception != null)
{
//Log - Exception Cases
}
else if(filterContext.Result.GetType() == typeof(RedirectToRouteResult))
{
//Log - Redirect to other Action
}
else
{
//Log the normal behavior
}
}
}
And then you just Decorate the actions you want to log with this attribute:
[LogActionFilter]
public ActionResult Edit(int id)
{
}