First, it depends on what you’re calling a layer. If they are layers of code within the same application, yes, the exception will bubble until someone captures it, in the latter case the . NET captures for you and does something (shows error in default form).
Exception is a complicated mechanism, it is a goto
that you don’t even know where you’re going. You are not required to deal with the failure (contrary to what many say about this mechanism) and do not know who will deal with it.
If you do it right, you don’t lose the stack trace, but for this it is important not to keep capturing to launch the exception again. The problem is that in codes that abuse exception and use as a validation mechanism it is common to do this, especially in layers, so your tendency will be to capture in one layer to launch something in another layer.
Often throw exceptions can be abstraction leak. It’s very complicated to make the exception be something natural, one of the reasons not to use it for flow control, as seems to be the case you’re wanting to do, because if they were used for exceptional situations you probably wouldn’t be living this dilemma.
Without a deep analysis it is complicated to give a definitive answer on the problem, and even more generic solutions cause controversy, I have seen people defending one thing or another.
If you use the exception correctly it should not go beyond the layer where it originates, another reason not to worry about the stack trace. In the repository it seems a suitable place to capture some very specific exceptions.
In the business layer rarely should have exceptions because there you will only have validations, only have things you have control, what fails is probably expected, is not exceptional.
But it is always possible to do something different. If it is the controller that mounts what will be shown to the user, there may be the proper location to capture a true exception. There are controversies about this, but one of the advantages of the exception is not having to go over it, you let it burst until you get to the place where you can do something useful, and most of the time is when you will interact with the user (although the controller not be the place of interaction, is the last code that will run on this layer of the solution, the side backend).
Thank you so much for the explanation, always very good read your posts.
– Nicola Bogar