Stop using async void in C#! Do this instead.

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello everybody I'm Nick and in this video  I'm going to show you why you should not be   using async void in c-sharp and how you can  accidentally fall into the Trap of using it   which can actually lead in your application dying  unexpectedly if you like a lot of content and you   want to see more make you subscribers in this  notification Bell and for more training check   out Nick chapsters.com but before I move on I'm  extremely happy to announce that I just launched   my brand new course from Zero to Hero rest apis  in.net it is the only course you need to learn   how to build elegant rest apis in.net and is  effectively the combination of what I learned   in the past six years of my career building rest  apis for millions of customers and some of the   biggest companies in the world it starts from the  theory and the most basic features of rest apis   and it goes into some of the most advanced ones  like building sdks for your consumers to consume   your rest API programmatically and even contains  a migration guide to move from controller based   apis which this course is using into minimal apis  now originally I was offering the has 200 of you a   15 discount with code rest15 however you smash  that way too quick so I'm adding an extra 200   usages to that discount code so another 200 of  you have now the chance to get that cost the 15   discount with code rest 15 okay now back to the  video so let me show you what I have here I have   a simple console application in dot Net 7 and the  only thing I really have is a print to say start   then I'm running some method I'm awaiting it and  then end and in this background task as you can   see all I'm really doing here is I'm having an  async task that I'll wait for a second and then   just says waited for one second and that is it  and as you might expect if I just run this method   as it is all I'm gonna get is start wait for a  second print wait for a second and then end and   that is it however now I'm just waiting for that  background task sequentially so even though it is   an asynchronous operation meaning that thread will  go and do something else I'm still waiting and I   can't move any further what if I wanted that to  be a fire and forget yet well what you might be   likely to do is one of two things you might go and  say you know what I'm not gonna wait for this and   if you do that then if I just run it what's gonna  happen is you're gonna get start and and nothing   that doesn't mean that the task did not start in  fact it did start and it will complete and I can   actually prove this by saying console.read key and  read key will effectively wait for me to press a   key in the console so the console will still be  running meaning I will be able to see what this   task is doing so if I go ahead and I run this then  it's going to say start and wait for a second and   then say wait it for a second and I can press  any button and just do this and that is it it   is now exited I do however get a warning saying  hey you have an async task here so you probably   want to wait it which is not actually what I want  to do so what you might think of doing is I know   it fixes this warning I'm gonna turn this into an  async void now and this is now truly if I don't   forget and if I run the application this will just  work no questions asked very very simple start and   wait for a second everything works like before and  if I say enter here it exits and on surface level   this will work however there's a few interesting  caveats with this approach with the most important   one is how it can actually cause your application  to completely fail let's take a look at the   simpler case if I go and I say file dot read  all lines async and I add some sort of real job   in this method not just waiting asynchronously  and just printing something so I say read all   the lines of the file at dot txt file well this  file doesn't exist so if I do that I'm gonna get   an exception now what do you expect to happen  here you can pause and think but it might not   be something you're expecting I'm gonna go ahead  and just run this obviously reading a file doesn't   exist Frozen exception exceptionally thrown the  application crashed completely it won't boom if   I scroll all the way up it's gonna say of course  start and wait for a second and then it's gonna   throw the exception and there's an unhandled  exception file not found exception and this   exception caused the application to completely  fail this behavior is unique to async void if   this was actually a task and nothing changes in  the method itself of obviously I'm gonna get the   warning but that's about it the operation will  still run then if I run it it's gonna get the   exception but no I didn't even get it printed  so both behaviors are actually interestingly   problematic but one literally kills your  app interestingly enough if I do add their   weight here and I still have the async task  then it's gonna wait throw the exception and   then it's gonna crash so sort of three different  behaviors but this one you'd expect because here   nothing actually handles the exception while  in this one since this is a fun and forget   you wouldn't want something that you fired and  forgotten about to cause your application just   completely crash so be very careful this now you  might be thinking oh I know what I can do to fix   this I can go here where I'm calling this for  and forget and I can say try and then I'm gonna   just print the exception but I'm not gonna do  anything about it I'm just gonna let it run   and this would be wrong if I do this watch what  happens I'll just run this start and exceptional   Throne application crashed so it was not actually  caught here which is another interesting Behavior   because if you're used to just thinking of code  as this thing executing sequentially you wouldn't   know that the context of this file and forget is  not going to be caught by this try catch Clause   you would actually have to go in the method itself  in here and you would have to wrap this thing in   a try catch and then if you were to do this and  you run it then the exception will be caught it   is printed but the application is not failing it's  still running and I can press enter and now it   access because I provide the key for it can reset  and this is clearly the obvious way of visualizing   any single weight but you can actually create  an async or weight accidentally Without Really   noticing so I'm gonna just remove this tricass  from the method and I'm gonna go back here and   I'm gonna create a list of numbers so I'm going  to say numerable dot range0 and then 10 and I'm   gonna get a list of them so two lists and list has  this method called for each so if you want to run   something for each number you might be likely  to just say something like this for example I'm   gonna go big g dot task and I'm going to add a new  method in here called run task async so this thing   is a task and it accepts an i and then wait for  half a second and prints it and if I go in here   and I say just run task async obviously this says  hey you should await this but I am within this   forage so I'm gonna say just async and a weight  here if I do this what you might expect would   happen I'm gonna get start and and then after  all the waiting the things will execute out of   order even though they did start in order but the  interesting thing about this is that if I go ahead   and I just sneak an exception in here because I'm  doing something then if I run this even though it   is an async task will the exception is thrown the  application will exit even though this is a task   that's because for each and many methods that  accept delegates will not actually accept the   appropriate type here this is an action of type T  and action is effectively avoid what you want is   a function that returns a task of type t for this  to actually have the true semantics of an async or   writable method so when you see action overload  you don't want to make them async here Ryder   thankfully tells me that hey what you're doing is  wrong but I don't know if every ID will warn you   so you have to be very careful if you want to do  something like this so if I had for example fire   and forget methods here this method would be bad  if I just said you know what uh go here bgtask   dot find forget and then pass that same thing in  there one over here so if I run this it has the   same problem it is an action of type T it's going  to just completely crash but if I had an overload   in here which was of type func that returns a  task then obviously the error goes away because   now it's using the right overload it's using the  function that returns task so if I go ahead and   I run this it's going to suffer from the other  problem which is there's still an exception but   it's behind the scenes you can still catch it in  the context and deal with it but it doesn't crash   your application so very important difference all  right Nick so you told me what not to do but if I   actually want to have a careful file and forget  what should I do well there's many approaches to   do this it's not necessarily you know one right  or one wrong approach but one thing you can do   is to Simply use task dot run so if I want to  run an async task I'm going to keep this as an   amazing task I'm not going to use async void and  I'm just going to say vg.task run on async and   that is it no warnings no you should await this  no nothing and if I do run this then this will   just work fine exactly as you'd expect I still  get the exception in here but it has this silent   effect as before you can still catch it in here  and do whatever you want for example if I say try   catching here and I catch the exception it still  exists and I'm just gonna quickly print it in the   console so catch it print it you can still deal  with it it just doesn't kill your application the   other thing about testotron is that it actually  has a function that returns a task overload so   you can't really have an async or white and this  doesn't stop you from where you're executing from   if you were to do a weight here then it would  but if you remove this away then it will work   and it will still not fail and anything it won't  crash your application it just works exactly as   before however even with this approach even here  there is still a problem because if an exception   of this exception is raised in here eventually  it's going to be raised as an unobserved task   exception and we don't really want that so  what we can do for that is actually wrap it   in a smart way now the approach I usually follow  for that is coming from a person called he has a   Blog I'm gonna put the link in the description to  this specific blog post where he talks about this   and I'm gonna go quickly here and just create a  tasks extensions class all I'm going to do is I'm   going to paste this method here which is just a  single forget method and it is a void extension   method on the task now he actually explains every  step of the way why he's doing each thing as a   few performance things here on top of catching  that an observed exception so you can read that   if you want to go really in depth there's even  links to things like um Ben Adams tweets or in   the blog he links to Stephen Top's blogs so this  will deal with the problem in a very smart way   so now what you can do if you don't want to have  to deal with this unobserved task exception it's   just say don't forget and that is it you have  to be very careful however even though this is   fire and forget it should be ideally short-lived  you don't want to do this for long running things   and especially for long-running things that  actually block the thread that's because that   service can actually grab that thread and keep it  for the lifetime of the application so that can't   be problematic there are ways to deal with this  but this is not the video for it if you want me   to make a video on Long running background tasks  then leave a comment down below and let me know   if you want to see that video again this is just  one of the implementations there are other ways to   do this but this should explain why you should not  be using async voiding and how you can properly do   this without having to worry about things crashing  one small thing I want to mention is that if you   had a desktop application like WPF or winforms  and you have something like a main window with a   button obviously the button to be triggered like  a click method has to be an event and ultimately   an async void is there for events so this is one  of the reasons why you could use it and that is   fine because you can't really do anything about it  so if I put the button in place and I go into this   on click method it has the same one second delay  and then says subscribed so if I just quickly run   this I'm going to a small button called subscribe  so if I click that then I'm getting a message box   popping up and that is it and I don't know if  you noticed but we did wait for a second there   but this also suffers from the same problem  with the exception so if I say read all text   async for example from file.txt and I awaited and  let me just quickly delete that so if I run it and   I click the button and after a second I have an  exception then as you can see the application will   just create it will crash completely so you have  to be careful handling things in on click events   because effectively async void is an asynchronous  event with very interesting and weightlifting   semantics but that is it now I want to know from  you did you know about all these caveats and how   are you doing fine forget leave a comment down  below and let me know well that's all I had for   you first video thank you very much for watching  special thanks to my patreon to make it videos   possible if you want to support me as well you can  find the link description down below leave a like   if you like this video subscribe the Bell as well  and I'll see you in the next video keep coding
Info
Channel: Nick Chapsas
Views: 55,191
Rating: undefined out of 5
Keywords: Elfocrash, elfo, coding, .netcore, dot net, core, C#, how to code, tutorial, development, software engineering, microsoft, microsoft mvp, .net core, nick chapsas, chapsas, dotnet, .net, .net 7, .NET 8, async task, async void, void, await async void, don't use async void, async void c#, async task c#
Id: ZFWxSQ-KjUc
Channel Id: undefined
Length: 13min 12sec (792 seconds)
Published: Thu Mar 02 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.