Showing posts with label Caching. Show all posts
Showing posts with label Caching. Show all posts

Wednesday, August 9, 2023

Building High-Performance Web Applications with .NET 8

 In the fast-paced world of web development, performance is paramount. Users have come to expect blazing-fast loading times and seamless interactions, and meeting these expectations can be a challenge. Fortunately, with the release of .NET 8, developers have a powerful set of tools and features at their disposal to build high-performance web applications that deliver exceptional user experiences. In this article, we'll explore how .NET 8 can be harnessed to create web applications that not only meet but exceed performance expectations.

1. Introduction to High-Performance Web Applications

High-performance web applications are characterized by their ability to deliver content and respond to user interactions swiftly, regardless of the user's device or network conditions. Achieving this level of performance involves optimizing various aspects of the application stack, including code efficiency, network requests, database interactions, and more.

2. ASP.NET Core: A Foundation for Speed

ASP.NET Core, the web framework within the .NET ecosystem, provides a solid foundation for building high-performance web applications. With .NET 8, ASP.NET Core has received further enhancements that contribute to its speed and efficiency. The introduction of "Minimal APIs" allows developers to create focused APIs with minimal overhead, reducing unnecessary code and improving response times.

3. Efficient Data Access

Web applications often interact with databases to retrieve and store data. With .NET 8, developers can leverage improvements in Entity Framework Core, the object-relational mapping (ORM) framework. Enhanced query performance optimizations and connection pooling can lead to faster database interactions, resulting in snappier application response times.

4. Caching Strategies

Caching is a powerful technique for improving application performance by storing frequently accessed data in memory. .NET 8 provides enhanced support for caching through libraries like Microsoft.Extensions.Caching.Memory, enabling developers to implement caching strategies that significantly reduce the load on the database and speed up data retrieval.

5. Asynchronous Programming

Asynchronous programming is crucial for web applications, as it allows the server to handle multiple requests concurrently without blocking the main thread. .NET 8 offers improved support for asynchronous programming patterns, such as the use of ValueTask in ASP.NET Core, which can lead to more efficient use of resources and reduced contention.

6. Performance Profiling and Diagnostics

Identifying bottlenecks and performance issues is a crucial step in optimizing web applications. .NET 8 includes enhanced diagnostic tools that make it easier to profile and analyze application performance. The improved error messages, stack traces, and debugging capabilities can help developers identify performance bottlenecks and address them effectively.

7. Content Delivery and CDNs

Content Delivery Networks (CDNs) play a significant role in web application performance by distributing static assets like images, stylesheets, and scripts across various edge locations. .NET 8 enables developers to seamlessly integrate with CDNs, reducing latency and improving the loading times of these critical assets.

8. Browser Compatibility and Performance

High-performance web applications should also consider browser compatibility and rendering performance. .NET 8 encourages the use of modern web standards and practices that ensure optimal rendering across various browsers and devices. Employing techniques like responsive design and lazy loading of assets can further enhance the user experience.

9. Continuous Monitoring and Optimization

Building high-performance web applications is not a one-time task; it's an ongoing effort. Continuous monitoring of application performance using tools like Application Performance Monitoring (APM) solutions can help developers identify issues in real-time and make necessary optimizations to maintain peak performance.

10. Conclusion

In a digital landscape where user expectations for speed and responsiveness are higher than ever, building high-performance web applications is a top priority. With .NET 8's powerful features and enhancements, developers have the tools they need to create web applications that not only meet these expectations but also exceed them. By optimizing data access, leveraging caching strategies, embracing asynchronous programming, and employing effective monitoring and profiling techniques, developers can unlock the full potential of .NET 8 to deliver exceptional user experiences and set new standards for web application performance.

11. Example

A recent project developed in ASP.NET 8 MVC: IIWIARS it's hosted on Microsoft Azure in Central US with MongoDB Atlas.

They are talking about it:

Saturday, October 27, 2012

Donut Caching with ASP.NET MVC 4

I'm working on a new personal project during my free time and I chose to develop it with ASP.NET MVC 4 (hosted on Azure of course...) to test the new features of this version.

In this project, I need to display "Logged in as xxxx " (if the user is logged...) in the header of the page. This is a simple scenario to implement but caching could complicate the development of my web app...

My header is in my layout and is used everywhere but I would like to place an OutputCacheAttribute on some actions (the home page, etc.). If I put the attribute on an action, all of my users will see an header with "logged in as xxxx" of the first incoming query!

The solution to this problem is named "Donut Caching": you send a cached page from the server with a "fresh" portion which is not in cache (the donut's hole).
Concretely, the server does not generate the requested page (query the DB, etc.): it just needs to take the cached version and replace a specific part.

Luckily, you do not need to develop your own custom OutputCacheAttribute because there is already a very good package (There's An App A Pack For That... thanks NuGet!): MvcDonutCaching for ASP.NET MVC 3 and later...

To install the package, you can search through NuGet or directly type the following command in the "Package Manager Console":

   1:  install-package MvcDonutCaching


The use of this package is very simple... They have created several extension methods for HtmlHelper with the usual parameters plus another boolean parameter: excludeFromParentCache. I just have to call my partial view (with the "connected has xxxx"...) like that:


   1:  ...
   2:   
   3:  @Html.Action("LoginHeader", "Account", new { lang }, true)
   4:   
   5:  ...

The last parameter of Html.Action is set to true: this partial view will be excluded from the parent cache (if there is a cache on the action...). (do not pay attention to new { lang }, it's a route's value)

To make it work, you must not use the OutputCacheAttribute but the DonutOutputCacheAttribute:


   1:  [DonutOutputCache(Duration = 60, VaryByParam = "lang")]
   2:  public ActionResult Index(string lang)
   3:  {
   4:      ...
   5:   
   6:      return View();
   7:  }

And that's it! The first request will be cached during 60 seconds but the LoginHeader partial view will be generated every time.

(note: of course, the donut caching only works on the server side...)

Wednesday, September 28, 2011

Customised OutputCache with VaryByCustom

In ASP.NET (MVC or not), it is possible to easily cache the rendering of a web page.
Take the case of an ASP.NET MVC project :

   1:  [OutputCache(Duration = 3600, Location = OutputCacheLocation.Client)]
   2:  public ActionResult Index()
   3:  {
   4:      return View();
   5:  }

We use the attribute "OutputCache" to cache the page. This case is very simple, the page is cached for one hour (3600 seconds) on the client side.

Now imagine that the "Index" view contains the actual time...

   1:  <p>@DateTime.UtcNow.ToLongTimeString()</p>

If you debug your website, you will see that the time is the same after a refresh. You can try this during an hour, it will still be the same.
Now we change the view's code with this:

   1:  <p>@DateTime.UtcNow.ToLongTimeString()</p>
   2:  <a href="?parameter=1">test</a><br />

And the controller's code with this:

   1:  [OutputCache(Duration = 3600, VaryByParam = "parameter", Location = OutputCacheLocation.Client)]
   2:  public ActionResult Index()
   3:  {
   4:      return View();
   5:  }

If you debug your website and you click on the link "test", you will have 2 cached versions : one with no parameter and one with "parameter=1". If you change the value of "parameter", you will have another cached version. This kind of functionality can be useful with query parameters (attention: choose the good time of caching according to your needs...). If you need to put more than one parameter, you can separate each parameters like this : VaryByParam = "parameter1;parameter2;parameter3"

When I was developing the homepage of a project (and the layout of the website), I encountered the following problem : I wanted to cache the homepage in the same way but there was the name of the current user in the top of the page (or nothing if there were not an authenticated user...).

You can see here a part of the top of the page:

   1:  @if (User.Identity.IsAuthenticated)
   2:  {
   3:      <li class="dropdown">
   4:          <a href="#" class="dropdown-toggle">@User.Identity.Name</a>
   5:          <ul class="dropdown-menu">
   6:              <li><a href="#">Account parameters</a></li>
   7:              <li><a href="@Url.Action("LogOff", "Account")">Log off</a></li>
   8:          </ul>
   9:      </li>
  10:  }
  11:  else
  12:  {
  13:      <li><a href="@Url.Action("Register", "Account")">Register</a></li>
  14:      <li><a href="@Url.Action("LogOn", "Account")">Log on</a></li>
  15:  }

If I test this code with a OutputCache attribute with a duration of one hour, I will get a bad result : imagine that I try to debug the website and the user is already authenticated... We will see his name on the top of the page and that is normal. Now I click on the logout link : the "LogOff" action will redirect me on the homepage and I will still see the name of the user on the top of the page. He is not authenticated but the homepage is in cache for one hour and I will get the same result with or without an authenticated user.

I could try a workaround with a parameter but I found a simpler and cleaner solution: the VaryByCustom parameter in OutputCache attribute.

Finally, here is the code of my controller :

   1:  [OutputCache(Duration = 3600, VaryByCustom="UserConnected", Location = OutputCacheLocation.Client)]
   2:  public ActionResult Index()
   3:  {
   4:      return View();
   5:  }



And the last thing that we need... Put the following code in Global.asax.cs:

   1:  public override string GetVaryByCustomString(HttpContext context, string arg) 
   2:  {
   3:      return arg.ToLower() == "userconnected" ? User.Identity.Name : string.Empty;
   4:  }

With this custom parameter for OutputCache attribute, we can have a cached page when there is no authenticated user and one cached page by User. It is perhaps not the solution to all your problems but it shows a nice utility of "VaryByCustom".

Note: this is just an example... If you need to cache different information depending on the user logged, I recommand to use the Donut Caching method.