Performance can be a complex beast - modern web applications have dozens of moving parts that can create performance bottlenecks. ASP.NET Core has many tools to help you. This blog post explores how to apply them effectively to build highly-performant web apps with ASP.NET Core.
Performance may not be the first thing on your mind when building applications. Often the priorities are building what the customer needs and meeting deadlines - performance tuning tends to take a backseat. However, when it comes time to ship apps, development teams end up hustling, trying to get performance to usable levels. Such last-minute performance tuning kills forward momentum and results in long hours with lots of stress for developers. We can do better.
If performance is made a priority during development cycles, issues can be resolved in chunks, thus preventing the death march and a bunch of stress. Performance is also money - it’s well-documented that even small changes in performance can result in driving up user engagement and surprisingly large changes in conversion rates. Major websites have realized how important performance tuning is to the overall user experience. Time is Money drives this point home.
Besides user engagement and developer sanity, app performance is also important for SEO purposes - Google has made site performance one of their criteria in search engine rankings. Performance is equally a concern for internal enterprise apps, as slows apps are a drag on user productivity, which costs money.
So you get the point: Performance should be a focus right from the start. But performance can be a complex beast. Based on web technology stack and app pipeline layer, there are various performance concerns to deal with. Thankfully, there is some help from application platforms - let’s talk about frontend concerns when building apps with ASP.NET Core.
Frontend performance usually consists of two things. The first thing is reducing the size and number of requests going over the wire between server/browser - there are several ways to cut down on web traffic including bundling, compression, and caching strategies. The second thing is reducing the time the user has to wait around for things to happen. This is often achieved by making use of asynchronous code and preventing blocking actions from blocking the user. ASP.NET Core has built-in features that help developers achieve both of these performance goals.
While it’s easy to tell if an application is slow, it’s a lot harder to get usable measurements of performance. There are dozens of different metrics and data flows you can measure that contribute to overall performance. Additionally, variables like network traffic render exact measurements difficult. This doesn’t mean measuring performance is hopeless. As long as you can recognize the variability and limitations of benchmarks, you can still make progress.
When gauging performance, there are two different types of measurements you can take. The first is individual measurements - this is you working your way through an application flow and figuring out how long stuff takes. While you can do this with a stopwatch, there are lots of tools you can use to get more granular measurements.
One popular tool is Miniprofiler - created by the fine folks at Stack Exchange to measure performance on sites like Stack Overflow. It comes as a NuGet Package you can simply install in your application. It measures performance and displays the results in a small overlay on your browser. Miniprofiler looks at the whole stack and makes it easy to spot bottlenecks, duplicate SQL queries, and excessive requests. Here’s a glimpse of Miniprofiler in action:
Chrome DevTools are also popular to examine individual requests in web apps. Besides network request monitoring, Chrome DevTools also come with several built-in performance profilers and audit tools. One of the newer audit tools is on the Audits panel in Chrome DevTools. You can run a battery of different performance tests against your site and Google will give you helpful hints on how you can improve performance.
And of course, there is Fiddler - the de-facto tool to monitor your web app’s network layer. In addition to monitoring network traffic, Fiddler will generate statistics that help you find bottlenecks in your application. It also allows for web session manipulation, HTTP/HTTPS traffic recording and web content debugging from any device. Bottom line: Fiddler is here to help, why not use it?
While measuring individual performance is important, you also need to measure aggregate performance. There are classes of performance issues that only appear while the application is under load. The best way to get data about how your whole application running is to use an Application Performance Monitoring (APM) tool. There are many different APM tools on the market - popular ones include New Relic and Application Insights. Application Insights, being a Microsoft product integrated in the stack, is especially useful for ASP.NET applications.
Because you can always make your applications faster, there is a risk of getting sucked into a rabbit hole with performance tuning. Performance needs to be balanced with other development goals and app features. A good goal for any application is to never make the user wait for more than a second for any action. Optimizations of less than a second seem imperceptible to users, while anything over ten seconds should be immediately remediated. If you can’t get a specific action under a second, one thing to consider is making it asynchronous - give the user back control of the app and notify them when the task is finished.
CSS is what styles your web apps. While plain CSS can be powerful, you should consider using a preprocessor like LESS or SASS - it does give you superpowers, while maintaining compatibility. And once you start using a bundling tool, you can use it to make your own custom bundles of CSS. In addition to making it easier to build larger stylesheets, you can use these preprocessors to reduce your CSS package size. Most serious CSS developers end up using a frontend library like Bootstrap, Foundation, or Material Design. You are, however, likely not using all the features and controls in those libraries. If you’re using a preprocessor, you can build your own custom distribution and comment out all the stuff you aren’t using. This reduces your bundle size while allowing you to easily include those controls if you want to use them later.
Regardless of how small individual network requests get, nothing is faster than not using the network at all and grabbing content out of the cache. Caching is an essential part of the performance enhancement for most web apps, and done well, can lead to a wonderfully optimized user experience. ASP.NET has several different types of caching, depending on what part of the stack you’re trying to optimize and how you want to store your data.
Caching in ASP.NET Core can be divided into two categories. The first category is data caching - mostly used for backend processing. This is where we cache data in memory or a distributed cache, like a Redis or SQL Server instance. This type of caching is appropriate for saving the results of frequently accessed database queries or storing complex calculations.
Another way to employ response caching is to use a Content Delivery Network (CDN). Powered by cloud infrastructure providers, CDNs specialize in fast delivery of static assets - through distributed nodes across the world. You are essentially delivering content from as close to the user as possible, thus cutting down on network latency.
asp-fallback-test="window.jQuery && window.jQuery.fn && window.jQuery.fn.modal"
<script src="~/js/site.min.js" asp-append-version="true"></script>
You can also host your own CDNs. Microsoft Azure, for example, has CDN service that is easy to set up - one you can pair with your web application or Azure storage bucket. AWS and other cloud providers have similar CDN services as well. Bottom line, use CDNs to reduce network latencies and meet the user closer to their geographic locations, thus speeding up your web apps.
Performance can be a complex beast - modern web applications have dozens of moving parts that can create performance bottlenecks. ASP.NET Core has many tools to help you though. From measurement tools like Miniprofiler to middleware and helpful TagHelpers, there’s no shortage of tricks you can use to make your applications go faster.
If you don’t know where to start, begin with measurement. Get Miniprofiler or Application Insights running on your application and start hunting for bottlenecks. From there, let the data guide you. Find the biggest bottleneck you can fix and get to work. Cheers to faster web apps that delight users.
Dustin Ewers is a software developer hailing from Southern Wisconsin. He helps people build better software. Dustin has been building software for over 10 years, specializing in Microsoft technologies. He is an active member of the technical community, speaking at user groups and conferences in and around Wisconsin. He writes about technology at https://www.dustinewers.com/.