C# Async SQL query

I have a general dislike for exception handling in languages like C#, Java, ...
View attachment 771178
...re documentation of exceptions is optional and the need to deal with an exception is optional... i.e. its design doesn't steer good practice, hence many get it wrong.
That picture is great in dark mode, only saw the text after quoting it. :p
But yeah, being forced to define what will fail can be is good, but can be annoying if working on generic stuff (I'm assuming you're referring to F# way as this is C# discussion), or I like golang's approach where it's a separate value with 3 levels (defer, panic, recover).
 
The thing is, why I put the exception handling in the data layer is that it is actually independent from the business layer and visa versa. One could say, that this data layer and use it in another project. But what I someone did that and they did not use exception handling properly or at all. The app would just go down in flames if say a connection string was wrong and nobody would be the wiser.

Does that make sense? :)
When I get an empty list back does that mean my query returned 0 results, or there was an error....
 
That picture is great in dark mode, only saw the text after quoting it. :p
But yeah, being forced to define what will fail can be is good, but can be annoying if working on generic stuff (I'm assuming you're referring to F# way as this is C# discussion), or I like golang's approach where it's a separate value with 3 levels (defer, panic, recover).
Nope, F# as a .net language also has the same exceptions; it's just called try / with instead of try / catch -- same design, same problems as C#.

Only difference is that many F# programmers tend to avoid that style of exception management; and the tools they reach for are available in C#, Java, Kotlin, etc. There's however no way to avoid it if a 3rd party dependency uses exceptions -- the approach in that case is to build a custom wrapper around the API to more elegantly deal with exceptions and concurrency issues (as needed).
 
When I get an empty list back does that mean my query returned 0 results, or there was an error....
Exactly... but how often have you found code that doesn't adequately deal with the exceptions that could be thrown by a function, or even worse... found code that doesn't document the exceptions that could be thrown.
 
Last edited:
Exactly... but how often have you found code that doesn't adequately deal with the exceptions that could be throw by a function, or even worse... found code that doesn't document the exceptions that could be thrown.
Rarely? Most of the time exceptions are from some I/O stuff, which generally has quite a good list of exceptions that can be thrown. That said, design is always catch general exceptions as well at highest level, just in case, save the world you know. ;)
 
^^ This. I had a explanation on the old MyBB site but that is gone now. The only reason to handle an exception in a DAL would be to:

...
that is doing something useful and then rethrowing the exception to bubble up.
Agreed... on that level one is very much limited to design of the API -- only alternative is to build a wrapper API.

Ideally you dont want your dal to be dependent on a logger. By using it in the way you show, you have a dependency. What if you have some other code from someone that is dependent on a totally different logger like yours are. Now you HAVE to use both as both sets of code have their own dependencies. Rather let the exception bubble up. It is easy to determine the type of exception in the higher level catch blocks ( <--plural! ) and handle accordingly. Exception handling strategies are a thing. At the higher level you can handle the specific type of exceptions and log that exception to logger and then throw a user-friendly exception insttead.
...
Agreed... however as your code also illustrates there's nothing in the signatures that specifies what exceptions could be throw, and nothing that forces a higher level code block to deal with it.
 
Rarely? Most of the time exceptions are from some I/O stuff, which generally has quite a good list of exceptions that can be thrown.
That really depends on the discipline of the team(s) you work with...

That said, design is always catch general exceptions as well at highest level, just in case, save the world you know. ;)
As I originally said "pass the buck"... because ....
 
Agreed... however as your code also illustrates there's nothing in the signatures that specifies what exceptions could be throw, and nothing that forces a higher level code block to deal with it.
Exactly... that is why many/most programmers use catch(Exception e). Partly because they are lazy and dont bother looking at the docs at to what exceptions may be thrown and 2nd, you are lucky if the exceptions are documented at all.
Each level of the call stack needs to know what exceptions the lower level might throw in order to either handle it or document it as a possible exception that will bubble up from a lower level past this level if not handled t this level. Nightmare of note
 
It is a nightmare of note and I think most guys would rather just catch and log and read the logs.

Earlier on in my career I did not implement any exception handling. Then when I did start implementing it I would throw the exception. Then someone at some or other job or forum said "Dude why are you throwing your exceptions you need to deal with them when and where they happen." So that's where the confusion came in. It makes sense to bubble it up the stack and in case something else broke along the way that needs to be identified too.
 
I doctored something up quick. Not sure if this is a great way to do it but here goes :X3:

C#:
        [Serializable]
        public class WithdrawalAmountTooLargeException : Exception
        {
            public WithdrawalAmountTooLargeException(string message)
                : base(message)
            {
                return;
            }
        }

        [Serializable]
        public class AccountNotFoundException : Exception
        {
            public AccountNotFoundException(string message)
                : base(message)
            {
                return;
            }
        }

C#:
            try
            {
                if (AccountLimit < AmountWithdrawn)
                {
                     //Able to withdraw from account
                }
                else
                {
                    throw new WithdrawalAmountTooLargeException("Withdrawal amount is too large.  Overdraft limit reached!");
                }

            }
            catch (WithdrawalAmountTooLargeException ex)
            {
                Log.Error(ex.ToString());
            }

C#:
            try
            {
                if (account != null)
                {
                    //Do something with account
                }
                else
                {
                    throw new AccountNotFoundException("Account not found!");
                }
            }
            catch (AccountNotFoundException ex)
            {
                Log.Error(ex.ToString());
            }
 
Last edited:
I doctored something up quick. Not sure if this is a great way to do it but here goes :X3:
...
Custom exceptions are a poor choice for the success/failure scenario you've presented.
Exceptions not only have a cost re performance, efficiency, documentation, ..., they're unary; meaning there'ss no concept of a composition of exceptions, and worse you're effectively creating program flow that's akin to a new age "goto" -- ref. spaghetti code.

I suggest you read up about best practices wrt exceptions and also look into alternatives e.g. non unary error handling, etc.

FYI here's a few examples that discuss this.
 
Top
Sign up to the MyBroadband newsletter
X