>> If your code is perfect and
there's nothing wrong with it, don't watch this episode
of Visual Studio Toolbox where Leslie Richardson will show
us debugger tips and tricks. >> I envy that person. [MUSIC] >> Hi, welcome to
Visual Studio Toolbox. So I'm your host
Robert Green and joining me today is Leslie
Richardson. Hey, Leslie. >> Hi. >> Thanks for coming on the show. >> Thanks for having me. >> Leslie is a PM in
Visual Studio land. >> Sure, I am. >> We're going to talk about
debugging tips and tricks. >> Yes, we are. So there's
obviously a lot to cover in the debugging space that sadly a lot of
people don't know about. You can spend countless hours debugging that one bug
and going through the most tedious steps
possible when at the end of the day you just want to get
back to writing code, right? >> Yeah. >> Yeah, so hopefully some
of these tips that I show you will help you
out in the long-run. >> Cool, and a lot of these have
been in the product for a while. Some are new to 2019. >> Yup. >> So if you can remember
too when there's something that's brand new and
2019, let's call that out. >> Okay. >> Otherwise, this is just
stuff in Visual Studio. >> Awesome. Yeah, definitely. So I'm going to be focusing more
on the .NET space today but a lot of these features
overlap into C++ as well. So I'm in Visual Studio
2019 right now and I'm using an ASP.NET
Core application. Because I loved to read so much, this is an app that randomly gives me a list of books that
I can choose to read and add to my shelf or reject and
they won't be added to my shelf. So this app also has a lot
of problems with it, so hopefully we can use some of the debugging tools available to
us in order to figure them out. >> Cool. >> So first off, I have
a breakpoint already set in this Book Manager constructor
here and this happens pretty early on in my program's
execution where it takes in a JSON file containing a bunch of different book-related
information, converts each piece of that into a book object and then stores
each of those in a list. So I'm at the start
of my function here but I actually want to navigate
to the bottom here instead. So normally that
would be when I start stemming F10 or step over in order to get down there but that can be tiresome especially because I have this for loop
right in the middle, so that can take a lot of time and that's not
very productive of me. So the other option
of course is to just set a breakpoint at
the end and then hit F5. But then if I do that, I have to remember to delete
the breakpoint afterward. >> Right, because
the next time you run the app and you get up and go
for a coffee or something, you come back and sitting on that
breakpoint you forgot to remove. >> Exactly, it's like I
thought it was going to run without me while I
get my coffee but no. So another alternative is
something called Run to Click which I can perform by hovering over the line I
want to navigate to next. When I do that, you'll notice there's this little green glyph
icon that shows up, and I can click on that and it'll run all of my code up to
that particular line. >> Which is easier
than going down there right-clicking and
then finding Run to, or set next statement, or whatever it was. This is just quicker. >> Exactly. It's like having a remote control for
your code and being able to fast-forward to
where you want to go. So from there, the reason
why I wanted to go to the end of this function
is because I wanted to hone in on that book lists which stores a hundred different books
because I want to quickly inspect each one. When I hover over
it, I get a data tip but one of my problems that I have a data tips from time to time is that the moment I hover away
from it, it disappears. So if I want to keep
it for a while longer, what I can do instead is pin it, and when I pin it,
this data tip will stick around for as long as I decided to leave
it until I ultimately close it. >> You can drag that to
a second monitor; is that true? >> You know I haven't actually tried. Good question. I feel like
that should be possible. >> Okay. >> But good question. The good news about this is that when I close
out of my debugging session here, it'll still be present even
when I start a new one. So now if I wanted to inspect all of the contents
of this list here, at first glance, this
isn't really helpful. Let's say I wanted to inspect
each book by their names, it would be a little
tedious to expand each of these out until I find there's the title property and
then keep going to the next one and so forth
until I find what I'm needing. So this also goes for if I were in the Locals window as
well or Watch, or Autos. Ideally, it would be
a lot nicer if instead of getting the type of object
under the Value column, I could see particular
properties that I'm interested in so I can just
quickly skim through this list. So thankfully, there is a feature that you can
use in Visual Studio, that's one of my favorites and it's an attribute
called DebuggerDisplay. That is an attribute
that allows you to customize how you view
your objects in the Watch, Autos, Locals, and Data Tip windows. So to do that, I can go and
see where I defined my class. At the top of that class definition, I can write in
some DebuggerDisplay syntax. The curly brackets
will return the value of any property or properties
because I can go plural with it, I can also use expressions, if I wanted of whatever
property that I specify. In this case, I want to view
books by their title property. So I'm going to type in title, and I'm also going to have to
restart the debugging session. But hopefully, this is
where the magic happens. So this is an attribute that
exists currently in F#, C#, and Visual Basic. So this is for manage users
but if you're a C++ user, the equivalent that you
can use that performs the same function is
something called Natvis where the difference
mainly is that you have to create a separate Natvis file
inside your project. That contains some XML that
you can add to or modify in order to perform the thing
that I'm about to show you. So I need to go back to the end
of this function again. I'm going to use Run To Click, and I have my Data Tip that I penned earlier that's still here
because I never closed it. This is my favorite.
This is the magic. >> That is cool. >> So cool. I love it a lot. >> Okay, now this is the
part where we have fun. How long it's been in the process? >> Yeah. Longer than 2015. Longer than 2015. It's
been around for a while. Longer than me, definitely. >> That's my favorite
part of the show. >> I get asked that all the time. So is this a 2017, 2019 exclusive? I'm like, "Oh no". >> No. Awesome. >> Yeah. So that's
one of my favorites. So another thing that I like- >> You can do
expressions, so you could concatenate a couple
of fields, actually? >> Exactly, yeah. If you wanted to do some simple type of expressions, then you can do that as well. If you're interested in seeing one property plus
another it's possible. >> Could you do something
like a function that says if these three
fields are missing, just display "incomplete",
then if they're there, display "complete". Can
you do stuff like that? >> You can, yeah. You can do some simple if conditional
type statements as well. Do it at your own risk. My recommendation for
when things start to get very complicated in
your DebuggerDisplay syntax, is to create another property
or function within that class first called like the DebuggerDisplay or
something like that. Include all that logic and then you can write the function name inside- >> That makes a lot of sense. >> -the DebuggerDisplay. >> Okay. >> From there,
another feature that I like are the Text Visualizers
in Visual Studios. So for instance, I have this JSON variable here that
stores all my JSON contents, and if I'm looking at it, first, I need to actually
navigate back to it because this is earlier on in my code and I'm
currently out of scope. So what I can use for
that is something called set to .NET statement which
I think you mentioned earlier. So to do that, I can pretend as if I were doing another Run To Click, so I can hold down the Control key and that
green glyph will turn into yellow icon which will
automatically move my execution pointer up
to that particular line. So that's nice especially if you want to try out what different
execution paths are going to be looking like or if you
want to go back and re-inspect a previous variable
but you have to use it at your own risk because
since you are changing the execution flow in a way that
it is not necessarily intended, it has the potential to mess
with the rest of your codes execution unless you restart and
make a new debugging session. So from there, I have the JSON
variable and looking at it, it's not very readable right off the bat because it's formatted
for JSON particular. That and it cuts off the screen. So if I'm looking at it in
the Local's window for instance, there's this magnifying glass icon
that's next to that and I can click this drop down to get a list of
different visualizers I can use. So I'm going to use the JSON
visualizer because it's a JSON. This time I get a lot
better of a formatted view. So I can quickly view this giant string and it's
proper format which is great. Again, if you had a string
that's cater for HTML or XML, then you can do that
as well or if you have something that's catered for
something completely different, you can also make
your own visualizers, so that's pretty needed. Also, if you just have a giant paragraph of text
being stored in a variable, you can just use the regular
text visualizer as well. >> Cool. >> So from there, now I
want to start looking into some problems with
my application itself. So I'm going to hit "Continue", and so this is the general
application, and again, I can go to this rate books page where'll
randomly give me a list of books that I can read to add in my shelf or not read
and they won't be added. So in my case, I just want to read everything. So I'm going to add. >> A hundred books. >> Yeah, I'm going to
read all hundred of them. >> How long will that take you? >> It depends. Depends
on how big it is. I have the goal every
year of reading 25 books. So I'm not quite at
the 100 a year things, so let's go with four years for 100. But I'm noticing that
of the 100 books that are supposed to be added to
the shelf when I do that, it looks like there's
only around half of them. So if I go into Visual Studio, I want to double-check that
out but also I should receive a notification if I click on the "Rate Books" page telling
that all the books are gone. Instead, I get a lovely
exception error instead. So let's try to solve this issue. I'm going to navigate to my
AddAlltoShell() function, and this is my function
that will take each book on the "Rate Books" page and
move them into my shelf. I'm thinking the problem lies
within this for loop here. So I want to see
what's going on here. When I first started coding, I was really big on
print statements everywhere. Yeah, I don't know how many people
in the audience out there love print statements as much
as I did but they're great. >> Well, I graduated to
writing things to a text file. >> Yeah, that's great
too, accounts logging. But I guess the problem with
that at least for me was that it would be all over my code
even when it's not needed, I forget to delete it when I'm done. So I prefer to not
modify my code nowadays. If you do like to log your
information to the output window, an alternative you can
use is a trace-point which is an offshoot of
a regular breakpoint. That will allow me to
essentially perform a print statement without having
to modify my code in the process. I'm going to set a normal breakpoint
inside this for loop first and then I can hover over the breakpoint to get
little settings icon. When I click on that
I'm going to select "Actions" and here I'll get a prompt telling me what I want to
log to the output window. In this case, I want to see how many indices this for loop goes there before it stops because I feel like it's
stopping prematurely. So I'm going to do index:{i} and
return the value of variable i. Hit "Enter" and I'm
going to leave "Continue Execution" checked but
if you wanted your code to stop when a trace-point
is about to be printed, you can do that as well. You get a diamond icon instead
of the circle as well. I'm going to boot up
the program again. >> It would come in handy if you wanted to watch
the progress of something. I was working on some code yesterday that looks in GitHub repositories
and it loops through a large number of them and some of them there was an exception
and I just wanted to know which ones through the exception without
watching this program go, that could take hours. So I wrote it to a file
which worked but it seems like this way
I could just write that information out to
the console window and then I don't have this printing, the saving to a file in my code, which I could
accidentally released to production and then it will
blow up because someone didn't have the directory that
this is writing to, right? >> Right. >> The big risks in
modifying the code to do debugging is you leave
that stuff in there. >> Yeah, because I am
pretty sure I've done a demo in school at
one point where I left some arbitrary console.log
something rather, and I always write weird quotes in it when I'm frustrated
and trying to debug. So like I said, like a random [inaudible] right in
the middle of the demo. >> What idiot wrote this code,
how comes this doesn't work? >> From here, I'm going to perform
that same "Add All Books" to My Shelf option and this time, I should see some print
statements to go with it. So going back into VS, I can go to the output window and scroll up a little bit and here you'll notice that there's a bunch of related print statements going back with the trace-point
that I created. This is one way to check out your trace-points but also
the problem with this is that these can easily get buried in the sea of stuff
in the output window. So the other place where you
can check them out that I like is in the
diagnostic tools window. This is the window that
I have a bad habit of closing usually when I'm
debugging but one of the perks of keeping it
open is this because you can filter out events that you see. >> I have a bad habit of leaving it open and watching the pretty picture. >> Yes, that's true too.
I do love the CPU graphs. >> Yeah, but then what
are you doing with that? >> But it makes you
look official when somebody's walking past you, what is that person doing? >> Although I did use it in
this application I was working on to tell if there was a problem
because the exceptions, and there's like 10 exceptions
that just happen, but then when I noticed
that there were 20,000 exceptions or 50,000
or 150,000 exceptions, that was my clue because the way this code
works if it hits an exception, it just sits in a loop because it's assuming that it
just needs to keep trying and when I got to 400,000
exceptions that was my clue that, hold on a second. >> Like well, okay, maybe
I should do something. You can view your
trace-points here as well which might make things
a little easier too. So from there, I'm noticing
that my index value, i, only goes up to 49 when
it should go up to 99. At this point, I just want
to step through like that last iteration of my for loop just to see what's going on
with each piece of it. I'm going to go back to
where I set this trace-point and now the new problem
is I want to go through this for loop but I don't want to start from
the very beginning of it, like from when i is equal to zero because I'll be there for
days and chances are I'm not going to pay attention
and I'm going to skip when i equals 49 and then I
have to rinse and repeat. So I can use a conditional breakpoint instead which will allow me to halt my code only under
a specific scenario that I give it. So where I set the trace-point, I'm going to go back to settings
and I'm going to uncheck "Actions" because I'm done with this tracepoint and
check "Conditions". From there, I want my code to
halt when i is equal to 49, hit "Enter" and closeout. The conditional breakpoint
has been created based off of this little plus icon
inside the standard icon. I'm going to have to
restart it again. >> Now, those conditional breakpoints are things have been in there for pretty much all or I don't even
remember when those were created. >> Yeah, I have no idea. I feel like I started hearing about Visual Studio around 2013 or whichever one
was before 2015. >> 2013. >> Yeah, '13. So anything past
that, I have no idea. Cool. Again, we're performing that "Add All Books"
to My Shelf action. My code halts this
time and you'll notice that the value of i is set
to 49 instead of zero. So from there if I step
through this for loop, I'm noticing that I used my neutralBooks.Count here as my loop
condition and at the same time, a book is being removed from neutralBooks at the end
of each iteration, which is causing the count to decrease at the start
of each new iteration. So think I found the problem here. So I'm going to stop debugging
and we're going to comment out this line and then just clear all the books at
the very end of the function instead and that should solve
the issue, get rid of that. >> Now, is there a way, okay, let's say you thought
that was the issue, you could add neutralBooks.Count
to the watch window, right? >> Right. >> But, correct me if I'm
wrong, but it doesn't update in real-time as the application
is running; is that true? >> Oh, it does update in real-time. If you add it to the watch window and you're stepping
then if it changes, it will let you know that it changed because it usually highlights in red in either the watch
or in local's window. >> All right. Good. >> Cool. From there,
adding all books. It's time it looks like there's
a lot more books that have been added and just to double-check,
it turns out yeah, I've rated all the books
in the library already. That was conditional breakpoints
and tracepoints, two awesome alternatives to regular breakpoints that you can use in your everyday
debugging environment. >> Cool. So I think what
we'll do is stop here and call this part one
and then next week we'll do part two and see
more debugging tricks. People want to learn more about that, you wrote a blog post on this, right? >> I did. >> People can check out at
aka.ms/DebuggerDisplay. >> Yeah, it goes through a lot more of the different scenarios that you can use with it and you can go
check it out for more examples. >> We will see you next time
on Visual Studio Toolbox. [MUSIC]