The Exception Mistake You Must Never Make in C#

  Рет қаралды 43,337

Nick Chapsas

Nick Chapsas

Жыл бұрын

Check out my courses: dometrain.com
Become a Patreon and get source code access: / nickchapsas
Hello everybody, I'm Nick, and in this video, I will show you one of the most common mistakes when it comes to exception throwing and explain why it's bad and how you can avoid it.
Workshops: bit.ly/nickworkshops
Don't forget to comment, like and subscribe :)
Social Media:
Follow me on GitHub: bit.ly/ChapsasGitHub
Follow me on Twitter: bit.ly/ChapsasTwitter
Connect on LinkedIn: bit.ly/ChapsasLinkedIn
Keep coding merch: keepcoding.shop
#csharp #dotnet

Пікірлер: 114
@MarkRendle
@MarkRendle Жыл бұрын
First
@StuartQuinn
@StuartQuinn Жыл бұрын
FirstOrDefault()
@PreuKaiser
@PreuKaiser Жыл бұрын
Single
@Neonalig
@Neonalig Жыл бұрын
!First
@kamilmikua5794
@kamilmikua5794 Жыл бұрын
FIFO
@bauckrob
@bauckrob Жыл бұрын
A related mistake might be not to provide the inner exception when throwing a new exception.
@notbalding
@notbalding Жыл бұрын
throw new CustomException("Custom message", ex); should also work without losing your stacktrace. Edit: The thrown error at line in stacktrace will be CustomException line while 'throw' will keep the line where the error was actually thrown.
@petrusion2827
@petrusion2827 Жыл бұрын
Right, but you should only do that if you have some useful info to add to that custom exception, otherwise you're only adding the need for the debugging developer to look at potentially multiple inner exceptions for no added benefit. I sometimes do this when I'm working with *checked { }* blocks to give more meaning to the overflow exception by wrapping it in an ArgumentException, UnreachableException etc.
@toks1396
@toks1396 Жыл бұрын
@@petrusion2827 even the name of your custom exception does add useful info without any additional data. You could easily add different logic handling your custom exceptions if need be.
@petrusion2827
@petrusion2827 Жыл бұрын
I didn't know it isn't just syntactic sugar. This is neat and good to know.
@nove1398
@nove1398 Жыл бұрын
Found out about this a while back, but it is a good point to make. It is easy to think that "throw ex;" is a smarter thing to do at that point of catching the exception.
@yazanshakhshir3049
@yazanshakhshir3049 Жыл бұрын
I also saw many people still doing this mistake! Thanks a lot Nick for the great content you provide man🙏
@canijo56
@canijo56 Жыл бұрын
ExceptionDispatchInfo can help to capture exceptions that can be throw later. Also AggregateException is usefull to throw multiple exceptions toguether
@novak-peter
@novak-peter Жыл бұрын
What I am more interested in is WHY the stack trace erasure happens, and if so why Microsoft did not solve it?
@pilotboba
@pilotboba Жыл бұрын
A couple common ones I see: Use stringbuilder instead of concatenation while building long strings. Dealing with stuff as strings when there is a class for it. Like Uris, File Paths, Connection Strings, etc. Using [EF|Database] queries in a loop, rather then querying for the set and looping through the set. Huge perf issues here.
@g3ff01
@g3ff01 8 ай бұрын
I'm not sure I understand correctly. I would assume, it's better to ""download" (query) a bigger chunk from the database, then loop on it, then asking from a (possibly remote) database server several times each after each. What am I overlooking?
@pilotboba
@pilotboba 8 ай бұрын
@@g3ff01No you got it. I was saying querying in a loop was bad. Query for all the rows and loop over the result set.
@inthemedium
@inthemedium Жыл бұрын
The other mistake is to catch “fatal exceptions” (e.g. OOM, threadabort, etc). The application can get in really bad state when people catch and ignore or try to do some kind of recovery on these exceptions.
@billy65bob
@billy65bob Жыл бұрын
When it comes to APIs, I made my own IExceptionHandler and IExceptionLogger implementations and registered them in the HttpConfiguration. The former basically just returns a nice error message... unless you used a token with the aptly named 'CanSeeExceptions' permission. The latter logs the request, with redacted parameters. As for exception related 'problems', only one I have is that sometimes people make the scope of the function and the handler quite big. And if you're missing line numbers, well then, you've got a null ref and a 1000 places it could be...
@akab211
@akab211 Жыл бұрын
What an exceptional video from you!
@user-cl1ul7de5l
@user-cl1ul7de5l Жыл бұрын
Sometime you don't wanna let client know, what is real exception ;-)
@josesousa8244
@josesousa8244 Жыл бұрын
Straight to the point, nice video 👍
@ABC_Guest
@ABC_Guest Жыл бұрын
One mistake that I've encountered recently was having a try/catch around a function which returns an IEnumerable, if the enumerable isn't iterated on before the end of the try block, it will not be caught there.
@jozsefszabados1183
@jozsefszabados1183 10 ай бұрын
Thanks for the content!!! 😎😎😎
@failgun
@failgun Жыл бұрын
There are some legitimate reasons for doing this - for example if you're designing a closed-source library and you don't want to expose details of your code structure or dependencies, but still need to throw an exception to the caller
@ryanjean
@ryanjean Жыл бұрын
Ahh, the perils of "Exception driven development." Throwing ex versus just throwing versus the very rare throwing new exceptions are one of the first things I had to make sure I got right in my early years working in dotnet. Another that's related to this was to actually try to be much more picky and explicit about the types of exceptions I'm catching so that I don't catch exceptions unnecessarily and end up hiding flaws in my code.
@thebitterbeginning
@thebitterbeginning Жыл бұрын
UNRELATED... I'm sorry, but I laugh out loud every time I watch one of your videos...which are great, by the way! Thank you! "Hello everybody, I'm naked...and in this video..." Every time my wife comes by and hears me play one of your videos, she laughs too. We can't be the only ones who've mis-heard your name. ...but don't change your introduction on account of my dumb a$$. Your content, your presentation, your energy is awesome! ...and it's good to start the day with a laugh. Thanks again for taking the time to share all this great information.
@StephenMoreira
@StephenMoreira Жыл бұрын
Thanks for the tip!
@Esgarpen
@Esgarpen Жыл бұрын
What about Maybe i.e. TryFirst() vs T?
@atziazas
@atziazas Жыл бұрын
Nick do you recommend using your Cosmonaut library at this time? It has not been updated in a little bit and I was curious as to whether you think it is still good to use.
@BenMakesGames
@BenMakesGames Жыл бұрын
a basic mistake I see a lot of is just tossing null-forgiving `!` (or `null!`) on things without thinking about whether or not it should be used. I think it's partly due to some libraries not being great about NRTs (including Blazor! I really hope MS tidies this up!), which kind of "normalizes" null-forgiveness, or desensitizes devs to its importance.
@Liphi
@Liphi Жыл бұрын
What about passing ex as a parameter to a new Exception as an inner exception? It might be useful if you want to "change" exception type
@xlerb2286
@xlerb2286 Жыл бұрын
That can work very well. It also allows you to have your code only throw one exception type, perhaps a custom exception, but still have that original exception available. I do that quite a bit when writing libraries. I want that original information to be available to the caller but still present an exception that is more in keeping with the level of abstraction of the library.
@gctypo2838
@gctypo2838 8 ай бұрын
Perfectly fine if your intent is to add some extra context in the wrapping type that wasn't in the original exception. The original stacktrace is still there in the inner and it'll still be shown in the printout.
@Tsunami14
@Tsunami14 Жыл бұрын
As for similar small things, I can't tell you how many times i've seen people misuse DataTables when checking query results. i.e. doing ToString()s and hard casts on datarows instead of dr("column_name"), and all the shenanigans with DBNull.Value.
@josephizang6187
@josephizang6187 Жыл бұрын
Thanks Nick
@90vackoo
@90vackoo Жыл бұрын
Thank you for the content 😊 Is throwing an exception or logging an exception better when it comes to dealing with exception handling in an API application? For example while fetching an API response there could be some unforeseen exception and I don't want to pass those stack trace details to the consumer of the endpoint but at the same time will log the exception for the sake of traceability and debugging for the developer of the API . What would you recommend as an ideal approach?
@krzysztofmilewski9516
@krzysztofmilewski9516 Жыл бұрын
Ideally you should log the exception, and return HTTP error from your API with some generic error message that doesn't expose any details. The developer will use application logs for analysis.
@emmandev
@emmandev Жыл бұрын
8 minutes well spent. I have also done these mistakes in the past.
@xlerb2286
@xlerb2286 Жыл бұрын
A somewhat related error I still see is people confusing when to use Debug.Assert() and when to validate parameters. For example: public void SomeLibraryFunction(string myParam) { Debug.Assert(null != myParam); //
@hichaeretaqua
@hichaeretaqua Жыл бұрын
Actually I think that there is a situation where I'm totally fine with throwing a new exception. When I catch an Exception from another layer of abstraction and/or can enrich the exception with more information. But in this case I would never throw a raw Exception, it would always be a custom exception with the catchend Exception as inner Exception. Btw, I consider throwing a non custom exception a code smell.
@Thorarin
@Thorarin Жыл бұрын
One thing I've seen way too often is people using some variation of ToLower or ToUpper to do case insensitive string comparisons. Not quite as big a problem as improper exception handling, but it makes me sad just reading the code 😕
@nikogj9495
@nikogj9495 Жыл бұрын
Hi @NickChapsas I've seen on multiple places on the internet that his pattern of catching an exception, logging it and rethrowing it (log and throw), is considered an anti-pattern. Have you heard of it and what's your point on this ?
@northshorepx
@northshorepx Жыл бұрын
Nick, did you ever do a video on using error details for returning information from HTTP endpoints?
@danielferri2948
@danielferri2948 Жыл бұрын
_logger.LogError(ex, "") will not record the original stacktrace? how can i capture the original one in logger with only throw?
@F1nalspace
@F1nalspace Жыл бұрын
Great information, didn´t knew that! What about you want to throw a different exception with more informations, such as paths, names, etc.? How do i pass down the full original information, so that the stacktrace is preserved? new MyException("bar whatever foo"", ex);
@reikooters
@reikooters Жыл бұрын
Let's say you're catching this exception and outputting it to a log file, after you log the exception you created, you then need to "while (exception.InnerException is not null)" 1) log the exception then 2) exception = exception.InnerException. So you log all the Inner exceptions, even inner exceptions to the one that wasn't thrown by you, since they could contain additional helpful info. For example an exception that was thrown when sending an http request may have a SocketException as the inner exception. The inner exceptions will have the full original information.
@noemi.farkas
@noemi.farkas Жыл бұрын
Interesting. Thank you! :)
@superpcstation
@superpcstation Жыл бұрын
Nick what about ExceptionDispatchInfo.Capture(ex).Throw()? Is it different from just throw?
@leandroteles7857
@leandroteles7857 Жыл бұрын
That's exactly the thing that produces the "stack trace from previous location" section. It's used behind the scenes in async/await, because it needs to capture an exception and rethrow it in a completely different context (possibly other thread), so "throw;" doesn't apply in that case.
@jameshancock
@jameshancock Жыл бұрын
I'd love to see an analysis of throw with global handler versus try/catch on everything and returning Problem or BadRequest. I hate the later, but I suspect it's faster.
@brandonpearman9218
@brandonpearman9218 Жыл бұрын
Do you need it to be faster?
@jameshancock
@jameshancock Жыл бұрын
@@brandonpearman9218 It's one of those things where most of the time not, but you'll appreciate the money you save when you're under a DDOS attack and they're sending massive malformed requests that are causing memory and CPU overhead.
@buriedstpatrick2294
@buriedstpatrick2294 Жыл бұрын
Wait, so what about throwing a new custom exception that wraps the caught exception? Like: catch (Exception ex) { throw new FailedToRetrieveWeatherException(ex, city); } Where the custom exception inherits from Exception and simply passes along the inner-exception? Is important stack information lost here?
@no-bc4kc
@no-bc4kc Жыл бұрын
I learnt something new today.. noice 👌👌
@etshbadr
@etshbadr Жыл бұрын
A very good point to make.
@99aabbccddeeff
@99aabbccddeeff Жыл бұрын
An interesting mistake can be using Thread.Sleep instead of Task.Delay in async code.
@nocturne6320
@nocturne6320 Жыл бұрын
I was already following the ReShaper suggestion for this, but thank you for clarifying the details. ReSharper combined with SonarLint is a must-have for C# development imo.
@tropictiger2387
@tropictiger2387 Жыл бұрын
One try/catch mistake I can think of is where to put your try/catch statements. I've seen people putting it only on the highest level and nowhere else. This means that if things change it becomes easy for the try to no longer catch the exceptions it was supposed to.
@ErazerPT
@ErazerPT Жыл бұрын
How can your entry point not catch(Exception ex)? If you have a try/catch on the entry point that has say catch(DivideByZeroException dzex) but doesn't have a catch(Exception ex) block, you're doing two things wrong not just one.
@surgeon23
@surgeon23 Жыл бұрын
Yeah, we had fun with this 10 years ago or so because throw ex was used all over the place.
@moatazal-ali2145
@moatazal-ali2145 Жыл бұрын
Hi nick …can you make a video talking about ( Ocelot ) and load balancing APIs
@comod
@comod Жыл бұрын
Do other languages behave the same? Php for example?
@electrocatalyst
@electrocatalyst Жыл бұрын
But shouldn't the ex object contain all the previous context? (I'm not asking if it does, only if it *should*.)
@JohnOliverAtHome
@JohnOliverAtHome Жыл бұрын
My issue is with logging. Yes, we log the exception object, but generally the message with use with the log is the outer exception message. If I'm looking at error logs (say SEQ), I want to see the actual exception from the inner exception. Yes, this does break down when the inner exception has another inner exception, but this is a rare event.
@YungDeiza
@YungDeiza Жыл бұрын
False, logging the object should provide all of the necessary information unless you have some logging configuration that overrides it. You get only the outer message when you log exception.Message.
@reikooters
@reikooters Жыл бұрын
I tend to use my own helper method which takes an exception and builds and returns a string which I use for logging, i.e. includes the source, type, message and stack trace, and loops through all the inner exceptions. Also checks the type of each exception to do extra stuff as sometimes there is additional information you can get. For example, on an SqlException, you can get the list of errors thrown by the database with line numbers from the query from the SqlException.Errors array. I use that for things like sending email alerts and logging to a text file with Serilog. Haven't used SEQ before so can't say if this approach would play well with it.
@davidwilliss5555
@davidwilliss5555 Жыл бұрын
If you want to throw a new exception, do something like throw new ApplicationException(""Failed to retrieve weather", ex). That will make the original exception with all its stack trace an InnerException. (I just read @notbalding comment - he said it better) The worst thing I've seen is somebody just logging ex.Message and not the whole exception. That gives you no context. And then they ignored the exception and let the code continue which would of course fail because something was null and then they'd just log the message about a null reference. Very frustrating to debug.
@J_i_m_
@J_i_m_ Жыл бұрын
Never underestimate the creativity of a developer, things could be even worse! I've seen code from a big tech company that was using a "SuccessfullyDoneException", just to break out of the routine when things were successfully finished.
@rogeriobarretto
@rogeriobarretto Жыл бұрын
Should you use catch "SpecificException" or catch Exception when SpecificException? IL seems to be bigger using when, so my assumption would be to multiply your catches
@gctypo2838
@gctypo2838 8 ай бұрын
Always catch the most specific type you intend to handle. If you intend to handle a larger scope, then that's what you should catch. For example, if you're at the top of the application stack and your intent is to handle an "if all else fails" situation by logging, showing an error message, and gracefully closing, that's a perfectly valid reason to catch a base type. But if your intent is to handle (for example) an InvalidOperationException, than catch just the InvalidOperationException. Just catch what you intend to handle, so you don't accidentally try to handle what you aren't able to. Otherwise you'll end up hiding errors you didn't expect. And if you're worried about performance, keep in mind that any exception still makes a sizeable performance hit due to constructing the stacktrace, so if you're able to error-handle proactively before an exception would otherwise be thrown, do so.
@DanBottiglieri
@DanBottiglieri Жыл бұрын
The one I see a lot is people calling ToList on Enumerables when they don't need to.
@zabustifu
@zabustifu Жыл бұрын
In general, when many developers get something wrong, it's a sign something is not very natural or explicit about a language or framework. Ideally, the language should be clear enough that little to no explanation is needed to figure things out. For example, instead of doing "throw;", it could have been called "rethrow;", maybe (then again, reusing the same "throw" keyword is kinda nice, so I don't really know).
@ryanboggs3924
@ryanboggs3924 Жыл бұрын
It's 2023 and I, too, am still seeing this issue in a lot of code these days. Thanks for calling this out in your vid.
@darthfikus5206
@darthfikus5206 Жыл бұрын
catch(Exception ex) { string message = ex.Tostring(); message = ""; } This the actual code running on a 300+ places in an 20+ year old application i am refactoring for the past few months.
@gbsyi_
@gbsyi_ Жыл бұрын
As I remember there already was a video from Nick about this problem 🤔
@nickchapsas
@nickchapsas Жыл бұрын
It was a short
@leandroteles7857
@leandroteles7857 Жыл бұрын
There's an even better, although uglier, way of doing this: by using an exception filter to call a function that always returns false. This way you get a chance to log the exception without actually "catching" it.
@kocot.
@kocot. Жыл бұрын
most static code analyzers pick it up, AFAIR even the default one in VS
@AnythingGodamnit
@AnythingGodamnit Жыл бұрын
This is why F# has raise and reraise. C# should have had throw and rethrow.
@cdarrigo
@cdarrigo Жыл бұрын
Don't return void from async methods
@cdarrigo
@cdarrigo Жыл бұрын
Please do a video on ConfigureAwait()
@amirparcheko1
@amirparcheko1 Жыл бұрын
@nickchapsas nice haircut btw 🙂
@gctypo2838
@gctypo2838 8 ай бұрын
5:45 I see this all the time in a legacy codebase and I absolutely _hate_ it. The message is often the least useful part of the exception. The stacktrace is almost always the most useful, and usually the type of the exception after that. When rethrowing, either use a bare `throw;` to continue unwinding with the original exception, or wrap it as an inner exception and use the new outer exception to add additional context. Additionally, there is *NEVER* a valid reason to throw the base System.Exception type. There's a lot of things where "never" should be treated as "almost never", but this one really is "never". Throw the most specific and applicable type for your error. There is zero benefit from throwing the base type, only downsides.
@alfany6252
@alfany6252 Жыл бұрын
throw new FirstCommentException("Zaaamn");
@Punkologist
@Punkologist 11 ай бұрын
A rare occasion where I see one of your videos that says "Don't make this mistake" and I'm not making it :)
@jk-dev4776
@jk-dev4776 Жыл бұрын
Thank you. I knew that you could do "throw;" or "throw ex;", and that the analyzer suggests the former. But I didn't ever read why the analyzer suggested that. I always assumed that it was simply a style suggestion.
@parlor3115
@parlor3115 Жыл бұрын
Only a problem if the exception originated from your code. If it's from a library code, then you're not missing out on much (unless the library is poorly developed).
@jtrc19953
@jtrc19953 Жыл бұрын
Only if you're okay with not reporting potential bugs to the developers of libraries you depend on
@parlor3115
@parlor3115 Жыл бұрын
@@jtrc19953 The bug can be detected from a highier level. I'm not going to stop work to track down a library code bug.
@uqashagedik1361
@uqashagedik1361 Жыл бұрын
I love you ❤
@nanvlad
@nanvlad Жыл бұрын
In my opinion this is C# design flaw, because it's intuitive to throw something rather than just throw; And if I throw the same exception it turns out that behind the scenes C# throws a new Exception from the same place we throw it. That's why previous stack trace is missing. As a workaround we can throw new Exception and pass original one within InnerException property - that at least Microsoft could implement behind the scenes.
@finickyflame
@finickyflame Жыл бұрын
The stack trace is built when you do the throw, and not when you create the exception. Throwing a variable doesn't mean it's referring to a new or an existing exception, so it will insert the current stack trace anyway. To not have this problem, c# would need to expose the "GetStackTrace" so devs can put it themselves in the exception and not have it added on the throw.
@justwatching6118
@justwatching6118 Жыл бұрын
I predicted that this will be the case 😅
@Kingside88
@Kingside88 Жыл бұрын
A small thing many do not understand is to avoid nested scopes if possible.
@MechMK1
@MechMK1 Жыл бұрын
This is also checked by CA2200.
@codeyhuntting8830
@codeyhuntting8830 Жыл бұрын
7:06 - Justification: "I'm making a video"
@Knuckles2761
@Knuckles2761 Жыл бұрын
Got it. Never develop a weather app. Good advice indeed.
@inayelle1044
@inayelle1044 Жыл бұрын
var task = DoSomethingAsync(); vs var task = Task.Run(DoSomethingAsync); Might be the case
@krss6256
@krss6256 Жыл бұрын
Another common mistake: `async void`
@alijamal7893
@alijamal7893 Жыл бұрын
i don't throw exception any more 😅
@TellaTrix
@TellaTrix Жыл бұрын
I was wrong !
@doofernz
@doofernz Жыл бұрын
An 8 minute video for a 60 second explanation...
@7r4k1r
@7r4k1r Жыл бұрын
For anybody interested - logging and immediate re-throwing the same exception is an anti-pattern. Logging should be part of handling the exception, and in here you're not handling it. Frequently, the caller will handle the exception by logging the error as well, and you'll end up with the same error logged multiple times. People do this, because they don't want to learn who is handling / should handle the exception and think it's better to be safe than sorry. A very lazy attitude that can easily lead to log spam.
@novak-peter
@novak-peter Жыл бұрын
You are right, however I can list you at least one reason why logging multiple places could be useful: some context information may be only at certain places which you also want to log however you don't want to loose the original exception itself
@7r4k1r
@7r4k1r Жыл бұрын
@@novak-peter You can always have the original exception as the inner exception. You would create a new instance of a more specific exception, add the context information to it, and provide the original exception as the inner. This way, you don't lose any context information and have the original exception available for the exception handling / logging.
@dsalodki
@dsalodki Жыл бұрын
Obvious thing
@Tsunami14
@Tsunami14 Жыл бұрын
Another common misconception I see is with the lazy'ness of LINQ queries, and that most LINQ expressions are just attaching a set of processing instructions to an existing collection.
@nooftube2541
@nooftube2541 Жыл бұрын
Without ExceptionDispatchInfo.Capture(ex).Throw() this video doesn't cover the problem entirely. Plus it good to mention that throwing a new exception with passing original exception as inner exception is also good.
@DxCKnew
@DxCKnew Жыл бұрын
And also if you catch TargetInvocationException, don't throw ex.InnerException, but instead ExceptionDispatchInfo.Capture(ex.InnerException).Throw();
@i_fuk_religion
@i_fuk_religion 8 ай бұрын
After watching your videos, it feels like all the programming I have been doing is just wrong..
6 C# Mistakes Microsoft Wants You to Fix
12:57
Nick Chapsas
Рет қаралды 61 М.
How to use Discriminated Unions Today in C#
17:09
Nick Chapsas
Рет қаралды 60 М.
Summer shower by Secret Vlog
00:17
Secret Vlog
Рет қаралды 14 МЛН
НРАВИТСЯ ЭТОТ ФОРМАТ??
00:37
МЯТНАЯ ФАНТА
Рет қаралды 8 МЛН
Пранк пошел не по плану…🥲
00:59
Саша Квашеная
Рет қаралды 7 МЛН
The 3 Biggest Mistakes of Object Mapping in .NET
11:33
Nick Chapsas
Рет қаралды 63 М.
The New Way of Parsing ANY Type in .NET
13:03
Nick Chapsas
Рет қаралды 68 М.
8 await async mistakes that you SHOULD avoid in .NET
21:13
Nick Chapsas
Рет қаралды 310 М.
The BEST way to reset your database for testing in .NET
13:14
Nick Chapsas
Рет қаралды 60 М.
3 .NET "Best Practices" I Changed My Mind About
10:16
Nick Chapsas
Рет қаралды 102 М.
C# Async Await Mistakes | Part 1
10:19
Amichai Mantinband
Рет қаралды 32 М.
The New Way of Calling Your Code in .NET 8 Is INSANE
12:34
Nick Chapsas
Рет қаралды 135 М.
The High Performance Types You Ignored for Years in .NET
10:14
Nick Chapsas
Рет қаралды 45 М.
The Importance of Error Handling in C
8:18
Nir Lichtman
Рет қаралды 29 М.
I Handled All Exceptions in 5 min! 💙 .NET 8
5:09
Gui Ferreira
Рет қаралды 3,4 М.
Summer shower by Secret Vlog
00:17
Secret Vlog
Рет қаралды 14 МЛН