>> Tune in to this week's Xamarin
Show where my good friend Dean talks about best
practices for Async/Await. You do not want to
miss this, so tune in. [MUSIC]. Welcome back everyone
to The Xamarin Show. I'm your host James
Matzo [inaudible] , and today I have my
favorite person in the entire world Dean with
me, how is it going Dean? >> Good. How are you? >> I'm obviously
absolutely fantastic. Now, people may not know who you are because this is your very
first time on the show, and I'm really excited
because we have a brand new micro series for best practices and Dean, you
are an expert in everything, but tell everyone a little
bit about yourself. >> Yeah. I'm Dean, I'm from the Microsoft Mobile
Customer Advisory Team. We work with customers to help them figure out Xamarin best practices, how to improve their apps, how to get a good dev/loop going, and in general have a great
experience with Xamarin. >> Yeah, that's awesome. It's really great because we have
a great platform but so easy as a developer to
get yourself into trouble. It's not your fault but sometimes
you just write some bad code, I write bad code all the time Dean. >> Yeah. >> I was talking to Alex, big boss man Alex who
will be on the show soon to talk about HttpClient
and we're just like, "Man, I see a lot of the work
that you're doing with the team, let's do a best practices series." We're going to have a
whole series of this, this is the first video, Async/Await which I
think honestly is one of those topics that I feel like I
know a lot about but then I don't, and then I get people's
code and I'm like, "I think you're doing it wrong." But maybe I'm doing it wrong
and we're doing it wrong. What do you see out in the
field with Async/Await? >> Yeah, that's what I'm
here to clarify today. There are a lot of different
ways to use Async/Await, and that's part of the problem. It's hard to understand
what each different method, each different field is on the tasks, what all the different keywords are, and how they differ, because sometimes they're
very similar and they were only created out of
necessity and efficiency. >> Got it. >> Yeah. >> I remember when I started with Xamarin, I didn't even
have Async/Await. Now, I did have tasks
but I would always continue with and I was
like, "Okay, I get it. I do this thing," then I'm like, "When you're done, do this." Async/Await it always
felt magical because my code got so much
cleaner and I was like "Just await, just await, just await," I didn't really think
about what I was doing. >> Yeah, and it just works
right? Until it doesn't. >> Well, let's get into it. >> Yeah. >> You told me you have a bunch of things that are not so good that
people might be doing, right? >> Yeah. I have a simple application we'll have a link to the repo, and in this app we just have a
bunch of different examples. On the left-hand side, we'll have the bad examples of what
we see out in the field, or we see common
mistakes or pitfalls, and on the right side
is how to fix them. >> Okay, perfect. >> Yeah. >> I like that also by the
way because it's like, "Here's bad code, here's good code." >> Yeah, exactly. This
make it digestible, then also to see the contrast and see what actually happens
when you run it, right? >> Perfect. >> Because a lot of times
you look at Stack Overflow, we're looking at a sample and
we contextualize in our head. But when we run it on the device, it's really hard to follow
if you don't do it. >> Got it. >> Yes, let's just jump right in. For the first page, what we have here is
your typical task, let me just explain
the app a little bit. >> Sure. >> We have a "TaskService" that has this main method which is
"GetStringWithTaskRunAsync". >> Okay. >> What this is, it's just a wrapper around a task. We'll see this is the main task, and it's just a wrapper
so that I can print the different task statuses to
the console or to the app itself. All it's doing is running
a delay internally, and then we'll see the different task statuses
come up on the screen. >> Got you. This is like your helper method that you're using. >> To illustrate. >> This is returning
a task of strings, this might be very familiar
if you're using HttpClient. >> Exactly. >> Get string asynchronously, you would call this get string with task run async and then
you'd await on that, right? >> Exactly. >> In general, very similar but
you're also passing in a bunch of arguments here like delays and cancel, are you
going to go into those? >> Yeah. There's a bunch of default parameters but I did add those to show the different examples so we have flexibility. Some of them are just passing in an action so that we can run
something after the delay and so on. >> All right, perfect, cool, lets go. >> We'll get into that as we go. The first one is just
invoking a task, once we have that task, what the method returns is just a task string
that we talked about. >> What that is saying is, "Hey, I'm going to go do some work, and when I'm done, I
will return a string." >> Exactly. >> And the whole idea of a task and awaiting on it is long running process because
I want to make that clear, because that's why you make a RESTful service call with HttpClient. Because that network
request might take a few seconds and you don't
want to block your UIThread, your awaiting is like
a promise coming back. Like, "I'm going to go do some work, when I'm done then continue on," and that way it doesn't
block your call, right? >> Exactly. >> That's your UIThread and that's why it's important here. >> Yeah. >> When I call this
method that you have, it's going to return a
string at some point. >> Correct. This is the
bad way to start with, we'll see, we're invoking the method, but then we're "calling.Result"
at the end of it. >> ".Result" >> Yeah. >> I wrote a whole blog post by
the way on "Stop Calling.Result". Why is this bad? I don't understand. >> What ".Result" is, it will wait for the
result of the task, and when that happens
is when we call it, it waits, if the task hasn't
completed, it just waits in line. We'll just actually stick
here, then just wait till the result comes back and then
we can continue execution. >> If that takes 10
seconds, you'll have locked your application
completely for 10 seconds. >> Yeah. >> This is synchronous. It basically turns asynchronous
method into a synchronus method. >> Exactly. You never want to
do that. Let's take a look. If we click this, it will run for two seconds and then
it suddenly pops up. You'll see while it's running, we can't open the menu or anything, that was really fast, I
think it's one second now. >> Because I saw there
was a delay there. >> Yeah. But you see the delay, you see the button
animation sticks there. >> That's the best
way to do it, right? When you click on something,
it should continue, but that blocked to that button
from even finishing its animation. >> Yeah, you don't want that.
That was just one second. Like you said, if
you have 10 seconds, users can delete your
app just like that. >> Yeah. >> All right. Let's look
at how to fix this. All right. This is the
one-liner that we have, all we do is call await on the task and we get the
result same as before. But the end behavior is, it just runs like that and the
task completes asynchronously. We can still use the app, we can even run it multiple times, if you just click on
this a bunch, it will complete and print
out your completion. >> If you try and do it
in a bad task invoke? >> You can't even. >> It won't even let you do it. >> It won't even let you do it. >> I think I might have
just broke your app. >> It might have deadlocked, yeah. >> There we go, it's
finally happening. But that is a bad user experience. >> Exactly, you never want that. >> You dropped the ".Result"
and then you used "await". >> Yeah, simple stuff. All right. Moving on to the next one, let's collapse this down. Next one is multiple tasks. Once you've figured out
that you can await tasks, the next thing I see is people
await tasks separately. If you have like three REST services endpoints
that you need to call, and you want to call them
asynchronously, right? There's await first
one, await second one, await the third one, and
you know what happens? >> You're awaiting, and
awaiting, and awaiting. >> Exactly. >> And you're not going to get to
the end until everything is done. >> Until everything is done. >> Got it. >> Let's take a look at that, we have our "awaits"
and a "for loop". >> Okay. >> Yeah, let's just run it.
We'll see the first one go, second one, third one, and so on. >> That doesn't look too bad
because you're awaiting, so you're not locking your UI but
you're one, two, three, four. >> Exactly. >> That's the problem. >> Yeah. >> Got you. >> These tasks are just one
second just to illustrate. But if you download the code, you can change the values and see
what it feels like in real time. >> Got you. >> Let's take a look at the "Fix". The "Fix" is to actually keep
the tasks in a collection. In this case, I'm putting
them in an array and then we can call "Task.WhenAll"
on the whole collection. >> What does "WhenAll"
mean, what does that mean? >> "WhenAll" means that
this task will only return once all the tasks are done. When a task is done, that
means it either completed, or it was canceled, or it's
faulted through an exception. >> Okay. Previously, we were
taking these tasks and we were firing, awaiting, firing,
awaiting, firing. Now, what you're saying is,
you're going to fire all of them, and then when done, come back. >> Exactly. >> That's a thing of
beauty, right? You can be uploading a bunch
of files at once, and then the task here is going
to figure out the threading, all the stuff for you, I can imagine. >> Exactly. >> Beautiful. >> Yeah. The task can
complete separately. If some of them come
back early, that's fine, it will just complete once
the last task comes in. >> Okay, cool. What
does that look like? >> Let's take a look. For the previous one, it took
five seconds, we can see here. But if we run them
with "Task.WhenAll", we'll see that they all fired off and then they all completed together. >> Because they all ran for a
second, so they're all done. >> Exactly. >> That's even just literally a four second improvement
because, guess what these mobile devices can handle. You have the bandwidth, stop choking your app. Cool, nice. >> Yeah. That's a really good
improvement, we see that a lot. Next, let's look at returning tasks. >> Okay. >> This is tricky, let's look at the good one
first because this is tricky. >> Okay. >> In our good example,
we returned a string, we returned a task string. >> Yeah. >> What we actually returned at
the end is this "Task.Run" task. >> Yes. >> This is the task, and then this is just
all the harness code to print out the task statuses, and then at the end, we just
return the task string. >> Okay, yeah. >> Okay. This is what we've
been doing all along. I don't have to show the good sample, but for the bad one we're calling a different method which is here, "AwaitStringWithTaskRunAsync",
and all that is is it's the previous
method, but we just return await instead of returning
the task directly. >> I see. This here is just like a helper method
that might be doing some stuff, but we've added an
"async" and "await" keyword here because
we thought we had to. >> Exactly. >> Okay. >> The normal case for this is, if this is a library that we're
using and it's an async library. Sometimes, developers think because it's
async, we have to await. Then it'll just return await. But what you can actually do is just return the task like we did earlier, and that's actually faster because
we don't have to await twice. Now, there's await
in-between which does context switches and all
this stuff under the hood. It's not much if you're just running
a little bit, but it adds up. >> I see. The main problem
that we're seeing here in general is there's already a task, and then you might have
another method that is returning a task that you want to await on, because you get a bunch
of gobbleygook in here too. >> Yeah. >> But there's no context,
there's no IsBusy, there's no anything, but
you're awaiting on it because you thought you
had to. Don't await. >> Yeah. >> What's this context switching
that you're talking about? You're saying this is
generating other extra code? >> Yeah. Under the hood, this is generating an extra
extra code that's unnecessary. We'll get into the context. But what it basically is is with Xamarin Apps,
there's a main thread, which is the UI thread, and then
there's a bunch of other threads, which depends on what
device you're running on. >> Got you. >> Think of the different
threads as a different context, and you always want to run
off of the main thread. >> Got you. >> That's what awaiting does for us. >> I see. >> "where.result" actually
ran on the main thread. >> Okay. Got you. Cool. >> Cool. For this one, this actually shows a
big improvement once we run up to 1,000 tasks,
but it takes awhile. On air, let's just run
100 and see what happens. I'm sorry, it's not that one. It was task return. This one. Okay. So we're
running 100 tasks, and you'll see that even though we're doing "Task.WhenAll"
just like before, they're not actually
all firing off at once because ".NET" is smart
enough where it knows like, "Hey, I can't run these
many in parallel. Let me just chunk
them off and run them when it's useful for me
and to be performant." >> I like also that you're scrolling through and it's firing off more, but your UI is responsive. >> Exactly. >> It's like 13 seconds. >> 13 seconds. >> Okay. >> If we do "task.return
await" on the task. >> This is the one where you're
adding an extra "await". >> Adding extra "await". >> Also, we see that they're
chunked in a little bit. They're not chunking
here then because you're awaiting and then
also chunking them. >> Yeah. Then we'll see nine seconds. Again, the difference is very minuscules for, this is 100 tasks, but I tried with 1,000 and
it's almost twice the time. >> Got you. Awesome. What we saw, you ran bad task and
then the good task, and the bad task actually was 10
seconds compared to six seconds. >> Exactly. >> Pretty good. If you
did like you said, over 1,000, that would be dramatic. >> Yeah. >> Yeah. >> Yeah, and it adds up. The magic of tasks make it almost too easy for
developers to abuse it, right? >> Yeah. >> It's like if you have a
power tool, it's too powerful. You have to control
yourself and understand it. >> The compiler is smart, but we just need to
help it from time to time, right? And be
like, hey, we can help you out a little bit when you
actually need to await on it. >> Exactly. >> Yeah. Cool. >> Let's go to the next one,
which is bad threading practices. >> Okay. >> Yeah. We talked
about contexts before. This is where I'm
going to illustrate. When we run a task, well, before that even, when we hit
a button and run the command, it actually executes
on the main thread. >> Yes. >> Once we await the task, what does it continue on afterwards? Is it still the main thread,
is it a different thread? Developers don't think
about this, right? It's like, "Well, it came
from the main thread, maybe it's still," or sometimes
they don't even think about the context because it's await, it works, it's just beautiful,
it runs asynchronously. But then everything after that, you have to be mindful
of where it runs. In this case, we have
a thread sleep to simulate a long-running calculation or some sort of download
image processing, whatever it is, and it's
happening after an "await". Sometimes, people think they're safe. But what happens is, execution
returns back to the main thread, and then this runs
on the main thread. Let's take a look at that. >> I see. Okay. Got you. In this instance, when we call out to the service, it's going to start on the UI
thread and actually await, do stuff in the background, come back onto the main thread,
where threads are sleeping. But you may think it's
on a background thread. >> Exactly. >> But it's not. Okay. Cool. >> Because the await was
on a background thread. >> Got it. >> Let's take a look. >> Let's take a look. >> Yeah. >> It's started, it's
created the task. >> Then it was sleeping. Okay. This is five seconds. We can actually see that the
app is totally unresponsive. >> That thread, which is five seconds, has completely locked the app. Very similar to a result, also. >> Exactly. >> Got you. You are
locking that thread. >> We didn't even use that "result". We used "await". Yeah.
It's tricky in that way. >> Yeah. >> The way to fix this is to actually use the magic keyword
"ConfigureAwait false". >> This is always tricky.
This one's tricky. It always scares me a
lot. Please explain. >> Yes. "ConfigureAwait", by default, a task will
have "ConfigureAwait true". That just means return on
whatever contexts was calling it, which was the main thread, right? When we say "ConfigureAwait false", we'll say don't return to the
thread that we called on, just return to a different
thread and we don't really have to specify what thread it is because
that's all managed for us. But what this guarantees is that whatever happens afterwards, isn't
going to be on the main thread. >> Okay. It's going to
say, go do this thing, but we're awaiting,
which means still don't execute anything after this
until I've finished this thing. But I am telling you that it's okay to not return onto the
UI thread, is that correct? >> That's totally correct. >> Okay. It saying, previously, we didn't use anything, so
it started on the UI thread, went to a background thing, went to some task
background thread thing, came back, now it's not
going to come back. >> It's not going to come back. >> Okay. All right. Whatever you say. >> Let's see. All right. If you don't believe me,
we'll take a look. All right. We'll start the good threading, then you can see that we can
still open this and close it, and then it finally ended. >> Okay. Now, how is it able
here, the "PrintStatus", to come back and actually update the UI because you just told me
you're not on the UI thread? >> Yeah. Behind the scenes,
we're using bindings. In the set property, it actually has an invoke
main thread inside. >> I see. Okay. >> There's some safeguards
by the good folks at Xamarin to help you update the UI. >> Perfect. I really
want to clarify this. Here, when you say
"PrintStatus" command ending, in that instance,
that method is being executed on some background
whatever thread, right? >> Yeah. >> If you didn't invoke on the
main thread, it would blow up? >> It would blow up. >> It would actually
crash your application? >> Exactly. >> Because you're trying to update
the UI from the background. >> From the background thread. >> That's why you always
really want to be sure where are you
executing right now? >> Yes. >> Cool. Nice. >> That's the most important
distinction for Xamarin. Sometimes .NET developers have
a background with Async/Await, but there's no concept
of a main thread. >> Got you. >> It's just a thread. >> Just a thread. >> Yeah. Actually, funnily enough, that's the next sample. The next one we're
going to take a look at is updating the UI from
the background thread. >> Okay. Got you. Cool. >> Yeah. Moving on to this. For this one, we're
actually in the code behind because we want to update
"StatusLabel.Text" directly. It's the same thing. We're awaiting with "ConfigureAwait
false" because we know, "Hey, let's get off the UI thread." >> Yeah. >> But then afterwards, if we update "StatusLabel.Text"
directly, bad things will happen. >> I'm ready to see bad things. Yeah. >> All right. I'll click this, and it actually worked. Sometimes it might work. Let's try again. There we go. >> There we go. >> We'll see an exception, "Only the original
thread that created the view hierarchy
can touch its views." >> Makes sense. >> I don't know why it did before, but this time it's
saying, "Don't do that. Be sure to be on the
main thread if you're updating anything in
the UI directly." >> Got it. Your app has
now crashed completely? >> It is completely crashed. Yeah. >> It's gone. Outta here. >> We've seen that in the wild. If this was in some
sort of edge case and some sort of branch where
it doesn't happen often, and then that one time that it
happens is just catastrophic. >> Got it. >> Yeah. How to fix this? All we do is call "Device.BeginInvokeOnMainThread"
and then put our code in there. >> Boom. >> Boom, simple as that. All that does is, it executes anything inside
of here on the main thread, and we're good to go. >> Very nice. >> Let's take a look,
and there it is. >> Nice. >> Updated from the UI thread. >> Now, the cool part
about that method too, both part Xamarin.Forms
and Xamarin.Essentials, is that, it does a check to see
if you're on the UI thread first. >> Yeah. That's right. >> We handle that for you. >> Awesome. >> Very cool. Nice. What else? >> Cool. Okay. Next, we're going
to look at "exception handling". This is something that is really, really easy to get wrong. We'll take a look at the bad
exception handling first. With tasks, we talked
about ".result", we talked about "await", but sometimes
you want to "FireAndForget". Sometimes a task can just run. We don't care if it completes, if it doesn't complete.
It's just, run. >> Yeah. Just go. >> Yeah. We just need
to execute something. Let's say we need to
try, "catch", right? We're done at developers. We use our catch statements. But in this case, what happens is
because we've "FireAndForget" it, execution will continue till we're
outside of the "catch block". >> Okay. >> If any exception happens
here, who knows where it goes. >> Into the ether. >> Yeah. It depends on how
your app is structured. Let's take a look. You'll see here, "command
ending" will print first before the exception happens. Let's take a look. That's "FireAndForget". Actually, before that, I have to restart the
app because setting the "StatusLabel.Text"
actually broke our binding. >> Interesting. Yeah. There you go. >> Yeah. >> That makes sense. >> All right. >> Yeah, previously, you'd just
have the binding setup. Cool. >> Yeah. Let's look at
bad exception handling. We'll see the command ended, and then the task faulted. But we're not getting our print
status exception occurred. >> That exception which was thrown by that
"FireAndForget" is gone. >> It's gone. >> No one knows. >> No one knows. >> Your app could have
some sorts of issues. It could be even crashing,
but it's like you >> Exactly. >> Who knows? I'll fix that. >> Yeah. This is almost
worse than an app crashing, right? Because with
crashes, you know where it is. With this, it could be
something layers down. >> Got you. >> Yeah. Moving on how to fix this. All you do is use
"task.ContinueWith". What "ContinueWith" does is, once our task completes, regardless, if we awaited it or not, this continuation will happen
and we can pass in an action. In this action, we have
the task as a parameter, so we can inspect our task. We can also set these
continuation options, where you can specify
only on faulted, or only if canceled,
or only uncompleted. >> Okay. That's really nice actually. You can do this "ContinueWith", decide how you want to
handle a continuous. Successful? Don't care. >> Exactly. >> But if it's faulted, let
me [inaudible] a message. >> Exactly. >> Very cool. >> One thing to note
with "ContinueWith", is you can't have multiple
"ContinueWith" on a single task. If you want to handle
multiple different options, then just handle them all
in the same "ContinueWith". >> Okay. Got it. >> Let's take a look here. If we do good exception handling, we'll see the command ended, then the test faulted, and we have our exception print. >> Nice. Very good. If you're logging that out into App
Center or something, now you actually get that exception. >> Exactly. >> Very cool. >> Very useful. All right. Now, let's look at timing out. How do you timeout a task, right? Task just run. What if you want to set a time
limit on it? How do you do that? The example that I've
seen in the field is here, actually, "Task.WaitAll". Because "Task.WaitAll" has a second
parameter which is a timeout. >> That seems convenient. >> Seems super convenient. Yeah. I was looking
through the task API. This one has a timeout.
It must work, right? >> Yes. >> Let's try it out. We'll
see, the buttons jammed. >> Yeah. That's not good. >> Yeah. Same issue as
before as ".Result", "Task.WaitAll" actually
run synchronously. >> So "WaitAll", it's literally
waiting. That would be all. >> Exactly. >> WaitAll. >> WaitAll. So anything with wait without an a, you always want a wait. You don't want to wait and
you don't want result. >> You don't want result because
those are easy to remember. >> Yeah. But I'm definitely
going to contradict myself later in this example. Okay. Moving on, how do we fix that? This time timeout tricked us. We don't like that. Let's take a look at our good friend. Actually it's the new one. What I used to do was, I would create a
separate task which was a delay and then I would
do "Task.WhenAll" on that. >> I see. >> But in researching for this segment, actually
find a better way. >> Okay. >> "cancellationTokenSource"
is your friend. What you can do is, create a
"CancellationTokenSource". What this is, is it's part of the TPL which is
the Task Parallel Library, which is a mechanism to
help you cancel tasks. Exactly what a timeout is, right? It takes a delay where you can
pass in what your time span is. In this case, we'll time
out after three seconds. How you pass in a "CancellationToken" and that's where the optional
parameters came in before. You'll see I'm passing it in here. >> Got you. Pass in that token. >> Yeah. I'm just passing
it into this "Task.Run". I'm right here, "CancellationToken". >> Got you. >> Then within the task itself, you can also throw it on
"CancellationRequested". >> Okay. >> You have that
fine-grained control, if you want certain things to throw or certain steps
to actually check. >> Got you. >> Because "CancellationToken"
will try to cancel the task. But if you just have a
test that's just spinning, sometimes it might just keep
going for more than you like. >> Got you. There's probably also the state in which you might
need to pass this token down. Maybe you're going to into
another third-party library. It takes the task cancellation token, and then you can pass it down. They can cancel it, and then
it get bubble up. Very cool. >> Exactly. Super useful, works awesome for timeouts. Let's take a look. We'll just say good
timeout, that's running. There's no UI lock. Then after three seconds, it cancels. >> Very cool. >> The underlying task still run, or it's not still running. It was supposed to
run for 60 seconds, and then it just got canceled. >> Canceled. Very cool. That's really nice because you
are just setting at a timeout. But I'm imagining that, with that you could also manually cancel. Maybe you have a cancel
button for instance. >> Exactly, yeah. >> You're doing a long upload. No, I'm in this airplane
right now, cancel. >> Yeah. One useful thing that
we've seen is on navigation. Sometimes you want to
reduce steps for the user, make it easier to use, but you
also want it to be performing. Sometimes if they're doing something and they navigate somewhere else, that means they wanted to cancel. >> Got you. >> One navigation, you cancel. They don't even have to do anything. >> Perfect. >> The next one we'll look
at "TaskCompletionSources". This is a more complicated
mechanism of task, the task parallel library. But in a nutshell, "TaskCompletionSources" let us make synchronous code
run asynchronously. >> Got you. >> It's a good way for us to create tasks with
fine-grained control. >> That's great because often
when you're dealing with iOS or Android specific code, there's not an asynchronous method. We might have like a
callback or an event. You can Async. >> Or delegate. >> Yeah, or delegate or
Async a file that API. >> Exactly. >> We do that with
Xamarin.Essentials all the time. >> Yeah. >> You'll find these things
scattered everywhere. >> Yeah. Once you're
done with the sample, look in Xamarin.Essentials, and
you'll understand the whole thing. >> Yeah. What's this
thing doing here? Okay. Let's take a look at
the good one first, actually. >> Okay. >> First, we'll look at what a bad "TaskCompletionSource"
looks like. We're simplifying this API. But sometimes, we'll
look in this method. There's a lot of code here. I won't go into all of it, but the gist of it is, internally, you have a
"Task.Run" where you set result. This is almost the
most important thing with the task completion source because if you never set the result, the task never completes. >> Got you. >> If we take a look at the
bad example, what happens is, in here, I'm making it run
10 tasks with "WhenAll". But these tasks, before
they're completed, they'll throw an exception. So what happens then, right? If their tests completed,
then it's fine. But if it throws an exception,
how are we handling that? >> It'll never get returned. >> Exactly. >> Because you never reset
it through an exception. >> You never set an exception. >> Got you. >> Let's take a look at that. We'll see that these tasks
actually are faulting, so the task faulted. But our exception here >> It was never printed. >> It's never printed. >> Got you. That's bad because
now which is again into the >> Again, into the ether
on multiple tasks. >> Got you. >> Then because we never
set the task completed, then the task might run
forever if it doesn't fault. This is faultings, it
actually has a safeguard. >> Got you. >> But otherwise, who knows? >> Who knows? >> To fix that, what we do is in our new method here, here, in the right way, we'll see this is a different method, similar to before with all the
structuring and harnesses. But in the "Task.Run" itself, instead of just setting the result, we actually have a check
on a cancellation token. If it's canceled, we need
to call "TrySetCanceled". Then in an exception case, we have to "TrySetException". >> Makes sense. Handle all the cases in which it can possibly go wrong. >> Exactly. >> Got you. >> In this way, we're totally safe. Any edge cases and exceptions,
we'll handle them. Any cancellations,
they're all covered. >> Very cool. That's nice. That's nice to see that, also prints out the faulted task, and stay in everything
that you would need. >> Yeah. >> Very cool, and all the exceptions. >> Exactly. >> Yeah. >> A funny thing with
the exceptions too. In our view model, we actually have a "try"
"catch" around the "WhenAll". This one gets us the exception, but it's only the first exception that occurs out of all of the tasks. >> I see. Got it. >> Here, we'll see, if we print "ex.Message", that's
only the first one. What we have to do is, we
have to check on each task, what the exception is, if any. >> Got it. Got it. >> That's kind of a got you. If you're not looking for it, it's really easy to miss. >> Makes sense. Awesome, Dean. I love it because these are things that I can apply it to my app today. Now I know you have a lot more. We should probably take
a break and come back for a part 2 advance. How
do you feel about that? >> Sounds great. >> Awesome. Well, thanks
everyone for tuning in. Dean, thanks for coming and
showing this off. Appreciate it. >> Thanks for having me. >> Now, don't forget in
the show notes below, we'll have all the links to the documentation, all
the things you need. You can also go to
aka.ms/xamarinbestpractices for everything in this series. Thank you so much for tuning in. I'm James Montemagno. This is The Xamarin
Show. Have a good one. [MUSIC] >> Hey, James here. Just
wanted to check in, and thank you for
watching this video. Now, do all the things that you
know you want to do such as "Like" "Subscribe", and ding
that notification bell, become part of the
notification squad. While you're here, check out all of these awesome videos that have already recorded,
click on that thing. Click it, watch it, do it.