How Do You Cancel an async Method? | Step-by-Step Tutorial

Поділитися
Вставка
  • Опубліковано 14 кві 2024
  • What happens when you start a long-running asynchronous method but wish to terminate it before completion?
    .NET TPL supports task cancellation - an elaborate mechanism involving marshaling and synchronization, but exposed through an intuitive and simple pair of types.
    Watch this video to learn how you can embed graceful cancellation into your asynchronous methods when you suspect they might be running longer. Learn about your duties when canceling a task, such as cleaning up the resources and propagating the cancellation up and down the call stack.
    The coding pattern is straightforward, but missing a tiny detail may turn your otherwise beautifully responsive code into one with a bug. Don't let that happen.
    Download source code ► / zoranhorvat
    Join Discord server with topics on C# ► codinghelmet.com/go/discord
    Enroll course Beginning Object-Oriented Programming with C# ► codinghelmet.com/go/beginning...
    Subscribe ► / @zoran-horvat
    ▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
    👨 About Me 👨
    Hi, I’m Zoran, I have more than 20 years of experience as a software developer, architect, team lead, and more. I have been programming in C# since its inception in the early 2000s. Since 2017 I have started publishing professional video courses at Pluralsight and Udemy and by this point, there are over 100 hours of the highest-quality videos you can watch on those platforms. On my UA-cam channel, you can find shorter video forms focused on clarifying practical issues in coding, design, and architecture of .NET applications.❤️
    ▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
    ⚡️COPYRIGHT NOTICE:
    The Copyright Laws of the United States recognize a “fair use” of copyrighted content. Section 107 of the U.S. Copyright Act states: “Notwithstanding the provisions of sections 106 and 106A, the fair use of a copyrighted work, including such use by reproduction in copies or phono records or by any other means specified by that section, for purposes such as criticism, comment, news reporting, teaching (including multiple copies for classroom use), scholarship, or research, is not an infringement of copyright." This video and our youtube channel, in general, may contain certain copyrighted works that were not specifically authorized to be used by the copyright holder(s), but which we believe in good faith are protected by federal law and the Fair use doctrine for one or more of the reasons noted above.
    #csharp #dotnet #asyncawait
  • Наука та технологія

КОМЕНТАРІ • 46

  • @CRBarchager
    @CRBarchager 18 днів тому +1

    4:05 & 4.50 Thank you for mentioning the reasoning behind to position of CancellationToken here.

  • @gligom
    @gligom Місяць тому +11

    Every time i watch your videos my head 🤯. I know, your speed and advanced understanding of all this concepts comes after many years of experience. Even with this headache I still watch and enjoy every minute, hopping that one day I will understand too…

  • @spechulfapticks3108
    @spechulfapticks3108 Місяць тому +12

    i will not judge you if you judge me for making cancellation token be 1-st parameter ©

  • @user-ei3fk6hh1w
    @user-ei3fk6hh1w Місяць тому +4

    Another high quality video for real world projects. Thank you so much!

  • @mcstonesen
    @mcstonesen Місяць тому +2

    Nice video. I always love to see your well explained scenarios, which make it easier to get the point of each topic. Btw. was the voice in this video AI generated? Every word was so uniformly pronounced, that I started to feel a little uncomfortable 😂

  • @HOSTRASOKYRA
    @HOSTRASOKYRA Місяць тому +1

    Thank you very much for this so helpful video!

  • @hozmannew896
    @hozmannew896 Місяць тому +1

    well explained concepts, thank you

  • @codingbloke
    @codingbloke Місяць тому +3

    Another great video. I'd like to know more about this functional pattern which leads to the CancelationToken being passed first in the parameter list. So far I have followed the pattern of existing libraries of having the CancellationToken be an optional parameter at the end of the parameter list. Perhaps this is a subject of another video?

    • @zoran-horvat
      @zoran-horvat  Місяць тому +5

      I believe there will be other videos to tackle that question. The point is in Currying and partial function application, where you supply the configuration and obtain a function with the shorter parameter list which is useful to its end user, i.e. the code that will only supply the variable parameters without knowing how the function was configured. It is a long but interesting story.

    • @7th_CAV_Trooper
      @7th_CAV_Trooper Місяць тому

      @@zoran-horvat omg, currying! that makes so much sense. I've been reading Eric Meijer's and Graham Hutton's paper on monadic parser combinators. This is taking some effort on my part as I'm new to functional programming. I learned about currying while researching Haskell so I could comprehend the sample code. Functional programming twists my brain in a knot. Also, curry is delicious.

  • @billy65bob
    @billy65bob Місяць тому +4

    Every single one of my async methods tends to end with `CancellationToken token = default`, which makes the token optional.
    I'm really not a fan of exceptions at the best of times, but the exceptions around Tasks really annoy me.
    Just consider that some spots throw OperationCancelledException, then others do TaskCancelledException, and just to make it more annoying, there's also a SqlException with the message "Operation was cancelled by the user"... Not a fan.

    • @stefano_schmidt
      @stefano_schmidt Місяць тому

      I know that TaskCanceledException is derived from OperationCanceledException, and you can catch the latter one and check who it actually is 😁
      But I haven't heard of SqlException with that message yet.
      If it's really caused by the task being canceled, it's gonna be some ugly mess in a catch block
      (since we would need to check some of its additional properties like "ErrorCode" (I believe it has one), to identify what caused the exception).
      And as the one who is a fan of explicitness, I would force anybody to pass CancellationToken.None 😂

    • @billy65bob
      @billy65bob Місяць тому

      @@stefano_schmidt I've "worked around" that SqlException by just making the first thing in the sql exception handler: token.ThrowIfCancelled(). I hate it, but it is what it is.
      I had never noticed that TaskCancelled derived from OperationCancelled, was it always like that? or am I experiencing some Mandela Effect thing here?

    • @7th_CAV_Trooper
      @7th_CAV_Trooper Місяць тому +2

      TaskCanceledException is derived from OperationCanceledException, so you can just handle the OpCan unless you have a reason to catch the more specific error.

    • @billy65bob
      @billy65bob Місяць тому +4

      @@7th_CAV_Trooper You're not the first to mention it.
      UA-cam has deleted their comments (and seemingly yours as well).

    • @7th_CAV_Trooper
      @7th_CAV_Trooper Місяць тому +1

      @@billy65bob I've noticed my comments getting lost lately. I thought maybe UA-cam was mad at me. Lol

  • @okcharles7
    @okcharles7 22 дні тому

    05:35 Answer to bonus question: nested catch?
    try { File.Delete(path); }
    catch {IOException) { }
    throw;

  • @pferreirafabricio
    @pferreirafabricio Місяць тому +1

    First of all, thank you for this high-quality content!
    I tried to implement similar code using the final adjustments that you made, but I got stuck in the scenario where the user decide to wait for the total file to be generated, the process never ends, the message "Ended interaction." is never displayed.
    After some research I found some StackOverflow questions talking about how "while (!fileWriter.IsCompleted)" was causing a dead lock.
    Is this the scenario? Is the main thread waiting for the task to complete, and is the task waiting for the main thread to be free to run the continuation?

    • @zoran-horvat
      @zoran-horvat  Місяць тому +3

      That is only true for infinite tasks. The task that writes to the file may take long, but it will eventually terminate and the main thread will continue beyond the whole loop.
      What may happen it's that the main thread is waiting for the user's input. The loop's primary duty in my example is to prompt the user, so the check only happens after dinner input has been processed.

    • @pferreirafabricio
      @pferreirafabricio Місяць тому +2

      @@zoran-horvat Testing some variations, the "Console.ReadLine" was really causing a wait. Thanks for the quick response!

  • @RualddeBruyn
    @RualddeBruyn Місяць тому

    Thanks!

  • @peterriesz69
    @peterriesz69 День тому

    There code analyzer CA2016: "Forward the CancellationToken parameter to methods that take one" only "analyzes method definitions that take a CancellationToken as their last parameter" so if you want the IDE to help enforce you are forwarding CancellationTokens I think its best to stick with C# conventions (CA1068) and keep it as the last param.

  • @SirBenJamin_
    @SirBenJamin_ Місяць тому +1

    So what about the failed delete call? Adding another try catch gets verbose?

    • @zoran-horvat
      @zoran-horvat  Місяць тому +2

      That will be the topic of another story...

  • @dwhxyz
    @dwhxyz Місяць тому

    It should be noted that there are times when a developer will need to gracefully handle the entire cancellation logic themselves. This could include letting some/all parts of an operation complete (and in turn selectively passing down the cancellation token to in-built .NET framework methods) and/or undoing/cleaning up some parts of an operation that is being cancelled depending on how far it got when the cancellation was triggered. Just blindly passing down the cancelled token to everything in the chain (from say an API/MVC web request) could leads to serious issues in some application and hence in many instances (especially if the operation is short lived) it would be better/safer to just to let the operation complete without passing down the cancellation token to anything! Unfortunately all the videos I see on this subject don't really address the entire cancellation subject and just focus on the cancellation source/token.

    • @zoran-horvat
      @zoran-horvat  Місяць тому +2

      You are right. The corner cases when working with tasks are serious and deserve equal attention.

  • @MC_DarkMaster
    @MC_DarkMaster Місяць тому +1

    I hate that the try/catch-syntax needs so much unnecessary boilerplate lines

    • @zoran-horvat
      @zoran-horvat  Місяць тому

      That is true. They made everything else so neat and short about tasks, but the exception handling syntax remained verbose.

    • @7th_CAV_Trooper
      @7th_CAV_Trooper Місяць тому +1

      I hope Zoran will publish a video showing us how to put try/catch/finally into a functional style. :)

    • @7th_CAV_Trooper
      @7th_CAV_Trooper Місяць тому

      like myMethod.Invoke() could be something like myMethod.Try().Catch(ex => stuff).Finally()

  • @escribe6751
    @escribe6751 Місяць тому

    What does BCL stand for?

  • @jamesbond6761
    @jamesbond6761 Місяць тому

    Why did you not dispose of CancellationTokenSource? It might lead to a memory leak.

    • @zoran-horvat
      @zoran-horvat  Місяць тому +1

      You are right. It should have been declared in the using statement.
      The real question is: What was Copilot looking at when I skipped using :)

    • @7th_CAV_Trooper
      @7th_CAV_Trooper Місяць тому

      @@zoran-horvat There's a nice Nuget package called IDisposableAnalyzers that I add to every project since discovering it. Seems like this would be built-in since it's a major source of runtime troubles. Dispose is such a broken pattern. They (the dotnet runtime engineers) should just Dispose automatically when the reference goes out of scope.

  • @7th_CAV_Trooper
    @7th_CAV_Trooper Місяць тому +1

    Why does adding the cancelation token as the first argument help with functional programming? Do I need to go read up on FCL?
    Don't forget to dispose the CancelationTokenSource.
    If you get an IO exception during the Delete operation just turn your computer off and call it a day.
    Note to self: BCL has nothing to do with the Borland Class Library which was never actually a thing.