C# and .NET Basics

Asynchronous Programming

Spencer Schneidenbach

Spencer Schneidenbach

Aviron Software, Microsoft MVP
C# and .NET Basics

Check out a free preview of the full C# and .NET Basics course

The "Asynchronous Programming" Lesson is part of the full, C# and .NET Basics course featured in this preview video. Here's what you'd learn in this lesson:

Spencer covers the concept of asynchronous programming and how it enables responsive and scalable applications. Spencer demonstrates the use of the async and await keywords to make asynchronous method calls and explains best practices for using async methods. He also discusses potential issues such as deadlocks and resource exhaustion.

Preview
Close

Transcript from the "Asynchronous Programming" Lesson

[00:00:00]
>> Spencer Schneidenbach: All right so we've covered a lot of ground today. We've covered classes, see a lot of the C sharp basic features. We talked about link and collections. I wanna talk about some of the advanced kind of the more kind of rubber meets the road stuff that you'll see up to this point.

[00:00:16]
We've really focused on the language itself and the capabilities of the language. I wanna talk about some of the deeper capabilities as it relates to actually doing stuff in the real world. So first, I do wanna mention that I provide a lot of examples for all of the link stuff that I just covered.

[00:00:34]
Each of these even selects and where's they all take. They all have an individual page where they kinda go over. Some of the more nuanced things we covered, a lot of the good stuff, which was good, but now let's go into what I would consider to be kinda as I mentioned, the rubber meets the road stuff.

[00:00:51]
So I said in my opening monologue that programming is so much more than just the ecosystem is so much more than the language. It's the ecosystem that you operated. And luckily for us .net and Microsoft have been very intentional about giving us a really batteries included framework for which we can build applications.

[00:01:12]
So I wanna talk about some of the more advanced or programming topics as it relates to. Some asynchronous programming or reading files from streams. So we're gonna talk about some of these libraries today. Collections is one that we've just gone through. We went through link, and I've showed you 90% of what you need to know in the for operating on collections in the real world.

[00:01:38]
We're gonna also talk about reading from and writing to files and things that are streams, called streams. We'll talk about writing to and from JSON, which is the kind of communication format of the web, the de facto one that's kind of taken over. We'll talk about making HTTP requests and how .net does that.

[00:01:59]
We've talked about link already. We'll talk about the asynchronous programming model, which is highly important. And finally, we will talk a little bit about reflection, which is a fairly advanced topic, but one that I think is important to know exists. So without any further ado, let's talk first about asynchronous programming.

[00:02:23]
So asynchronous programming is really this idea that this idea that there are some operations that you will do that will naturally just be bound by other things, right? So think of a when you open your web browser and you go to Facebook or you go to Twitter or Google.

[00:02:40]
And you go to that website, and you sit and wait for it to load. A lot of things are happening in the background, that there was that information, that web page is being loaded asynchronously. We have to reach out to the server, we have to connect to the server, we have to download that stream of bytes, and then we have to render it inside the browser.

[00:02:59]
Asynchronous Programming enables responsive and scalable applications, specifically in really all walks of life. When we do our ASP.NET Core course, we will focus specifically on how it helps in a web environment. But just imagine if you had a browser and you opened it up and when you went to a website, your whole browser froze until that website was finished loading.

[00:03:25]
I think most people would stop using that browser. And asynchronous programming kind of allows you to have a lot of those things that will allow you to keep that screen from freezing, right? It will help you from prevent resource exhaustion. I hope you do all of those things while providing a really nice experience for your user or I said, not exhausting your servers.

[00:03:50]
So this is the general syntax. So there's a couple of things that we need to talk about. So the keywords that you need to know are called async, and they're called await. Okay so what does that mean? What are those things and what the heck is task? Well, I think the best thing is to actually show it in a real kind of scenario.

[00:04:14]
A task is kind of like, if you're familiar with JavaScript, a task is essentially a promise. It's basically saying that this is something that's happening that will eventually be done, right? A task is a, an object that has properties to say, is it started, Is it finished, is it exceptioned AKA, did it encounter an exception?

[00:04:38]
And so it in and of itself can be it can do one of two things. A task can return a value, or it can just do something kind of like an action method, avoid returning method. There are 2 types of tasks. When we're talking about making HTTP requests specifically.

[00:04:59]
All of the libraries that we use, that are common to use all download requests asynchronously. There is no way to just download a request synchronously. So imagine if you were doing this in win forms. In win forms, if you click the button to download something and you weren't asynchronous, your whole application would freeze up while it was completing that request.

[00:05:22]
Whereas asynchronous programming gives a language integrated way to kind of give you that give you a way to program asynchronously, but not really no need to know in a deep way, what's going on under the hood. It is useful to know, but you don't have to create and write all those constructs yourself.

[00:05:42]
You don't have to do it all yourself, you don't have to do all the wiring yourself it just sort of happens. So I wanna kind of point out two things. I wanna point out this async keyword. The async keyword declares a a a function as being asynchronous, and that means that it can call and wait on other asynchronous methods.

[00:06:02]
And an asynchronous method in the context of the .net core libraries is going to be a method that returns some aspect of task. Now task you see, has this little thing next to it, and you hover over it says a waitable. That means you can wait on the response of that request.

[00:06:21]
And what's happening under the hood is essentially Microsoft is in or .net is saying, hey, this thing is waiting. I'm gonna free up the resources on this thread. And once that promise returns, once that thread or once that task finishes, I can resume that thread where I left off and then complete the rest of the function.

[00:06:39]
So let's see what that looks like. The point of this, the real point of this is that it's meant to be kinda natural and language integrated in a way that makes it very easy to do. So I'm gonna make one change to our void method, I'm gonna say, or our main method.

[00:06:56]
I'm gonna say, instead of void, I'm gonna say async task. That's essentially our way of declaring this main method as being able to await on things. So that's a feature that's been around for the last few versions of .net is where you're able to declare this as async task and it allows you to do things like data = await getdata from server async.

[00:07:32]
I will declare this method as static. So what are we doing here? We're calling this method which we could call without the async without the await keyword, and I'll show you what that looks like. And what we're doing is we're essentially saying, I want the string from this task of string that you've promised me.

[00:07:51]
This method says that it will return a task of a string, so I'm gonna await on that method. I'm just gonna let you do your thing, and then once you're done, you're gonna return to me the result that is of string. If I delete this await keyword, it's gonna complain to say that you cannot convert from a task of a string to a string, because at this point, we're no longer awaiting on this.

[00:08:13]
We're just actually trying to get it like this, where we do task of string, as opposed to just give me the string there are some valid reasons to do this. I think for most programmers and most .net developers, they're probably going to do something along these lines. They're probably gonna program asynchronously like this, where we actually say, I want the string and I want to await or wait for that string to be returned.

[00:08:42]
So I'm gonna say google.com, and I'm gonna say Console.WriteLine(data) and we're gonna see what happens, boom.
>> Spencer Schneidenbach: Okay, you see that our console has a bunch of gobbledygook. And I'm I assume that, well, let's see, I see a lot of JavaScript. I see some embedded images. I see HTML I think what we've done is we've gone out to google.com and returned the entire page and just spit it out into a string.

[00:09:15]
And as opposed to rendering it in a browser, we're just putting it in console. And I bet you there's that text box somewhere, the search box as it were, I don't exactly know what it's named. Point being is that, we've gone to google.com using our HttpClient. We've gotten the contents of that string, we've returned it to our caller, and then we've just printed it to the console.

[00:09:41]
So this is really powerful because it's really simple. Again, I can't emphasize enough the term language integrated, right? The async await programming, this was the kind of a revelation for programming languages. The reason that async await exists in JavaScript, the way that it does, is largely due to async way as it was created in C sharp.

[00:10:02]
Couple of things to note. A method that does not return a task or does not return a value from a task is simply a task. And you will not just return anything. And that's pretty much the same as A is a void returning method. But it's the asynchronous version of avoid returning method, whereas this is the asynchronous version of a method that returns a value.

[00:10:28]
In this case, it's just returning a string. If you don't declare this as async, you can't use this await. You can't use the await keyword because a method you can return, you could just say return the task directly like that, which is totally fine as well. But most of the time, in order to preserve a nice stack trace, so if you're getting an exception and you wanna see all the things that happened in the meantime.

[00:10:56]
It's best to typically await on these calls and just return it and then Just declare it as asynchronous. And when you get into error handling and you're looking at exceptions, that becomes really important. So some do's and don'ts of asynchronous programming, async all the way down is highly recommended.

[00:11:14]
If a method calls asynchronous APIs, it should itself be declared as async. And if we have an async version of an API with extremely few exceptions, and I will tell you the one exception that I can think of at the ASP.NET Core course, but you should always use the asynchronous APIs.

[00:11:35]
If you're in an asynchronous context, if you're in an asynchronous method, you should call the method that Is prefixed or that is the asynchronous method. And typically, in .NET it's a standard that all methods that are async await, or that are awaitable as we say, are ended in the word async.

[00:11:55]
It drives some developers crazy. For me, I'd like it because it's very explicit. So if you see a GetSring method, and then this GetStringAsync method, if you're in an asynchronous method, you should prefer to use GetStringAsync. I should note that some constructs in.NET like like HttpClient, don't even have a GetString method that is synchronous.

[00:12:19]
It's async all the way Down, then that's very much by design.
>> Spencer Schneidenbach: So, there's a couple of other things that you should know about async await or asynchronous calls. There is a property on the task itself. So at this point I've taken out the await and I'm looking at the task itself.

[00:12:40]
I'm looking at the properties on the task. You can see that there's an exception which can be null if there's not an exception hasn't been thrown. There's an ID because all tasks are assigned an ID by the runtime. And then there's a couple of weird ones. There's wait and then there's dot result.

[00:12:54]
What the heck is this dot result? That's the result of my asynchronous call. Well, that should work just fine right? Should never use .result or .wait, and the reason why is in that in certain .net contexts, you can cause deadlocks. Not to mention that you've kind of discarded all of the you've essentially discarded and have converted a asynchronous method to asynchronous one by using these, by not using the await keyword to just get that value out.

[00:13:27]
So it's really important that you avoid those. You don't need to declare every method as async in your whole application. And in fact, the compiler will complain to you that you're doing so if you're doing so unnecessarily. You should only declare function is async if you need it to be asynchronous.

[00:13:43]
So you should go async all the way down and favor async APIs where you can. But if none of the things that, none of the functions that you're doing require async, then you shouldn't declare the method as async. So a good example of that would be an add numbers class.

[00:14:01]
You would not declare or an AddNumbers method, you wouldn't declare this as an asynchronous method because there's no point. There's no asynchronous operation and as I mentioned, if you did, the compiler will complain at you. Couple of notes about declaring async methods. If you declare this async, it will complain because it must be of a task that can be awaitable, or of a type that can be awaitable.

[00:14:29]
Int is not awaitable, but task event is awaitable because it's a task that's something that can be awaited. This would be a huge waste of time and resources, but it is technically feasible, but as I mentioned, the compiler will complain and tell you that this does not have any benefit and will run synchronously.

[00:14:53]
There's one last thing is that you can, in fact, declare methods as async void. This is a compromise done a long time ago due to event handlers in .net all returning being void, returning methods or functions that have void. Do not ever declare a method as async void unless it's an event handler and really, and that's if you know what you're doing.

[00:15:22]
And what I mean by an event handler is something inside of like a win forms application. An event handler would be you click a button that handles an event handler is triggered, and that might include some asynchronous operation. That is the only use case for async void. I have seen so many developers get hung up on async void.

[00:15:38]
They've declared a method as async void. They didn't call it async task because they just wanted to do something. They just wanted to perform some kind of asynchronous operation. Call an API, right? Just call an API and mutate a target system, add this person to the payroll system, and they declared it as async void, and then wondered why they were getting these mysterious runtime errors or runtime problems.

[00:15:58]
It's because async void is not something that should be used in most contexts. And I bring it up because I've seen it all too often. Every time somebody writes async void outside the context of an event handler, Jon Skeet himself summons tainted souls into the realm of the living.

[00:16:15]
That's what happens don't do it. Lastly, there is a task .run I think it's actually task .run right here where you can take a asynchronous method and run it synchronously. That's about as useful as doing .result or .wait and again, discards some of the usefulness that you get out of, that kind of throws away some of the usefulness that you get out of using, the async await keyword.

[00:16:43]
This will become very much more relevant in the ASP.NET Core, course, when we're looking at real code, because I intend to show you code that I would write. And we'll be doing async programming almost all the way down there.
>> Student 1: Is there anything that's the equivalent of promise dot all, from JavaScript?

[00:17:01]
>> Spencer Schneidenbach: Yes so if you have a series of tasks that you need to complete and you need to wait till they're all done, you would do a wait. So let's say that this would be a good use case task1, this would be a good use case for bringing your tasks into a variable like this.

[00:17:26]
You might download Google twice, or you might download Twitter. I guess you'd be downloading Elearn. Say await Task.WhenAll and that would wait until where we take wait until all of these things are done before it would resume operation.
>> Student 1: And this is kind of a follow up to that but are do you have any tips for preventing race conditions when using async.

[00:17:54]
>> Spencer Schneidenbach: Await, just as long as you're awaiting if you awaited each of these, they would run asynchronously per se in the in a literal sense. But in a procedural writing code sense these would then be this one would run wait till this this would wait and then task two wouldn't kick off until task one was complete good question

[00:18:18]
>> Student 1: And are there any concerns about exhausting the sockets with async or HTTP clients in general.
>> Spencer Schneidenbach: HTTP client yes, and we'll get to that when we get to the HTTP client section. That is something that that can happen, but only if you use mainly if you misuse HTTP client.

[00:18:36]
Otherwise I would not have a problem from a single HTTP client. I wouldn't have a problem with running multiple simultaneous requests. If I was doing hundreds of them, then I'd be worried about something else like bandwidth, but I'd be worried about some other kind of resource exhaustion, not necessarily one within the runtime.

[00:18:53]
Also a really good question. Of course, we awaited these, so this task went all breaks.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now