>> 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]