Hello friends, today we will talk about a performance issue that does not only affect mobile apps but other types of Dotnet client applications too. That is, HTTP request performance. Making HTTP requests is something we should do cautiously because it consumes a lot of resources that are difficult to release later. This can impact the user experience negatively. In this article, we will go through a few things you can do, to improve HTTP Request Performance in Dotnet MAUI / Xamarin apps. Though most of it applies to any Dotnet app.

Want to know how to get country data (name, flag, code etc.) in your .NET MAUI apps with minimum code? check this out.

The Performance Issues

I have primarily experienced this issue in my Xamarin Apps. While monitoring my app’s crash and error reports, I always noticed weird Socket exceptions while making HTTP requests to the server. My users experienced these errors often. It wasn’t as bad as a permanent crash of the app, but this made some requests not go to completion thus impacting negatively the UX. These errors occurred even when my user’s internet connection was turned on and had a good signal strength. This error occured in the form of socket exceptions with messages similar to:

At first, I didn’t know the cause and a quick Google search suggested that I change the timeout of my HttpClient (This was a wrong idea). I increased the time out to about 10 minutes, but it didn’t help, because the source of the problem was somewhere else.

I also experienced a high consumption of memory by my apps. Though this is mostly due to heavy UI elements, or loading too many resources in the memory, poorly deserializing hundreds of HTTP request responses and HTTP request bodies impacted negatively memory consumption.

The Causes and Solutions to These Issues

After coming across the issues I mentioned above, I researched optimal ways to improve HTTP request performance in MAUI / Xamarin or any other dotnet app. Here are the causes and solutions I found and applied to improve my apps.

1- Do not Use Multiple HttpClients or an HttpClient Factory.

This might sound weird, but I assure you, you shouldn’t do that. Before starting the development of the Xamarin Forms apps I’m talking about in this article, I implemented the ASP Dotnet Core’s App builder pattern in the initial project template. This pattern is the one that inspired Dotnet MAUI’s actual app builder pattern. This made me add easily a dependency injection layer and more importantly, leverage Aspnet core’s HttpClient Factory. Initially, I thought this would be a great approach, since I’d have multiple Httpclients injected into my services and reused, without having to dispose of them. But it turned out to be a bad idea since I often had the System.Net.Sockets.SocketException I mentioned above.

It turns out that, having multiple HTTP clients causes multiple sockets to be opened, and it won’t be long till your app runs out of sockets. Causing SocketException due to socket exhaustion.

The Solution

Under the hood, HTTP clients use socket connections for web requests, and these sockets should be re-used. You should also note that HttpClients are thread-safe as mentioned in the documentation, and can be reused. So, the ideal approach would be to set a single HttpClient per server you send requests to or a single HttpClient instance for the lifetime of your application. I did just that, and I stopped having Socket Exhaustion Exceptions.

If I haven’t convinced you yet, take it from the Dotnet MAUI team, who improved the dotnet podcast MAUI app, by removing the user of the HttpClient Factory. You can find the details of this enhancement here.

Do not do this

Do this instead

2- Disposing HttpClients is not Enough

We saw above that having multiple HttpClients is not ideal. So now, what if you used multiple HttpClients but disposed of them systematically and immediately after usage? Like wrapping them inside a Using statement. This is not a good idea. It is kinda contradictory because most of the HttpClient usage examples available out there emphasize disposing of the client after usage. Also, the HttpClient is an IDisposable object, and the docs insist on disposing of objects with the Using statement. But the HttpClient is of a different species and should be treated differently. As highlighted by the experiment described in this article, though HttpClients are disposed of, sockets might still remain open in the background. Since operating systems take time to definitely close sockets and create new ones, your app will come across a socket exhaustion exception soon.

Do not do this, this is a simplistic approach to using HTTP clients that can quickly become harmful to your app.

The Solution

As mentioned in the previous point, HTTP clients should be reused. That is to set a single HttpClient per server you send requests to, throughout the lifetime of your application. I did just that, and I stopped having Socket Exhaustion Exceptions.

3- Avoid Modifying the Default HttpClientHandler of Your HttpClient.

This point is specific to mobile app development with Dotnet. By default, any HttpClient you create in your android or iOS application will have a native HttpClientHandler assigned to it. Taking this into consideration, you should avoid customizing HttpClientHandler for your client, since it will override the native ones. Using the default one should be ok,

The native HttpClientHandler is specific to each platform and leverages the native HTTP request APIs of Android and iOS. This is done in Xamarin Forms and shouldn’t have changed in Dotnet MAUI. The native handlers have several advantages that you should leverage.

On Android, the AndroidClientHandler delegates requests to the native java code. And on iOS, we have the NSUrlSessionHandler that leverages the NSUrlSession API introduced in iOS 7 and later. If you’re interested in diving deeper into this topic, check out this article.

4- Do Json Serialization Directly to Streams to Reduce Memory Consumption

When you check C# Json serialization and deserialization online, the examples you get will show you how to load the JSON into memory and then deserialize that JSON into C# objects later. Though it is easy to follow this path, you should avoid it because it consumes memory. What we want is to do is reduce memory consumption by allocating the least amount of memory thereby, reducing garbage collection. To do this, you need to stream the JSON deserialization process when you receive a response from the API.

I stole the examples below from the performance tips of NewtonSoft.Json found here. You can find more performance tips in the documentation above.

Don’t do this

Do this instead

Conclusion

The tips I shared above concern only Http Requests you make in your client apps. I implemented those, and I got a performance boost. Though they are useful, you shouldn’t neglect any performance aspect of your app. Xamarin.Forms is resource greedy, MAUI is far less greedy, but you shouldn’t let your guard down.

References

https://www.aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/

http://byterot.blogspot.com/2016/07/singleton-httpclient-dns.html

Xamarin.Forms Native HttpClientHandler for HttpClient…

https://docs.microsoft.com/en-us/dotnet/architecture/microservices/implement-resilient-applications/use-httpclientfactory-to-implement-resilient-http-requests

https://itnext.io/httpclient-may-kill-your-system-be-careful-62b1533ad456

https://docs.microsoft.com/en-us/dotnet/api/system.net.http.httpclient?view=net-6.0 

Follow me on social media and stay updated
%d