Performance Check With MiniProfiler In ASP.NET MVC

MiniProfiler is an open source profiling library which monitors the performance of a .NET application. It is very lightweight and fast. Using this, we can easily track a performance issue with our application. It was created by Stack Overflow Team members. 

To know more about MiniProfiler, just visit the official site.

Why is MiniProfiler useful?

Creating an application with a high-performance rate is not an easy task. But due to complex logic, mapping entities, multiple libraries, good amounts of HTML, CSS and JS code, Database logic, connectivity, and server response time etc., our application becomes too slow. And it becomes very hard to figure out the exact root causes which slow our application.

MiniProfiler is an awesome tool to figure out how much time in processing each portion of the application takes. We can easily see, using MiniProfiler, how much time our database logic is taking and how much time is taken by our server response etc.  Basically, MiniProfiler helps us to know who is responsible for slowing our application down so that we can make an improvement on that part and make the application faster.

Setting up MiniProfiler with Asp.Net MVC Application

First, create an application in ASEP.NET MVC 4, right-click on the project, and choose “Manage NuGet Packages..” to install MiniProfiler for ASP.NET MVC application. As we can see with the below screenshot, we have searched for MiniProfiler.MVC and are going to install the second one, “MiniProfiler.Mvc4”. We can also see the description of MiniProfiler that says “MiniProfiler which was designed for ASP.NET MVC 4+ sites”. So, let us install this by clicking on the “Install” button from the right pane.

ASP.NET

After MiniProfiler installation, we will find two references inside the Project Reference section - “MiniProfiler” and “MiniProfiler.Mvc”. Now, it's time to configure when MiniProfiler will start profiling to the application. So, make the following entries inside the Global.asax file.

  1. using StackExchange.Profiling;  
  2. using System.Web.Mvc;  
  3. using System.Web.Optimization;  
  4. using System.Web.Routing;  
  5.   
  6. namespace MiniProfilerTest  
  7. {  
  8.     public class MvcApplication : System.Web.HttpApplication  
  9.     {  
  10.         protected void Application_Start()  
  11.         {  
  12.             AreaRegistration.RegisterAllAreas();  
  13.             FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);  
  14.             RouteConfig.RegisterRoutes(RouteTable.Routes);  
  15.             BundleConfig.RegisterBundles(BundleTable.Bundles);  
  16.         }  
  17.         protected void Application_BeginRequest()  
  18.         {  
  19.             if (Request.IsLocal)  
  20.             {  
  21.                 //MiniProfiler will start at the begining of the request.  
  22.                 MiniProfiler.Start();  
  23.             }  
  24.         }  
  25.   
  26.         protected void Application_EndRequest()  
  27.         {  
  28.             //MiniProfiler will stop at the begining of the request.  
  29.             MiniProfiler.Stop();  
  30.         }  
  31.     }  
  32. }  

As we have configured with the above code, MiniProfiler should start profiling once a new request gets the process; and stop profiling at the end of the request.

Now, move to the View and configure MiniProfiler so that the profiling data will get inside the HTML portion at the top left corner. To do that, we have to add “@MiniProfiler.RenderIncludes()” code with Layout page. We have chosen layout page because we would like to profile each request that is using this layout page.

  1. @using StackExchange.Profiling  
  2.   
  3. <!DOCTYPE html>  
  4. <html>  
  5. <head>  
  6.     <meta charset="utf-8" />  
  7.     <meta name="viewport" content="width=device-width, initial-scale=1.0">  
  8.     <title>@ViewBag.Title - My ASP.NET Application</title>  
  9.     @Styles.Render("~/Content/css")  
  10.     @Scripts.Render("~/bundles/modernizr")     
  11. </head>  
  12. <body>  
  13.     <div class="navbar navbar-inverse navbar-fixed-top">  
  14.         <div class="container">  
  15.             <div class="navbar-header">  
  16.                 <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">  
  17.                     <span class="icon-bar"></span>  
  18.                     <span class="icon-bar"></span>  
  19.                     <span class="icon-bar"></span>  
  20.                 </button>  
  21.                 @Html.ActionLink("Application name""Index""Home"new { area = "" }, new { @class = "navbar-brand" })  
  22.             </div>  
  23.             <div class="navbar-collapse collapse">  
  24.                 <ul class="nav navbar-nav">  
  25.                     <li>@Html.ActionLink("Home""Index""Home")</li>  
  26.                     <li>@Html.ActionLink("About""About""Home")</li>  
  27.                     <li>@Html.ActionLink("Contact""Contact""Home")</li>  
  28.                 </ul>  
  29.             </div>  
  30.         </div>  
  31.     </div>  
  32.     <div class="container body-content">  
  33.         @RenderBody()  
  34.         <hr />  
  35.         <footer>  
  36.             <p>© @DateTime.Now.Year - My ASP.NET Application</p>  
  37.         </footer>  
  38.     </div>  
  39.     @Scripts.Render("~/bundles/jquery")  
  40.     @Scripts.Render("~/bundles/bootstrap")  
  41.     @RenderSection("scripts", required: false)  
  42.   
  43.     @MiniProfiler.RenderIncludes()  
  44. </body>  
  45. </html>  

DO NOT DO

Don’t install “MiniProfiler” and then “MiniProfiler.Mvc4” or “MiniProfiler.Mvc3” one by one with ASP.NET MVC application. It will create an issue with the MVC application; the MiniProfiler will not work and you will get the following issue.

“localhost:port/mini-profiler-resources/results”  Not Found [404].

WHAT TO DO

  • Always install a specific version when working with ASP.NET MVC application. For example, if working with ASP.NET MVC 4, then choose “MiniProfiler.Mvc4” from NuGet and install it or if working with ASP.NET MVC 3, then choose “MiniProfiler.Mvc3” from NuGet and install it.
  • If you get an error after running the application with MiniProfiler.Mvc4 or MiniProfiler.Mvc3, which states “/mini-profiler-resources/includes.js 404 not found”, then simply add the following line of code in Web.Config inside Web Server section.
    1. <system.webServer>  
    2.     <handlers>  
    3.       <add name="MiniProfiler" path="mini-profiler-resources/*"  
    4.                verb="*" type="System.Web.Routing.UrlRoutingModule"  
    5.                resourceType="Unspecified" preCondition="integratedMode" />  
    6.     </handlers>     
    7. </system.webServer>  

Finally, we have done all the installation and settings to configure MiniProfiler with ASP.NET MVC application. Now, we can run the application. To run, press F5 and the application will be populated as follows with MiniProfiler Data at the top left corner of the application. The output will be like in the below image. Here, we can see clearly how much time each event has taken to process.

ASP.NET

If we view the “page source”, we will find the following scripting code which is auto generated and added with the View to display the profiling data.

  1. <script async type="text/javascript" id="mini-profiler" src="/mini-profiler-resources/includes.js?v=sudYtmATCtlvvgsiJ+ijDWT8sy88Fx31VI8aPQ/CYM8=" data-version="sudYtmATCtlvvgsiJ+ijDWT8sy88Fx31VI8aPQ/CYM8=" data-path="/mini-profiler-resources/" data-current-id="bd11c448-99dd-4c44-a49a-e248cc52bb83" data-ids="bd11c448-99dd-4c44-a49a-e248cc52bb83" data-position="left" data-trivial="false" data-children="false" data-max-traces="15" data-controls="false" data-authorized="true" data-toggle-shortcut="Alt+P" data-start-hidden="false" data-trivial-milliseconds="2"></script>  

Now, let us move on to  see how MiniProfiler works with actual data. To complete this demonstration, we are going to create some dummy blog post data in one step and in the next step  we are going to modify the actual username.

Note

I am creating dummy data inside the controller itself. Instead of this, we can get actual data from API.

We can define our own steps to see which process takes how much time. So, basically, STEPs in MiniProfiler are used to see the performance of each process, like getting data from the server, updating data on the server or posting data in Database etc.  Here I am going to create a list for Blog Posts and define it inside one STEP.  Another STEP will be defined to update the Username for Blog Post as in the below code shown.

So, first, let's create a model class for a blog post which has a few properties to define the blog data. Just create a class inside the Model folder with the name “BlogPost”.

  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Web;  
  5.   
  6. namespace MiniProfilerTest.Models  
  7. {  
  8.     public class BlogPost  
  9.     {  
  10.         public int PostId { get; set; }  
  11.         public string Title { get; set; }  
  12.         public string Category { get; set; }  
  13.         public string Content { get; set; }  
  14.         public string UserName { get; set; }  
  15.     }  
  16. }  

Now, move to the home controller and define steps. The first step will be defined to“Get Blog Post Data”. Here, we are creating dummy details for the blog post to show on View but instead of this, we can also get the actual data from our services or APIs. With the next step “Update User Info”, we are modifying the username based on a certain condition. Once the Model is defined, it will be passed to View to render the data on the View in a tabular format.

  1. using MiniProfilerTest.Models;  
  2. using StackExchange.Profiling;  
  3. using System;  
  4. using System.Collections.Generic;  
  5. using System.Linq;  
  6. using System.Web;  
  7. using System.Web.Mvc;  
  8.   
  9. namespace MiniProfilerTest.Controllers  
  10. {  
  11.     public class HomeController : Controller  
  12.     {  
  13.         public ActionResult Index()  
  14.         {  
  15.             var miniProfiler = MiniProfiler.Current;  
  16.             List<BlogPost> post = new List<BlogPost>();  
  17.   
  18.             //Suppose getting blog post data form API call.  
  19.             using (miniProfiler.Step("Get Blog Post Data", ProfileLevel.Info))  
  20.             {  
  21.                 post.Add(new BlogPost() { PostId = 1, Title = "Blog Post Title 1", Category = "Category 1", Content = "Content for Blog Post 1" });  
  22.                 post.Add(new BlogPost() { PostId = 2, Title = "Blog Post Title 2", Category = "Category 2", Content = "Content for Blog Post 2" });  
  23.                 post.Add(new BlogPost() { PostId = 3, Title = "Blog Post Title 3", Category = "Category 1", Content = "Content for Blog Post 3" });  
  24.                 post.Add(new BlogPost() { PostId = 4, Title = "Blog Post Title 4", Category = "Category 2", Content = "Content for Blog Post 4" });  
  25.                 post.Add(new BlogPost() { PostId = 5, Title = "Blog Post Title 5", Category = "Category 1", Content = "Content for Blog Post 5" });  
  26.             }  
  27.   
  28.             using (miniProfiler.Step("Update User Info", ProfileLevel.Info))  
  29.             {  
  30.                 //Suppose updating user name form API call update here.  
  31.                 foreach (var item in post)  
  32.                 {  
  33.                     if (item.PostId < 3)  
  34.                     {  
  35.                         item.UserName = "Mukesh Kumar";  
  36.                     }  
  37.                     else  
  38.                     {  
  39.                         item.UserName = "Admin";  
  40.                     }  
  41.                 }  
  42.             }  
  43.   
  44.             return View(post);  
  45.         }  
  46.   
  47.         public ActionResult About()  
  48.         {  
  49.             ViewBag.Message = "Your application description page.";  
  50.   
  51.             return View();  
  52.         }  
  53.   
  54.         public ActionResult Contact()  
  55.         {  
  56.             ViewBag.Message = "Your contact page.";  
  57.   
  58.             return View();  
  59.         }  
  60.     }  
  61.   
  62. }  

It's time to render the data on Index.cshtml View. So, make iteration on Model data and fill in the table as below.

  1. @model IEnumerable<MiniProfilerTest.Models.BlogPost>  
  2.   
  3. @{  
  4.     ViewBag.Title = "Home Page";  
  5. }  
  6.   
  7. <div class="pull-right" style="width:600px;">  
  8.     <h3>MiniProfiler Test Data</h3>  
  9.     <table style="border:3px solid #808080;">  
  10.         <tr>  
  11.             <th>ID</th>  
  12.             <th>Title</th>  
  13.             <th>Category</th>  
  14.             <th>Content</th>  
  15.             <th>User</th>  
  16.         </tr>  
  17.         @foreach (var post in Model)  
  18.         {  
  19.             <tr style="border:1px solid #808080">  
  20.                 <td>@post.PostId</td>  
  21.                 <td>@post.Title</td>  
  22.                 <td>@post.Category</td>  
  23.                 <td>@post.Content</td>  
  24.                 <td>@post.UserName</td>  
  25.             </tr>  
  26.         }  
  27.     </table>  
  28.   
  29. </div>  

Now, we have set up the steps, let's run the application to see what happens. If we run the application, we will see the output as following where we can see the actual data in Table format along with profiling data created by MiniProfiler.

We can clearly see the STEPs [Blue Circled with Image] which we have defined at the time of creating dummy data “Get Blog Post Data” and “Update User Info”. Here, we can see how much time this application has taken to “Get Blog Post Data” and how much time is consumed to “Update User Info”.

ASP.NET

So, based on this profiling report, we can modify our logic so that our application will get, post, update, or delete the data in minimal time.

Conclusion

Thus, we saw how to implement MiniProfiler with ASP.NET MVC application and how it can help us to know the actual time taken by each process.

I hope this post will help you. Please put your feedback using comments which help me to improve myself for the next post. If you have any doubts, please ask; and if you like this post, please share it with your friends.