AWS Developer Tools Blog

Preview 1 of AWS SDK for .NET V4

In February 2024, AWS SDK for .NET team announced changes to the minimum .NET target versions the AWS SDK for .NET will support. The major changes announced were ending support for .NET Framework 3.5 and changing the minimum .NET Framework to 4.6.2. In June we revised the blog post with the .NET Framework minimum set to 4.7.2.

As part of the .NET target changes, we are making modernization changes to the SDK, resolving technical debt, and addressing customer feedback that requires some breaking changes. These changes result in the creation of a new major version of the SDK. The current V3 version of the SDK was released in 2015 making V4 the first major version of the SDK in 9 years.

V4 is an evolutionary change to the SDK. The programming model hasn’t changed and .NET applications using the AWS SDK will require little to no code changes when upgrading to V4.

Today, we have released preview 1 of V4 and we encourage .NET developers to try out the new package versions. We would love to hear feedback on the changes we have made as well as the challenges you experience when upgrading to V4.

Performance

With the changes made to the SDK for V4 so far we are seeing performance improvements with the SDK. Starting with size, the AWSSDK.Core assembly shrank from 2MB in V3 to about 900 KB in V4 preview. A major cause of the reduction was the removal a large JSON file that was embedded in AWSSDK.Core for defining the endpoints of services. The endpoint JSON file had to be parsed during startup, causing large amounts of memory allocations and delays for the initial requests.

AWS Lambda is an environment that is sensitive to startup costs. The following Lambda function runs an Amazon DynamoDB query to list the US postal zip codes for a state. With V4, we observe a 12% cold start performance boost with 512 MB of memory, and 15% when using 256 MB of memory.


public async Task<List<string>> FunctionHandler(string state, ILambdaContext context)
{
    var response = await _ddbClient.QueryAsync(new QueryRequest
    {
        TableName = "ZipCodes",
        IndexName = "State-index",
        KeyConditionExpression = "#S = :s",
        ExpressionAttributeValues = new Dictionary<string, AttributeValue>
        {
            { ":s", new AttributeValue{S=state} }
        },
        ExpressionAttributeNames = new Dictionary<string, string>
        {
            {"#S", "State"}
        }
    });

    var codes = new List<string>();
    foreach(var item in response.Items)
    {
        codes.Add(item["Code"].S);
    }

    return codes;
}

(Side note, this function is an example of how code targeting V3 or V4 doesn’t necessary require changes.)

To test out the memory allocation differences between V3 and V4 the same code from the Lambda function querying the US postal zip codes for the state of Washington was used. The response from DynamoDB is a 100 KB JSON document that the SDK has to parse and turn into .NET objects that client applications will interact with. Running the code using both V3 and V4 with BenchmarkDotNet to measure memory allocations, we see that V3 is using 2.4 MB allocations and V4 is using 1.3 MB allocations. By reducing memory allocations, the scale of requests that can be handled within a process can increase before hitting memory limits.

Improvements to AWSSDK.Extensions.NETCore.Setup

The NuGet package AWSSDK.Extensions.NETCore.Setup is a popular library for integrating the AWS SDK into .NET’s configuration and dependency injection framework. As part of .NET 8’s release, the AWS SDK was updated to add Native AOT support with the exception of a few areas of the SDK. AWSSDK.Extensions.NETCore.Setup was one of those exceptions due to high use of reflection. As part of V4, this package has been updated to be Native AOT compatible.

We have also made it easier to edit the configuration of the library in the appsettings.json file by enabling intellisense. For example:

Breaking Changes

In the SDK’s repository, we have created a pinned GitHub issue for tracking the development of V4. The issue contains the breaking changes made to the SDK for V4. Most of these changes require few changes in code that is using the SDK. The changes listed below are the changes most likely to require updates in existing applications using the AWS SDK.

Nullable value types

V4 changes properties on classes used for requests and responses that used value types like int, bool, and DateTime to use the nullable version, essentially changing the type from bool to bool?. This addresses a long standing issue many users had with the SDK in that they could not tell, for example, if a boolean property is false because the service returned false, or if the property is false because that is the default value for bool types.

Because .NET’s handles implicit conversation between value types and nullable value types, many applications will require no changes other then recompilation. In cases, where the implicit conversation doesn’t handle the change, the .NET compiler will return a compilation error. You will need to update your code to call the Value property or the GetValueOrDefault method.

Collections null by default

In V3, properties of type List or Dictionary for requests and responses types were initialized to an empty collection. When making requests, the SDK would only send the property if the collection was not empty. This was done to avoid null pointer exceptions in code using the SDK but it has the following drawbacks:

  • The SDK couldn’t always understand the user’s intent, especially when attempting to clear out a collection on an AWS resource.
  • When getting a response back from a service, users couldn’t tell if the empty collection was due to the default initialization of the SDK or if the service actual sent back an empty collection.
  • Collections were being created that were not even being used, which caused wasted allocations.

Let’s dive deeper into the last point on allocations. The AttributeValue is the type representing each attribute for each item being returned in a DynamoDB query. AttributeValue has separate properties for each possible data type that DynamoDB supports. There are five collection properties on AttributeValue covering all the possible DynamoDB collection types.

In the DynamoDB query example used previous, there are 6 attributes for each item, and about 700 US postal zip codes were returned for the state of Washington. Our math for this scenario is:

(5 collection types) * (6 attributes per item) * (700 items) = 21,000 collections.

That results in 21,000 collections created in V3 made for each query in this example that are not used. This is wasted allocations that have to be cleaned up by the .NET garbage collector, which uses CPU and memory that could be used for processing more requests.

To address this issue, V4 will no longer by default initialize collections to an empty collection. When using V4, you will need to initialize the collections when making requests. For a lot of code using the .NET SDK, this is already being done as part of constructing the type with an object initializer like the Lambda function code shown above. Collections properties in responses will need to be checked whether they are null to avoid null pointer exceptions.

This change is likely the most impactful change to existing code using the SDK due to it being a runtime change. To alleviate concerns and allow users of the SDK to upgrade to V4 even if they are unsure whether they will be affected by this change, we created the Amazon.AWSConfigs.InitializeCollections property. If you set this property to true you can revert to the collection initialization behavior of V3. The Amazon.AWSConfigs.InitializeCollections property was also recently added to V3 with the default value true. This allows V3 users to set the property to false and try out this new collections behavior before upgrading to V4.

Conclusion

I want to call out community members Daniel Marbach and Steven Weerdenburg who have been monitoring our V4 work and contributed performance PRs to the effort.

V4 won’t be released at the same cadence as V3 until we get closer to GA. There will be some period of dual support of V3 and V4 once V4 reaches GA based on how we see the adoption of V4. Our hope is that the upgrade from V3 to V4 is easy enough for users to quickly do so that we can focus on more improvements to V4.

We ask AWS users of the .NET SDK to try out the preview of V4 and let us know what you think. You can monitor the progress by following the pinned GitHub issue on our repository. Please provide feedback by opening issues and discussions on the AWS SDK for .NET’s repository.

Norm Johanson

Norm Johanson

Norm Johanson has been a software developer for more than 25 years developing all types of applications. Since 2010 he has been working for AWS focusing on the .NET developer experience at AWS. You can find him on Twitter @socketnorm and GitHub @normj.