Debugging, diagnostics and profiling are fundamental stages in software development that ensures that all errors, bugs and performance bottlenecks are found and resolved, before the application is deployed.
Every application developer is responsible for writing logical, syntactical and error free code.
However in real life, errors and bugs creep in, and can slow down the application. For this reason, developers are always looking out for tools to manage code for debugging and performance.
Although some 3rd party profiling and debugging tools like RedGate’s Ants Performance Profiler makes the job easier for you, Visual Studio 2015 and recent Visual Studio 2013 updates have also introduced new capabilities to maximize developer productivity and improve code quality.
In this article, we will explore some of the enhancements made to debugging features in Visual Studio 2015. We will also revisit some Visual Studio 2013 debugging features wherever applicable, for the sake of completeness.
Some new debugging features in Visual Studio 2015 are as follows:
- Understanding Debugging with Stepping
- Debugging a specific method out of multiple method calls from a single statement
- Debugging Code Data Visualizer
- Managing the Display of the Debugged Data
- Evaluating lambda expressions in debugger watch window
Since this article is based on the Release Candidate version of Visual Studio, it is possible that any feature discussed in this article may change in the future. Download the Free Visual Studio 2015 Community Edition or the Free Visual Studio 2013 Community Edition
Before we get started with these features, let us set up a sample application.
Set up a Sample MVC Application for Debugging
Step 1: Open Visual Studio 2015 and create a new empty ASP.NET MVC application as shown in Figure 1:
Figure 1: Empty ASP.NET MVC application
In this MVC application, add a new SQL Server Database of the name ApplicationDB.mdf in the App_Data folder. In this database, add a table called ‘EmployeeInfo’ with the following structure.
Figure 2: EmployeeInfo table
Step 2: In the Models folder, add a new ADO.NET Entity Data Model with the name ApplicationDBEDMX.edmx. This step will start a wizard. Select ApplicationDB.mdf file and the EmpoyeeInfo table. After completing the steps of the wizard, the EmployeeInfo table mapping will be generated.
Step 3: In the same project, add a new folder with the name ‘DataAccess’. In this project, add a new class file with the following code in it:
using System.Collections.Generic;
using System.Linq;
using MVC_ForDebugging.Models;
namespace MVC_ForDebugging.DataAccess
{
public class EmployeeDAL
{
ApplicationDBEntities ctx;
public EmployeeDAL()
{
ctx = new ApplicationDBEntities();
}
public List<EmployeeInfo> GetEmployees()
{
return ctx.EmployeeInfoes .ToList();
}
public EmployeeInfo GetEmployee(int id)
{
return ctx.EmployeeInfoes.Find(id);
}
public void AddNewEmployee(EmployeeInfo Emp)
{
ctx.EmployeeInfoes.Add(Emp);
ctx.SaveChanges();
}
public void UpdateEmployee(int id, EmployeeInfo Emp)
{
var e = ctx.EmployeeInfoes.Find(id);
if (e != null)
{
e.EmpName = Emp.EmpName;
e.Salary = Emp.Salary;
e.DeptName = Emp.DeptName;
e.Designation = Emp.Designation;
ctx.SaveChanges();
}
}
public bool CheckEmpNameExist(string ename)
{
bool isExist = false;
foreach (var item in ctx.EmployeeInfoes.ToList())
{
if (item.EmpName.Trim() == ename.ToUpper().Trim())
{
isExist = true;
break;
}
}
return isExist;
}
public bool CheckValidSalForDesignation(int sal)
{
bool isValid = true;
if (sal < 5000)
{
isValid = false;
}
return isValid;
}
public void DeleteEmployee(int id,EmployeeInfo Emp)
{
var e = ctx.EmployeeInfoes.Find(id);
if (e != null)
{
ctx.EmployeeInfoes.Remove(e);
ctx.SaveChanges();
}
}
}
}
This class will be used for performing CRUD operations using the Entity Framework model we added in Step 2.
Step 4: In the Controllers folder, add a new MVC controller with the name ‘EmployeeInfoController’. Add the following code in it:
using System.Web.Mvc;
using MVC_ForDebugging.Models;
using MVC_ForDebugging.DataAccess;
namespace MVC_ForDebugging.Controllers
{
public class EmployeeInfoController : Controller
{
EmployeeDAL obj;
public EmployeeInfoController()
{
obj = new EmployeeDAL();
}
// GET: EmployeeInfo
public ActionResult Index()
{
var Emps emps = obj.GetEmployees();
return View(Empsemps);
}
// GET: EmployeeInfo/Details/5
public ActionResult Details(int id)
{
var Emp emp = obj.GetEmployee(id);
return View(Empemp);
}
// GET: EmployeeInfo/Create
public ActionResult Create()
{
var Emp emp = new EmployeeInfo();
return View(Empemp);
}
// POST: EmployeeInfo/Create
[HttpPost]
public ActionResult Create(EmployeeInfo Empemp)
{
try
{
if (obj.CheckEmpNameExist(Empemp.EmpName) && obj.CheckValidSal(Empemp.Salary))
{
obj.AddNewEmployee(Empemp);
return RedirectToAction("Index");
}
else
{
return View(Empemp);
}
}
catch
{
return View(Empemp);
}
}
// GET: EmployeeInfo/Edit/5
public ActionResult Edit(int id)
{
var Emp emp = obj.GetEmployee(id);
return View(Empemp);
}
// POST: EmployeeInfo/Edit/5
[HttpPost]
public ActionResult Edit(int id, EmployeeInfo Empemp)
{
try
{
obj.UpdateEmployee(id, Empemp);
return RedirectToAction("Index");
}
catch
{
return View();
}
}
// GET: EmployeeInfo/Delete/5
public ActionResult Delete(int id)
{
var Emp emp = obj.GetEmployee(id);
return View(Empemp);
}
// POST: EmployeeInfo/Delete/5
[HttpPost]
public ActionResult Delete(int id, EmployeeInfo Empemp)
{
try
{
obj.DeleteEmployee(id, Empemp);
return RedirectToAction("Index");
}
catch
{
return View(Empemp);
}
}
}
}
This controller class contains action methods which calls the methods from EmployeeDAL class added in Step 3.
Generate Views from Index, Create, Details and Edit action methods. To generate View, right click on the Action Method and select the Add View option from it. Build and run the application.
Note: Open RouteConfig.cs file from the App_Start folder and change the routing as shown in the following code:
Figure 3: Changing Routing information
This will display the Index View when the application runs.
Now that we have setup the application, let’s jump into the new Debugging features in Visual Studio 2015.
New Debugging Features in Visual Studio 2015
Understanding Debugging with Stepping
We will explore a new experience of stepping through the code. Open EmployeeInfoController.cs and apply breakpoint on the Index action method. Run the application, and you will see that the Index() method from the EmployeeInfoController will be hit. We will make use of F10 (Step Over) and F11 (Step Into). We will use F10 to debug the GetEmployees() method call from Index() method and check values returned from it.
In Visual Studio 2015, we can make use of Locals and Autos window to check return values from the GetEmployees() method without jumping into it, as shown in Figure 4:
Figure 4: Checking return value in Locals Window
Using this feature, we can check the return values from an external method call without Stepping into the method. This is more useful if we are debugging in a multi-layered application where the code getting debugged, makes calls to multiple external methods.
Note: Visual Studio 2015 IDE provides a handy performance tooltip feature called PerfView, using which we can check how much time is taken by a statement. Typically we need this in case of foreach loops. In Figure 4, you can see the PerfView tooltip (yellow marked) which shows that the statement took 1341ms to execute.
Alternatively we can also make use of the Watch window to check returned values using pseudo variable of the name ‘$ReturnValue’. Open the Watch Window and use the $ReturnValue as shown in Figure 5.
Figure 5: Checking return value using Watch window
Debugging a specific method from a statement with out of Multiple Method Calls
Consider a scenario in the debugging code, where we have a statement calling more than one method, as shown in Figure 6:
Figure 6: Statement calling more than one method
The if statement makes calls to CheckEmpNameExist() and CheckValidSal() methods (along with get() method call for EmpName and Salary properties). In traditional debugging, to debug these methods we need to put a breakpoint on every method. In case of Visual Studio 2015, we can choose a specific method to debug using Step Into Specific context menu.
To experience this new feature, apply a breakpoint on the if statement of the Create() action method of the EmployeeInfoController as shown in Figure 6. Run the Index View. Click on the Create New link of the Index View. This will bring up the Create view. Enter Employee data in Create view and click on the Create button. This will display the code in the debugger on the if statement as shown in Figure 7:
Figure 7: Debugger Code
Right-click on the debug statement and select Step Into Specific option as shown in Figure 8:
Figure 8: Step Into Specific option
Figure 8 shows a list of all methods called in the currently debugged statement. From here, we can now select specific methods to be debugged. This will apply one-time breakpoint to the entry-point to that method, and the method will be debugged.
Select CheckEmpNameExist() method from the list and this method will get debugged as shown here:
Figure 9: Debugging a method
This feature gives us the benefit of selection based debugging for a specific method. One important thing to note here is that we can directly jump to the specific statement for debugging using Run to Cursor option from the context menu (available in Visual Studio 2013 as well). In the CheckEmpNameExist() method, right-click the if statement and select Run to Cursor, and the if statement will be hit by the debugger.T his eliminates the need to apply and remove breakpoint on a specific statement for debugging. To go back to the immediate statement from which we started the debugging, we can make use of the Step Out feature from the Debug menu.
Debugging Code Data Visualizer (available in VS 2013 too)
When debugging code, if the current statement contains a Data Source expression, we can view the data using Text, XML, HTML and JSON Visualizers.
To experience this feature, in the EmployeeInfoController.cs add the following namespace reference:
using System.Web.Script.Serialization;
Add the following lines in the Index Action method (highlighted)
public ActionResult Index()
{
var Emps = obj.GetEmployees();
var jObj = new JavaScriptSerializer();
var jsonData = jObj.Serialize(Emps);
return View(Emps);
}
In the above method, add a breakpoint on the return statement. The code serializes Emps into JSON format. Run the application and place the mouse cursor on the jsonData variable. You will see a magnifier on debug as shown in Figure 10:
Figure 10: Debug magnifier
Click on the dropdown of the magnifier to display the data visualizer options window:
Figure 11: Data Visualizer Options
Select the JSON Visualizer to display a window with JSON data:
Figure 12: JSON Visualizer
Figure 13: Search JSON Visualizer
Over here, Figure 13 displays a Search window to search data from the received data.
The data visualizer window will remember the selection made by us e.g. if we select JSON visualizer, it will keep remembering the JSON visualizer option. Likewise we can take advantage of various data visualizers.
Managing the Display of the Debugged Data (also present in VS 2013)
While debugging the code using Visual Studio 2013 and Visual Studio 2015, we are given a feature of managing the data display. In our code, the Index action method shows the Employees data. We can manage the display of this data during debugging using DebuggerDisplay attribute class. To experience this feature, open the EmployeeInfo class and apply the DebuggerDisplay attribute as shown here:
[DebuggerDisplay("Emp {EmpNo}")]
public partial class EmployeeInfo
{
public int EmpNo { get; set; }
public string EmpName { get; set; }
public int Salary { get; set; }
public string DeptName { get; set; }
public string Designation { get; set; }
}
In this code, the DebuggerDisplay accepts the string parameter. Here Emp represents the constant string and the {EmpNo} represents the EmpNo property which will represent the value of the Employee Record. Debug the Index action method and view the value for Emps as shown in Figure 14.
Figure 14: Debugger display for Employee records
Over here, Figure 14 shows the debugger display for Employee records as Emp 1, Emp 2, etc.
Using Make Object ID to Maintain the State of the Debug Result
Another useful debugging feature in VS 2015 (also present in VS 2013) is Make Object ID. While debugging the code, we make use of the Watch window to evaluate the expression. The watch window can maintain the state of the expression in the current scope only. When the expression moves out of the scope, the watch on it becomes invalid. But sometime it is necessary for us to keep watch on the data generated by the previous debug for the expression not in scope. We can implement this using the Make Object Id on the watch expression.
To experience this feature, apply the a breakpoint on the Index and Create with HttpPost action methods. Run the application, the Index action method will be hit. Press F10 on the Emps = obj.GetEmployees(); expression. To add watch, right-click on Emps and select Add Watch from the context menu as shown in Figure 15:
Figure 15: Add Watch option
This will display the watch window as shown in Figure 16.
Figure 16: Add watch window
To maintain the state of a specific record e.g. Emp 1, right-click on the [0] record and select the Make Object Id option as shown in Figure 17.
Figure 17: Generate ObjectID using Make Object ID
This will generate the Object Id,
..and will maintain the state of the first Employee record. Complete the debugging to display the Index view in the browser. IOn this view, click on the Create New link to display the Create view. This means now we have come out of the scope of the Index action method.
In the Create view, enter data in the TextBoxes and click on the Create button. This step will start debugging the Create action method. Once we enter in the debug mode, we can see the watch window where the previous watch is disabled as shown in Figure 18.
Figure 18: Disabled watch from previous debugging session
Here we cannot interact with Employee records Emp 2 and Emp 3. But since we have generated the object Id for Emp 1, we can check values generated using the Object Id as $1. In the watch Window, enter the Name as $1 and press enter, the values will be displayed as shown in Figure 19.
Figure 19: Object ID base watch
Evaluating lambda expressions in debugger watch window
While debugging code, sometimes we may come across LINQ queries or lambda expressions. Now we can evaluate these Lambda Expressions or LINQ queries using the Immediate Window. To experience this feature, we need to make some changes in the code.
Open EmployeeInfoController.cs and add the following reference in the code:
using System.Linq;
Apply the breakpoint on the Index() action method. Run the application and the Index method will be hit. Complete debugging for the following statement.
var Emps = obj.GetEmployees();
Now open the Immediate Window and start typing code.
Figure 20: Lambda Expression IntelliSense
Yes! We have IntelliSense!!
The Lambda Expression with its result can be seen in Figure 21.
Figure 21: Evaluating lambda expressions in debugger watch window
And with this feature, we can now evaluate the Lambda Expressions using the debugger Immediate Window in Visual Studio 2015.
Conclusion:
Visual Studio 2015 has provided some cool developer friendly and easy to use features for code debugging. Developers can now make use of these features for effective debugging management.
Download the entire source code from GitHub at bit.ly/dncm19-vs2015debug
This article has been editorially reviewed by Suprotim Agarwal.
C# and .NET have been around for a very long time, but their constant growth means there’s always more to learn.
We at DotNetCurry are very excited to announce The Absolutely Awesome Book on C# and .NET. This is a 500 pages concise technical eBook available in PDF, ePub (iPad), and Mobi (Kindle).
Organized around concepts, this Book aims to provide a concise, yet solid foundation in C# and .NET, covering C# 6.0, C# 7.0 and .NET Core, with chapters on the latest .NET Core 3.0, .NET Standard and C# 8.0 (final release) too. Use these concepts to deepen your existing knowledge of C# and .NET, to have a solid grasp of the latest in C# and .NET OR to crack your next .NET Interview.
Click here to Explore the Table of Contents or Download Sample Chapters!
Was this article worth reading? Share it with fellow developers too. Thanks!
Mahesh Sabnis is a DotNetCurry author and a Microsoft MVP having over two decades of experience in IT education and development. He is a Microsoft Certified Trainer (MCT) since 2005 and has conducted various Corporate Training programs for .NET Technologies (all versions), and Front-end technologies like Angular and React. Follow him on twitter @
maheshdotnet or connect with him on
LinkedIn