ASP.Net Core is a fast, lightweight, open-source, cross-platform rewrite of the ASP.Net framework that runs on Windows, Linux, and even Mac OS X. Speed is one of the key features of ASP.Net Core, meaning that the ASP.Net Core framework is optimized for better performance. Nevertheless, there are some best practices and strategies you can adopt to improve the performance of your applications that leverage the .Net Core runtime.
The essence of improving application performance is ensuring that you build applications that consume the least amount of resources to produce the desired output. This article presents a discussion of the best practices you can adopt to improve the performance of ASP.Net Core applications.
Inlining methods improves performance as it saves the cost of jumps, passing arguments, and saving and restoring registers. Note that a method that contains a throw statement will not be inlined by the JIT (just-in-time) compiler. To solve this, you can take advantage of a static helper method to contain the throw statement.
Minimize virtual calls
Calls to virtual members are slower because virtual calls require indirection. Devirtualization is a feature of JIT compilers and a devirtualized method can become a candidate for inlining. When the type of an object is known, — the JIT for .Net Core — can devirtualize non-sealed method calls. To avoid virtual calls, you can follow these guidelines:
- Mark classes or methods as sealed by default
- Mark overridden methods as sealed as well
- Use concrete types in lieu of interfaces
Pool HTTP connections
Although HttpClient implements the IDisposable interface, it is advisable to reuse HttpClient instances. The reason is that HttpClient leaves the socket open and in the wait state for a short duration of time even after it has been closed. So, if you try to create new HttpClient instances every time a HttpClient is needed, you might run out of available sockets.
With this in mind, HttpClientFactory was introduced in ASP.Net Core 2.1 to pool HTTP connections. By pooling connections, HttpClientFactory optimizes performance, scalability, and reliability. So, avoid creating and destroying HttpClient instances directly, and use the HttpCLientFactory to retrieve HttpClient instances.
Reducing the size of the response improves the performance of the application because less data is transferred between the server and the client. You can take advantage of response compression in ASP.Net Core to shrink the response and reduce bandwidth requirements. Response compression in ASP.Net Core is available as a middleware component. The following code snippet shows how you can add response compression middleware to the request processing pipeline.
public void ConfigureServices(IServiceCollection services)
options.Level = CompressionLevel.Fastest;
You can also take advantage of ASP.Net Core’s built-in support for bundling and minifying client files or assets to improve performance.
For more information, you can read my article on .
Minimize large object allocations
The .Net Core garbage collector is adept at releasing memory occupied by objects in the managed heap. However, freeing up objects can take up CPU time, especially when the objects are large objects (85 Kbytes or more). Garbage collection happens in four generations — generations 0, 1, and 2 and the large object heap (LOH). The garbage collector works much more frequently in the lower generations than in the higher ones.
Garbage collection of large objects is expensive. To minimize large object allocations, you should take advantage of pool buffers using ArrayPool<T> and cache large objects that are used frequently. You should not acquire locks on common code paths and avoid allocating too many short-lived objects on hot code paths.
Use exceptions only when necessary
It should be noted that throwing and catching exceptions is expensive. Hence, exceptions should be used only when they are needed. You should minimize the use of exceptions in your application and avoid using exception handling to control program flow. You can read my article on to learn more.
Optimize data access
Remember that data access is one of the slowest operations in an application. You should call all data access APIs asynchronously. You should minimize roundtrips to the database and retrieve only the data that is needed. Avoid using projection queries on collections.
If you are using Entity Framework Core for data access, follow the recommended guidelines and practices in Entity Framework Core. If you are reading data that won’t be modified by the application, you should take advantage of no-tracking queries in Entity Framework Core. See my article on to learn how to improve Entity Framework performance.
While web application performance tuning is complicated, there are some common techniques and recommended practices you can take advantage of to improve the performance of your ASP.Net Core applications. You can also leverage certain tools like , , , and to measure application performance, detect the performance bottlenecks, and determine the appropriate remedies to fix them.