DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Last call! Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • Developing Minimal APIs Quickly With Open Source ASP.NET Core
  • Revolutionizing Content Management
  • Revolutionizing API Development: A Journey Through Clean Architecture With Adapter Pattern in ASP.NET Core
  • Building a Microservices API Gateway With YARP in ASP.NET Core Web API

Trending

  • Revolutionizing Financial Monitoring: Building a Team Dashboard With OpenObserve
  • Intro to RAG: Foundations of Retrieval Augmented Generation, Part 1
  • It’s Not About Control — It’s About Collaboration Between Architecture and Security
  • How the Go Runtime Preempts Goroutines for Efficient Concurrency
  1. DZone
  2. Software Design and Architecture
  3. Performance
  4. How to Enhance the Performance of .NET Core Applications for Large Responses

How to Enhance the Performance of .NET Core Applications for Large Responses

Does your .NET Core 3+ API use Newtonsoft.Json and struggle with performance due to large payloads? Explore solutions in this article.

By 
Rishi Mohan user avatar
Rishi Mohan
·
Oct. 29, 24 · Analysis
Likes (2)
Comment
Save
Tweet
Share
5.3K Views

Join the DZone community and get the full member experience.

Join For Free

Problem Statement

Our API/application uses the Newtonsoft.Json serializer on .NET Core 3 or above, and our response payloads are larger in size. How do we use the .NET code properties and settings to improve API performance?

Possible Case Where You Could Have Started Facing the Performance Issue

This issue could have started when you upgraded your API to .NET Core 3.0 or above with the Newtonsoft.Json serializer, or when you created your API with .NET Core 3 or above and using the Newtonsoft.Json serializer.

You would have started noticing the two behaviors below that were not there before and are performance hits for larger payloads greater than 32KB:

  1. I/O API operations on disk which results in temp data files in a temp directory
  2. Impact on the application performance matrix

API response time matters for all domains and applications, but if you are in the financial, trading, payment, banking, etc. domains, a small delay introduced is not acceptable.

So, What We Can Do if We Start Facing the Above Issue?

  1. With a standard developer mindset, we start by looking at the code, run code optimization analysis, and optimize loops. This is fine, and it helps, too, but if the application was already in better shape, then it would not help much.
  2. Deep dive into the .NET Core and identify why hops to disk got introduced and how we can avoid it and its impact. I have done this for you and am sharing the below analysis which I think would be helpful for you, too.

Analysis

I will discuss the analysis done and the outcome by digging into the .NET Core internals in detail. You can research it further in case you want to do it by yourself with fare ideas after this article.

If You Are Using .NET Core 3 or Above

1. Migrate to System.Text.Json

If you don't have any custom handling with Newtonsoft.Json, are not majorly dependent on it, and don't mind removing the dependency, then this is your best option. Just move to the new System.Text.Json. It is by default included in the runtime for .NET Core 3.1 and later, so you don't have to import any package to your application.

  • It is async-friendly, which means it will directly write to the response stream, without any intermediary buffer or I/O operations.  
  • No temp file creation
  • If you have to make some tweaks or adjustments to move to System.Text.Json, those are easy to implement by using custom converters. For a detailed reference, use "Migrate from Newtonsoft.Json to System.Text.Json." It has detailed information about the differences between the two and explains migration.

But if your API is well established, and you see it would require a bigger effort to migrate to System.Text.json and you can't afford the time and effort yet, then below are your options. 

2. Set SuppressOutputFormatterBuffering = true and AllowSynchrounousIO = false

By setting SuppressOutputFormatterBuffering = true and AllowSynchrounousIO  = false, you would avoid I/O operations for your API calls and no temp file generation from response buffering.

Before 3.0, the Newtonsoft.Json serializer was by default used to read and write (HttpRequestBody, HttpResponseBody) synchronously to/from the output stream.  This was perfectly fine with the smaller payloads — but with bigger or larger payloads, thread starvation was an issue. To avoid the thread starvation situation, the .NET Core 3.0 framework introduced asynchronous Input/Output (I/O) API operations as default behaviors. 

With .NET Core 3.0 and above, synchronous operations are disabled by default (see "ASP.NET 3.0 Core breaking changes"). The code below is the default setting of the AllowSynchrounousIO Kestrel property. However, this can be overridden by setting its value to true, which will allow the Synchronous I/O operations.

C#
 
services.Configure<KestrelServerOption>(options => {
	options.AllowSynchronousIO = false;
});


However, just setting the AllowSynchrounousIO = true wouldn't be enough because before serializing the response payload, there is an output formatter (NewtonsoftJsonOutputFormatter) that creates the HTTP response body. It is also an asynchronous operation by default and a reason behind the buffering of response to the disc. 

Once again, we get an option to suppress the OutputFormatterBuffering. It can be overridden by setting the SuppressOutputFormatterBuffering to true (default is false) as shown below.

C#
 
services.AddControllers(options =>
	options.SuppressOutputFormatterBuffering = true;
);


2. If You Are Using .NET Core 6 or Above

If you are using .NET Core 6 or above, and you know the maximum limit of your response size, then you get an option to set the threshold (maximum size of response) before starting the buffering to disk when SuppressOutputFormatterBuffering is not set.  

You can set OutputFormatterMemoryBufferThreshold to any int value in KB according to your need as shown below (default is 30KB).

C#
 
Configure<MvcNewtonsoftJsonOptions>(  o => { 
    o.OutputFormatterMemoryBufferThreshold = 100; 
}).BuildServiceProvider();


Analysis Conclusion

If the payload is more than 32KB, .NET Core 3.0 or above will by default start buffering the response to disk, and once buffered, it will serialize and send it to the client. This buffering would save the thread starvation, but as I said earlier, increases the I/O operations extensively and will impact the performance. 

You have 3 options based on case to case according to the size of the response payload. The first one is the best approach because it comes with the .NET Core inbuilt. The other two are the workarounds provided by the framework. Whatever case you choose, you will feel better with the improved performance.

It was really great to get into the investigation, and it feels good when you learn something new by digging into the ASP.NET Core and extending your learning a bit more.

I think for any future projects, just simply choose System.Text.Json — moving to it from Newtonsoft would not be easy because there are many differences between them.

API ASP.NET ASP.NET Core application Payload (computing) Performance

Opinions expressed by DZone contributors are their own.

Related

  • Developing Minimal APIs Quickly With Open Source ASP.NET Core
  • Revolutionizing Content Management
  • Revolutionizing API Development: A Journey Through Clean Architecture With Adapter Pattern in ASP.NET Core
  • Building a Microservices API Gateway With YARP in ASP.NET Core Web API

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!