In the world of .NET development, handling JSON serialization and deserialization is a common task, especially when dealing with web APIs, configuration files, and data interchange between systems. Two prominent libraries for JSON processing in the .NET ecosystem are Newtonsoft.Json (often referred to simply as Newtonsoft) and System.Text.Json. In this article, we'll compare and contrast these two libraries, exploring their features, examples, advantages, and disadvantages. Newtonsoft.Json Newtonsoft.Json, developed by James Newton-King, has been the go-to library for JSON serialization and deserialization in the .NET ecosystem for many years. It offers a wide range of features and has garnered widespread adoption among developers. Let's explore some of its characteristics: Features of Newtonsoft.Json Flexible and Robust: Newtonsoft.Json provides comprehensive support for JSON serialization and deserialization, handling complex object graphs, custom conversions, and nullable types effortlessly. Customization Options: Developers can customize the serialization and deserialization process using attributes, custom converters, and serialization settings, allowing fine-grained control over JSON representation. Widely Adopted: Newtonsoft.Json is battle-tested and widely adopted in the .NET community, with extensive documentation, tutorials, and community support available. using Newtonsoft.Json; // Serialization string json = JsonConvert.SerializeObject(myObject); // Deserialization MyObject obj = JsonConvert.DeserializeObject<MyObject>(json); System.Text.Json System.Text.Json, introduced in .NET Core 3.0 and later versions, is Microsoft's built-in JSON processing library, aiming to provide a modern, high-performance alternative to Newtonsoft.Json. While it may not offer the same level of features and flexibility as Newtonsoft.Json, it focuses on performance and seamless integration with the .NET ecosystem. Features of System.Text.Json Performance: System.Text.Json is optimized for performance, offering faster serialization and deserialization compared to Newtonsoft.Json in certain scenarios. Built-in Support: It seamlessly integrates with other .NET features such as async/await, streams, and memory management, making it a natural choice for .NET Core and .NET 5+ projects. Minimalistic API: System.Text.Json provides a minimalistic API surface, emphasizing simplicity and ease of use for common scenarios. using System.Text.Json; // Serialization string json = JsonSerializer.Serialize(myObject); // Deserialization MyObject obj = JsonSerializer.Deserialize<MyObject>(json); Advantages and Disadvantages Newtonsoft.Json Advantages Comprehensive feature set with extensive customization options. Widely adopted with a large community and ecosystem. Mature and battle-tested library. Disadvantages Performance may degrade for large datasets compared to System.Text.Json. Requires additional dependencies for .NET Core and .NET 5+ projects. System.Text.Json Advantages Optimized for performance, especially in scenarios with large datasets. Built-in support in .NET Core and .NET 5+, eliminating the need for additional dependencies. Seamless integration with other .NET features. Disadvantages Less feature-rich compared to Newtonsoft.Json, lacking some advanced customization options. Limited community support and fewer resources compared to Newtonsoft.Json. [Benchmark] public void NewtonsoftDeserializeIndividualData() { foreach (var user in serializedTestUsersList) { _ = Newtonsoft.Json.JsonConvert.DeserializeObject<User>(user); } } [Benchmark] public void MicrosoftDeserializeIndividualData() { foreach (var user in serializedTestUsersList) { _ = System.Text.Json.JsonSerializer.Deserialize<User>(user); } } Results: Data Method Count Mean Ratio Allocated Alloc Ratio Newtonsoft 10000 15.974 ms 1.00 35.5 MB 1.00 Microsoft 10000 8.472 ms 1.00 3.96 MB 1.0 Conclusion In the realm of JSON serialization and deserialization within the .NET landscape, our benchmarks present a compelling case. Despite claims of high performance from Newtonsoft.Json, the results unequivocally demonstrate that Microsoft’s System.Text.Json consistently outperforms its counterpart. Whether handling large or small datasets, System.Text.Json showcases superior speed and memory efficiency.
Before diving into optimization techniques, it’s important to identify the areas of your code that require improvement. By measuring and profiling your application’s performance, you can pinpoint the exact bottlenecks and focus your optimization efforts where they matter the most (Measure and Identify Bottlenecks). In this blog, I’ll explain effective strategies for handling memory and reducing garbage collection overhead in your C# applications. Memory management and garbage collection are essential aspects of performance tuning in C#, so these best practices will help you optimize your code for maximum efficiency. Here are 8 tips that will help with performance optimization. 1. Use the IDisposable interface : Utilizing the IDisposable interface is a crucial C# performance tip. It helps you properly manage unmanaged resources and ensures that your application’s memory usage is efficient. Bad way: public class ResourceHolder { private Stream _stream; public ResourceHolder(string filePath) { _stream = File.OpenRead(filePath); } // Missing: IDisposable implementation } Good way: public class ResourceHolder : IDisposable { private Stream _stream; public ResourceHolder(string filePath) { _stream = File.OpenRead(filePath); } public void Dispose() { _stream?.Dispose(); // Properly disposing the unmanaged resource. } } By implementing the IDisposable interface, you ensure that unmanaged resources will be released when no longer needed, preventing memory leaks and reducing pressure on the garbage collector. This is a fundamental code optimization technique in C# that developers should utilize. 2. Asynchronous Programming with async/await Asynchronous programming is a powerful technique for improving C# performance in I/O-bound operations, allowing you to enhance your app’s responsiveness and efficiency. Here, we’ll explore some best practices for async/await in C#. Limit the number of concurrent operations Bad way: public async Task ProcessManyItems(List<string> items) { var tasks = items.Select(async item => await ProcessItem(item)); await Task.WhenAll(tasks); } Good way: public async Task ProcessManyItems(List<string> items, int maxConcurrency = 10) { using (var semaphore = new SemaphoreSlim(maxConcurrency)) { var tasks = items.Select(async item => { await semaphore.WaitAsync(); // Limit concurrency by waiting for the semaphore. try { await ProcessItem(item); } finally { semaphore.Release(); // Release the semaphore to allow other operations. } }); await Task.WhenAll(tasks); } } Without limiting concurrency, many tasks will run simultaneously, which can lead to heavy load and degraded overall performance. Instead, use a SemaphoreSlim to control the number of concurrent operations. 3. UseConfigureAwait(false) when possible ConfigureAwait(false) is a valuable C# performance trick that can help prevent deadlocks in your async code and improve efficiency by not forcing continuations to run on the original synchronization context. public async Task<string> DataAsync() { var data = await ReadDataAsync().ConfigureAwait(false); // Use ConfigureAwait(false) to avoid potential deadlocks. return ProcessData(data); } 4. Parallel Computing and Task Parallel Library This will help the power of multicore processors and speed up CPU-bound operations Bad way: private void Data(List<int> data) { for (int i = 0; i < data.Count; i++) { PerformExpensiveOperation(data[i]); } } Good way: private void Data(List<int> data) { Parallel.ForEach(data, item => PerformExpensiveOperation(item)); } Parallel loops can considerably accelerate processing of large collections by distributing the workload among multiple CPU cores. Switch from regular for and foreach loops to their parallel counterparts whenever it’s feasible and safe. 5. Importance of Caching Data Utilizing in-memory caching can drastically reduce time-consuming database fetches and speed up your application. The good way demonstrates the use of in-memory caching to store product data and reduce time-consuming database fetches. 6. Optimizing LINQ Performance Force immediate execution using ToList() or ToArray() when needed. Use the AsParallel() extension method to ensure safety and parallelism. Selecting a HashSet instead of a List offers faster look-up times and greater performance 7. Task and ValueTask for reusing asynchronous code Use ValueTask to reduce heap allocations public async ValueTask<string> DataAsync() { var data = await ReadFromStreamAsync(_stream); return ProcessData(data); } By switching from Task<TResult> to ValueTask<TResult>, you can reduce heap allocations and ultimately improve your C# performance 8. Use HttpClientFactory to manage HttpClient instances private readonly HttpClient _httpClient; public MyClass(HttpClient httpClient) { _httpClient = httpClient; } public async Task GetDataAsync() { var response = await _httpClient.GetAsync("http://himashu.com/data"); } This approach manages the lifetimes of your HttpClient instances more efficiently, preventing socket exhaustion. - Use null-coalescing operators (??, ??=) string datInput = NullableString() ?? "default"; - Using Span and Memory for efficient buffer management // Using Span<T> avoids additional memory allocation and copying byte[] data = GetData(); Span<byte> dataSpan = data.AsSpan(); ProcessData(dataSpan); - Use StringComparison options for efficient string comparison bool equal = string.Equals(string1, string2, StringComparison.OrdinalIgnoreCase); - Use StringBuilder over string concatenation in loops StringBuilder sb = new StringBuilder(); for (int i = 0; i < 1000; i++) { sb.AppendFormat("Iteration: {0}", i); } string result = sb.ToString(); This has been a collection of just a few things I’ve found useful for enhancing the performance of my C# .NET code. Remember that the key to successful development is a balance between code quality and performance optimizations. By employing these techniques, you’ll be able to build high-performing C# applications that deliver a seamless user experience.
In this blog I'll show how you can use a CancellationToken in your ASP.NET Core action method to stop execution when a user cancels a request from their browser. This can be useful if you have long running requests that you don't want to continue using up resources when a user clicks "stop" or "refresh" in their browser. What is Cancellation Token in c#? Cancellation tokens in C# are used to signal that a task or operation should be cancelled. They allow for the cooperative cancellation of a task or operation, rather than aborting it forcibly. Why Use Cancellation Tokens? Here are some benefits of using cancellation tokens: Avoid resource leaks by freeing up un-managed resources linked to the task Stop further processing when a task is no longer needed Improve responsiveness by quickly responding to cancellations Easy propagation of cancel requests in child tasks Without cancellation logic, long-running tasks will continue processing in the background even if no longer needed. You can use cancellaiontoken in any action method or project. Here I am taking one example of .NET web API. Here, I have created a web API project in .NET, and the above image shows the default controller for the web API, which includes the WeatherForecastController. In that, I have added some log information and added one 10-second task delay that means when this line is executed it will wait for 10 seconds after the next line is executed. I have added task delay because it is better to understand CancellationToken. If we hit the URL /GetWeatherForecast then the request will run for 10s, and eventually will return the message. So now, what happens if the user refreshes the browser, halfway through the request? The browser never receives the response from the first request, but as you can see from the logs, the action method executes to completion twice - once for the first (canceled) request, and once for the second (refresh) request. Whether this is correct behavior will depend on your application. ASP.NET Core provides a mechanism for the webserver to signal when a request has been canceled using a CancellationToken. This is exposed as HttpContext.RequestAborted, but you can also inject it automatically into your actions using model binding. Using CancellationToken in your method CancellationTokens are lightweight objects that are created by a CancellationTokenSource. When a CancellationTokenSource is cancelled, it notifies all the consumers of the CancellationToken. This allows one central location to notify all of the code paths in your app that cancellation was requested. When cancelled, the IsCancellationRequested property of the cancellation token will be set to True, to indicate that the CancellationTokenSource has been cancelled. Lets consider the previous example again. We have a long-running action method . As it as an expensive method, we want to stop executing the action as soon as possible if the request is cancelled by the user. The following code shows how we can hook into the central CancellationTokenSource for the request, by injecting a CancellationToken into the action method, and passing the parameter to the Task.Delay call. MVC will automatically bind any CancellationToken parameters in an action method to the HttpContext.RequestAborted token, using the CancellationTokenModelBinder. This model binder is registered automatically when you call services.AddMvc() (or services.AddMvcCore()) in Startup.ConfigureServices(). With this small change, we can test out our scenario again. We'll make an initial request, which starts the long-running action, and then we'll reload the page. As you can see from the logs below, the first request never completes. Instead the Task.Delay call throws a TaskCancelledException when it detects that the CancellationToken.IsCancellationRequested property is true, immediately halting execution. Summary Users can cancel requests to your web app at any point, by hitting the stop or reload button on your browser. Typically, your app will continue to generate a response anyway, even though Kestrel won't send it to the user. If you have a long-running action method, then you may want to detect when a request is canceled, and stop execution. You can do this by injecting a CancellationToken into your action method, which will be automatically bound to the HttpContext.RequestAborted token for the request. You can check this token for cancellation as usual, and pass it to any asynchronous methods that support it. If the request is canceled, an OperationCanceledException or TaskCanceledException will be thrown.