Profile and debug your ASP.NET MVC app with Glimpse
Glimpse is a thriving and growing family of open source NuGet packages that provides detailed performance, debugging and diagnostic information for ASP.NET apps. It’s trivial to install, lightweight, ultra-fast, and displays key performance metrics at the bottom of every page. It allows you to drill down into your app when you need to find out what’s going on at the server. Glimpse provides so much valuable information we recommend you use it throughout your development cycle, including your Azure test environment. While Fiddler and the F-12 development tools provide a client side view, Glimpse provides a detailed view from the server. This tutorial will focus on using the Glimpse ASP.NET MVC and EF packages, but many other packages are available. Where possible I will link to the appropriate Glimpse docs which I help maintain. Glimpse is an open source project, you too can contribute to the source code and the docs.
- Installing Glimpse
- Enable Glimpse for localhost
- The Timeline tab
- Model Binding
- Routes
- Using Glimpse on Azure
- Additional Resources
You can install Glimpse from the NuGet package manager console or from the Manage NuGet Packages console. For this demo, I’ll install the Mvc5 and EF6 packages:
Search for Glimpse.EF
By selecting Installed packages, you can see the Glimpse dependent modules installed:
The following commands install Glimpse MVC5 and EF6 modules from the package manager console:
[!code-consoleMain]
1: PM> Install-Package Glimpse.MVC5
2: PM> Install-Package Glimpse.EF6
## Enable Glimpse for localhost
Navigate to http://localhost:<port #>/glimpse.axd and click the Turn Glimpse On button.
If you have your favorites bar displayed, you can drag and drop the Glimpse buttons and add them as bookmarklets:
You can now navigate your app, and the Heads Up Display (HUD) is shown at the bottom of the page.
The Glimpse HUD page details the timing information shown above. The unobtrusive performance data the HUD displays can notify you of a problem immediately - before you get to the test cycle. Clicking on the “g” in the lower right corner brings up the Glimpse panel:
In the image above, the Execution tab is selected, which shows timing details of the actions and filters in the pipeline. You can see my Stop Watch filter timer start at stage 6 of the pipeline. While my light weight timer can provide useful profile/timing data, it misses all the time spent in authorization and rendering the view. You can read about my timer at Profile and Time your ASP.NET MVC app all the way to Azure. The Tabs page provides links to detailed information on each tab.
I’ve modified Tom Dykstra’s outstanding EF 6/MVC 5 tutorial with the following code change to the instructors controller:
[!code-csharpMain]
1: public ActionResult Index(int? id, int? courseID, int ? eager)
2: {
3: var viewModel = new InstructorIndexData();
4:
5: viewModel.Instructors = db.Instructors
6: .Include(i => i.OfficeAssignment)
7: .Include(i => i.Courses.Select(c => c.Department))
8: .OrderBy(i => i.LastName);
9:
10: if (id != null)
11: {
12: ViewBag.InstructorID = id.Value;
13: viewModel.Courses = viewModel.Instructors.Where(
14: i => i.ID == id.Value).Single().Courses;
15: }
16:
17: if (courseID != null)
18: {
19: ViewBag.CourseID = courseID.Value;
20: // Eager loading
21: if (eager != null && eager > 0)
22: {
23: ViewBag.eagerMsg = "Eager Loading";
24:
25: viewModel.Enrollments = viewModel.Courses.Where(
26: x => x.CourseID == courseID).Single().Enrollments;
27:
28: }
29: else {
30: // Explicit loading
31: ViewBag.eagerMsg = "Explicit Loading";
32:
33: var selectedCourse = viewModel.Courses.Where(x => x.CourseID == courseID).Single();
34: db.Entry(selectedCourse).Collection(x => x.Enrollments).Load();
35: foreach (Enrollment enrollment in selectedCourse.Enrollments)
36: {
37: db.Entry(enrollment).Reference(x => x.Student).Load();
38: }
39:
40: viewModel.Enrollments = selectedCourse.Enrollments;
41: }
42: }
43:
44: return View(viewModel);
45: }
The code above allows me to pass in query string (eager
) to control eager or explicit loading of data. In the image below, explicit loading is used and the timing page shows each enrollment loaded in the Index
action method:
In the following code, eager is specified, and each enrollment is fetched after the Index
view is called:
You can hover over a time segment to get detailed timing information:
The model binding tab provides a wealth of information to help you understand how your form variables are bound and why some are not bound as would expect. The image below shows the ? icon, which you can click on to bring up the glimpse help page for that feature.
The Glimpse Routes tab will can help you debug and understand routing. In the image below, the product route is selected (and it shows in green, a Glimpse convention). Route constraints, Areas and data tokens are also displayed. See Glimpse Routes and Attribute Routing in ASP.NET MVC 5 for more information.
The Glimpse default security policy only allows Glimpse data to be displayed from local host. You can change this security policy so you can view this data on a remote server (such as a web app on Azure). For test environments on Azure, add the highlighted mark up to the bottom of the web.confg file to enable Glimpse:
[!code-xmlMain]
1: <glimpse defaultRuntimePolicy="On" endpointBaseUri="~/Glimpse.axd">
2: <runtimePolicies>
3: <ignoredTypes>
4: <add type="Glimpse.AspNet.Policy.LocalPolicy, Glimpse.AspNet"/>
5: </ignoredTypes>
6: </runtimePolicies>
7: </glimpse>
8: </configuration>
With this change alone, any user can see your Glimpse data on a remote site. Consider adding the markup above to a publish profile so it’s only deployed an applyed when you use that publish profile (for example, your Azure test proifle.) To restrict Glimpse data, we will add the canViewGlimpseData
role and only allow users in this role to view Glimpse data.
Remove the comments from the GlimpseSecurityPolicy.cs file and change the IsInRole call from Administrator
to the canViewGlimpseData
role:
[!code-csharpMain]
1: public class GlimpseSecurityPolicy : IRuntimePolicy
2: {
3: public RuntimePolicy Execute(IRuntimePolicyContext policyContext)
4: {
5: var httpContext = policyContext.GetHttpContext();
6: if (!httpContext.User.IsInRole("canViewGlimpseData"))
7: {
8: return RuntimePolicy.Off;
9: }
10:
11: return RuntimePolicy.On;
12: }
13:
14: public RuntimeEvent ExecuteOn
15: {
16: get { return RuntimeEvent.EndRequest | RuntimeEvent.ExecuteResource; }
17: }
18: }
[!WARNING] Security - The rich data provided by Glimpse could expose the security of your app. Microsoft has not performed a security audit of Glimpse for use on productions apps.
For information on adding roles, see my Deploy a Secure ASP.NET MVC 5 web app with Membership, OAuth, and SQL Database to Azure tutorial.
- Deploy a Secure ASP.NET MVC 5 app with Membership, OAuth, and SQL Database to Azure
- Glimpse Configuration - Doc page on configuring tabs, runtime policy, logging and more.
|