I am building a Data Access Layer which is going to be used in two types of applications.
Applications that do not care about the specifics of the error. If an exception occurs then most probably is going to just get logged and the user may not be aware of it.
Example: Simple barcode stock taking application. The user inputs the barcode and if a connection is available to the database, then the system provides some extra info, if not then only the barcode is recorded locally. In this case I do not want detail exception handling.
Applications where I care a lot about the details of the exception.
What strategy do I have to follow when building my DAL in order to accommodate both categories?
Right now I am building an application from the first category and all I have done in my DAL methods is to just let the exception bubble up to the presentation layer, where I have several try..catch blocks in order to make the simple handling of logging, letting the user be unaware of he error.
Error handling is geting information from the part of code that knows to the person who needs to know. The DAL knows how to pritty print the trace of, say, a SqlException, SqlCommand and the SqlParameters collection. But the UI knows the entire call stack that caused the exception. The user probably doesn't know what to do with the information, so you should log to a separate channel, such as email to the developer or a log in the database.
I would also recommend using a real application (or several real applications) as tests of your library if you are writting an error logger. For example, you could wire up your error logger to a variety of apps on codeplex and see what the pain points are in troubleshooting bugs, or try dogfooding and using your error logger to log errors is your own library.
Related
I have a question about the clean architecture I use to write my project, I need to tackle the subject of exceptions.
In the project I am using CQRS which is located in the application layer and which orchestrates the whole operation and component connection. In the domain layer, I have domain objects that have some logic, if there is an error this layer throws an exception BusinessRuleValidationException, or NullReferenceException in this layer I only use these 2 exceptions, but now I have an infrastructure layer which, if necessary, also throws exceptions, but there are more of them in this layer and they will probably continue to grow as the application develops.
Now the question is how to solve this problem, which are exceptions that I wouldn't want to keep remembering about handling every single exception inside api using exception middleware. My idea is to leave the exceptions in the domain layer as they are, because there are only 2 and write a decorator to MediatR that will catch exceptions from the domain layer only and make them consistent across the api, i.e. add a unified response so that exceptions are not sent to the user from its internal message, only consistent for everyone, in the form of Result using the Fluent Results bundle. Instead of throwing exceptions in Infrastructure, use a Fluent Results package that will return errors instead of exceptions and eventually return Result from all MediatR Handers. I would not like to use Fluent Result inside the domain layer because it is kind of breaking the rule that the domain layer doesn't have any references to other things.
The next question, if I decide to solve the problem in one way or another, the results of errors from the Infrastructure should immediately contain an error code such as Api should return to the end user, e.g. if occurs an error because it is impossible to connect to the database, the infrastructure should return, the message (Result) under the title "Could not connect to the database" with the code "500", or rather this error code should be returned from the api itself, ie the controller gets an error (Result) and it decides what code to give to this error.
Thanks for help :)
Exceptions aren't a problem that you need to solve.
Exceptions are there to say something unexpected has happened, and there are many many things that can go wrong: incorrect input, timeouts, not authorised, not authenticated, missing data, etc, etc.
You can structure your code, where it reuses .net exceptions as much as possible, and if you have to add something that is unique to your business domain, you put that in the layer that throws those exceptions. If this happens at the networking level, you put exceptions there. If this is domain logic validation - you can keep it in the domain core.
Consuming code may or may not catch the exception. If it catches the exception, the code import the exception from the current layer or the layer below.
PS: don't throw null reference exceptions
We are creating a new .Net Core Library, an application service that resides within a Clean Architecture.
The new service will read new customer details via the RepositoryService layer and Post them via a RestApiService Layer to multiple systems including : CreditCheck system, Billing system etc..
Within the new Application Service we want a consistent way of handling responses from RestAPi service. Response data includes:
- Return values: entities returned by restAPI service
- Exceptions like an error 500, time outs.. that have bubbled up from the RestAPi.
- Data Errors messages such as Customer already exists, bank details invalid
- Warning messages ... "Processing continues as normal, but order is flagged"
It is the last two that are foxing us, because this is different to the interaction with the Repository layer which has no business logic, so basically returns a success or an exception.
Microsoft and SOLID virtually state that the use of exceptions handling is the way to go , whether it be exceptions, errors or warnings.
But in this scenario not clear how this will work ..
a. We loose the option of handling and forwarding on the return values.
We really don't fancy storing all this in the exception message
- Whilst not a show stopper, we fear the code will be more difficult to read than it needs to be.
- Exception handling is expensive,but not worried too much on this score with number of transactions.
We are drawn to some how using FluentValidation or a hybrid version, it will need to work with Logging and RepositoryService as we will need log and decode stuff .
We really don't fancy repeating the RestAPi Service layer approach i.e. handling HTTP exceptions separately, then processing return values which are basically extended entities with Errors Status , Error codes and messages.
We are not expecting the above to be specific to our company. The issue seems to be around handling messages from a 3rd Party Business logic layer , within our Application Service.
So our question is how can we best handle Errors warnings along side data in the application service layer and still have SOLID testable and maintainable code ?
Microsoft and SOLID are right.
The correct way to go are Exceptions as per standard practices (and c#), independently of another considerations, like performance for instance.
Generally speaking there are two different types of "Errors", technical, and business logic related.
Failing to Connect to a DB, receiving a 500 from a REST Service, etc... are technical, and as they could be transient you can try to recover from this situation, sometimes without success, what finally causes the Business Orchestration/Process failure.
Business Logic errors, like 'Customer already exists', 'Bank details invalid','Input data is not in the valid format' are non-transient, and determined solely by Business Rules (some implicit, other explicit) and will stop stop your process as well without possibility to recover, simply because something is not in the proper/expected state.
There is a reason we use Exceptions (as technical artifacts) and is to handle these hard-stops 'properly'.
Every time you throw an Exception the application traverse back the stack up to the first available Exception Handler able to handle such Exception, returning the control to you and to a known location where something will happen (telemetry, rethrow, show a dialog to the user...)
Any mechanism trying to substitute this propagation (Error) must rely, for instance, on hijacking the return value of the methods to provide back a status, or forcibly include an out parameter to all your methods signatures, which will have awful collateral effects in your implementation.
Yes, sometimes your current design look 'too flat' that you are tempted to hijack the return value here and there, creating a highly coupled component, but you never can tell how the system complexity will grow, meaning that at some point you will extend your system with additional layers, and most likely the 'substituting mechanism' approach will not fit , and you are forced to support them, the regular way and the imaginative one.
So, trying to implement a custom solution will create a tightly-coupled technical requirement that must be supported all across the board, what in architecture terms is simply 'not good' (not a good practice)
IF any Service you are consuming is not able to produce a meaningful 'error' information, well structured, then, the Service is not well designed, and the problem flips to the Client side (Talking in SOA terms).
The only 'most correct' solution left to not introduce chaos in your Client is by creating a Proxy to the Service RESPECTING the rules required by your implementation approach.
My recommendation about Error Handling is very simple, stick to the rules that are well know and have been in place for decades and do not try workaround this by yourself, or you are going to face too many issues, create a Proxy for each service and integrate them properly in your code base (unit testing and such)
In regards to warnings, there is no recommendation from anybody to handle this by using Exceptions, those 'warnings' in your question is a normal output when interacting to the Service/a logical state supported by the Business Logic, thus, the place to handle this state is in the Data Contract coming back from the Service, again, if the Service is so horribly designed that is replying you with just a text string containing the word 'warning', and you are forced to parse this string to notice the situation, then your Proxy to the Service should check for it and provide a meaningful and well structured output to the Client.
I have a three layers C# software : UI, Business, Database.
I have some business rules that I want to implement into my business layer. For instance, if two objects have the same name, the business layer needs to throw an exception to the UI.
My problem is that my application is multi language, and my business layer don't have access to my resource files. So my UI needs to catch the exception from the business layer, and decide what message it will show to the user.
I was thinking about creating a BusinessException class, with a property who tells the UI which key to take in the ressource file. Do you thing it a good way to do it? Or do you have better ideas? Thank you!
The preferred solution is to create different exception types that represent the different errors, add any important data as properties to the exceptions and let the UI handle the user facing error messages.
This is ideal if you have a separate UI design team that wants to handle the text displayed to the user, including error messages. To be frank, developers tend to write good error messages for other developers but not for users.
Otherwise, embed some form of message ID in the exception that the UI can look up (as you suggest) or localize the error messages in the business layer.
I ended up with a mix of those two solutions. So I'm using only one class : BusinessRuleException. This class as a property "rule" which is a enum of all my business rules.
When my UI receive a BusinessRuleException, it can catch it, and than compare the "rule" to a ressource file and get a friendly message for the user. If the UI can't find a translation, it will only send the rule as is. So the user still have a change to understand what is going on.
It don't like the solution of a different exception for every different business rule, because it will end up with so much extra code, which doesn't help you understand what is the real work you class is doing.
In my ASP.NET MVC application, I do not want to report all exception messages to the user. But there are certain types of exceptions that I'd like to report to the user, so I created an action filter to decide if it's this particular type of exception, and if so then display the exception's message, otherwise display a generic message. So I created a custom exception called ClientException.
My filter looks something like this:
if (filterContext.Exception is ClientException)
message = filterContext.Exception.Message.Replace("\r", " ").Replace("\n", " ");
else
message = "An error occured while attemting to perform the last action. Sorry for the inconvenience.";
filterContext.HttpContext.Response.Status = "500 " + message;
I read this http://blogs.msdn.com/b/kcwalina/archive/2007/01/30/exceptionhierarchies.aspx where the author recommends using existing .NET exception types to report usage errors. However, by introducing my custom exception, I just have to do a single check in my filter. Is my approach okay?
I like this approach for a couple of reasons.
First, it fails safely. If someone doesn't explicity throw a ClientException, then the exception details are not reported. Forgetting to display something is a lesser problem than accidently displaying something.
Secondly, it allows the decision about whether to display the exception to be made at the proper place. Not all IOExceptions are displayed, for example. Some may be, and others wont be. The specific exceptions can be caught and transformed anywhere in the call stack, so that tranformation can be made at a place where it is known to be correct.
Both of those things together mean that a future developer will not innappropriately change a whole class of exception to be displayed, or think that something won't be displayed when it actually will be.
Also, the purpose of the using a particular exception type is to determine later what action to take in response to that exception. "Display this message to the user" is a perfectly good action to specify. Once that decision has been made, then the exact nature of the exception is completely irrelivant. (The original problem may be put in the InnerException property, for logging purposes, of course.)
So, in my opinion, this is a good design.
Your approach is fine IMO but there are alternatives. (We're software developers so there are always alternatives.)
You could harness the Exception Data dictionary to store a flag indicating whether or not an exception is a client exception. Then you could have your filter check for the existence of the flag.
If your approach works for you then it is fine. And are you surprised that a Microsoft blog is recommending that you use their Exception class? ;)
There are some .NET library features and 3rd party OSS stuff that will only work with .NET exceptions however.
To get the best of both worlds you could always extend the .NET Exception object into your own.
I would use different Threshold values based on the type of exceptions, and these Threshold values would be associated with the exception messages.
Based on the particular Threshold value logic you may want to decide whether or not to show exception.
My concerns with this solution is that very likely these exceptions will typically be thrown by objects in a business layer (or model objects in MVC terminology). The usage you describe is really what I would consider to be a presentation concern.
Typically you'd need to rethrow whatever exception you have in your model, only to communicate whether or not the exception can be exposed to the user or not.
What do you expect the user to do with the information? If the user can fix the situation perhaps there should not be an exception to signal the state to begin with?
I would stick to catching specific exceptions per case and do presentation decisions at the spot. You may send out an exception, as caught, used as model to a view though. I would still let the controller decide, not whomever throws the exception.
If I have a multi-layer Winform app with a Presentation, Business and Data Layer for example, and I encounter an error in either the Business Layer or Data Layer for which the only logical action is to log the error and inform the user that an error has occurred where should the logging take place?
Should I put the the methods in the Business and Data Layers in try catch blocks like so
try
{
DoSomethingThatMightGiveErrors();
}
catch(Exception ex)
{
logger.log(ex.ToString());
throw;
}
Or should I just let the errors bubble up to the presentation layer and handle the logging and informing the user there?
I'd put the logging at the business layer level and then rethrow the error. If this layer is used in another project in the future, it's already doing the logging. Rethrowing the exception allows consumers of this layer to convert the error into a friendly message.
EDIT: I think it depends a bit on the kind of logging: if you're logging to a central database, which is independent from the UI, put the logging in the business logic layer. If the logging is specific to the UI, for example writing a log file to the application's directory, put it in the UI.
If you are talking about unhandled (non-business related) exceptions just let them propagate to the UI layer where you could catch/log/inform the user.
My preference would be to place it in the business layer.
If you ever change the nature of
the presentation layer (i.e.
winforms to webforms) the logging
code won't need to be duplicated.
All of your logging will be a lot easier to find and maintain, as you can always scan the business class's list of methods and inspect/tweak them for logging. If you put the logging in your presentation layer, the logging calls will be scattered all over the place - a single business class could have logging calls made in many different presentation classes.
That depends on your requirements, like, for instance, do you want to put your users off your application as a result of errors showing up via bubbling up to the presentation layer? How often would these errors occur in unexpected situations?
This is a loaded question and every application is different, the most basic thing I can say is to use the try catch clauses in the business/data layers and ensure that you inform the users of certain situations where an error could be expected (You do have this in documentation?)
Other than that, check with the requirements and feedback from end users...if you allow the errors to appear on the presentation layer, the worst case is the user will refuse to work with it as a result of errors spewing out...
Hope this helps you,
Best regards,
Tom.