What is the best practise for returning an error of a business rule in a BLL? SHould I just raise exceptions and catch them in the presentation layer, shoudl I return some kind of object that holds any exception type info?
The word "returning" is tricky here.
The primary virtue of multi-tier design is orthogonality. You should be able to call the classes in your BLL from an entirely different UI than the one you're currently using and handle logging completely differently.
If an exception is able to be handled without user intervention or notification, you should generally do so within the BLL. If the exception needs to be brought to the user's attention or logged, let it bubble up to the UI, which can implement notification and logging without building such things into the BLL.
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
I'm learning about layered architecture at the moment and I'm wondering how to add a logging system to such a design.
Now let's say we have three layers:
Presentation Layer
Business Layer
Data Access Layer
And assume that only a higher level layer is aware of the layer one level below. For example, the Presentation Layer is aware of the Business Layer but not the other way around.
Where should you implement a general logger class?
If I implement it in a different project, it means all the layers have a dependency on a common assembly, which may or may not be good. Though this can be overcome with dependency injection.
If I implement it in the highest level (in our case the Presentation Layer), it will defy the Single Responsibility Principle.
What is a good place to implement a logging mechanism?
And after implementing it, what is a way to use such a system?
It should ideally be able to catch uncaught exceptions and save the exception description somewhere.
Where should you catch exceptions? Should they be caught in the highest layer (the Presentation Layer)? Or should they be caught somewhere else?
And what is the way to use to pass a logger to a class? Does it make sense to add a method/constructor overload to everything in the project that accepts an interface like ILogger?
As you can see I'm pretty confused about the subject, and in my current job there's no one that has any knowledge about enterprise application design / layered design, even though they are designing enterprise applications. So any help showing me the right direction will be appreciated.
Logging is a cross-cutting concern. This means that it encompasses all layers of your architecture, and it makes sense to implement it as a separate library. However, this would only make sense as an exercise, since there are already very good solutions like Log4Net, NLog, and even .NET's own TraceSources.
I tend to prefer those which support hierarchical logging (e.g. log4net). This make it much easier to configure the desired tracing level in production systems. E.g. you could set general tracing level for MyApp.SomeNamespace to Warning, but also have set a specific type like MyApp.SomeNamespace.AnInterestingClass to Debug.
I am not sure I understood the "what is a way to use such a system" part.
You use logging everywhere it is needed, in all layers of your app, in each method which needs it. I am under impression that you have an idea of centralized place where all errors are handled and logged, but these are separate things.
It should ideally be able to catch uncaught exceptions and save the
exception description somewhere.
No, it shouldn't. Loggers write stuff to logs, they don't handle exceptions. Logging is not used only for reporting errors. You also want to log the execution of your application and many internal information (but with varying tracing levels), for the sake of troubleshooting the system in production or post mortem analysis.
Where should you catch exceptions?
At all levels. Many methods in your code will be handling the exceptions relevant to current context. I suppose that you really want to know where to handle the exceptions which were not caught elsewhere - some kind of catch-all handler. For this, often it makes sense to do it in the topmost layer, i.e. in your .exe or, more generally, in the layer which contains the types which represent the application itself. There are many ways to do it - from simply registering the handlers for the unhandled exceptions (ThreadException/UnhandledException) to HandleError/Application_Error in ASP.NET MVC to using something like exception handling application block, which I personally dislike (as most of Enterprise Library).
And what is the way to use to pass a logger to a class? Does it make sense to add a method/constructor overload to everything in the project that accepts an interface like ILogger?
It depends on your implementation. It seems that you want to go down the dependency injection path. Since logger is not an essential dependency (i.e. it is not related to functional behavior of types, but to the implementation), I would prefer to handle it via property injection as an optional dependency, instead of doing it via constructor which, IMO, should be used only for primary dependencies - those which are required for the type to function properly.
However, you might not want to use DI. Then you need some other way to get to logger. One option is discussed here.
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.
I have an n-tier web application, and I want to catch a specific type of exception in every method coming from the DAL (Data access layer) and rethrow it as a new exception of a specific type.
There are many methods in my DAL, so I don't want to start wrapping each one with try/catch.
I think this is possible using the Exception Handling Application Blocks, but i couldn't find any good documentation of how to do this...
I'm not familiar with the previous versions of the application blocks neither.
Has your DAL repositories got an interface?
I would implement the interface using a decorator pattern.
All the decorator does catches the exception and then builds a new exception and throws that out to the upper tier
As a point of note, in our n-tiered applications we always let exception just get thrown naturally and catch them in once single place and log them. We only create specific exceptions if we absolutely have to and that would be rare enough.
The reason for this is maintainability of code. Code can easily become unreadable when try/catches exist everywhere.
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.