Home > Uncategorized > 🚫 Why AWS SDK for S3 No Longer Works Smoothly with .NET Framework 4.8 β€” and How to Fix It

🚫 Why AWS SDK for S3 No Longer Works Smoothly with .NET Framework 4.8 β€” and How to Fix It

In 2024, more .NET developers are finding themselves in a strange situation: suddenly, tried-and-tested .NET Framework 4.8 applications that interact with Amazon S3 start throwing cryptic build errors or runtime exceptions. The culprit? The AWS SDK for .NET has increasingly shifted toward support for .NET Core / .NET 6+, and full compatibility with .NET Framework is eroding.

In this post, we’ll explain:

  • Why this happens
  • What errors you might see
  • And how to remove the AWS SDK altogether and replace it with pure .NET 4.8-compatible code for downloading (and uploading) files from S3 using Signature Version 4.

🧨 The Problem: AWS SDK & .NET Framework 4.8

The AWS SDK for .NET (like AWSSDK.S3) now depends on modern libraries like:

  • System.Text.Json
  • System.Buffers
  • System.Runtime.CompilerServices.Unsafe
  • Microsoft.Bcl.AsyncInterfaces

These dependencies were designed for .NET Core and later versions β€” not .NET Framework. While it was once possible to work around this with binding redirects and careful version pinning, the situation has become unstable and error-prone.


❗ Common Symptoms

You may see errors like:

Could not load file or assembly ‘System.Text.Json, Version=6.0.0.11’

Or:

Could not load file or assembly ‘System.Buffers, Version=4.0.5.0’

Or during build:

Warning: Unable to update auto-refresh reference ‘system.text.json.dll’

Even if you install the correct packages, you may end up needing to fight bindingRedirect hell, and still not get a working application.


βœ… The Solution: Remove the AWS SDK

Fortunately, you don’t need the SDK to use S3. All AWS S3 requires is a properly signed HTTP request using AWS Signature Version 4, and you can create that yourself using standard .NET 4.8 libraries.


πŸ” Downloading from S3 Without the AWS SDK

Here’s how you can download a file from S3 using HttpWebRequest and Signature Version 4.

βœ”οΈ The Key Points:

  • You must include the x-amz-content-sha256 header (even for GETs!)
  • You sign the request using your AWS secret key
  • No external packages required β€” works on plain .NET 4.8

🧩 Code Snippet


public static byte[] DownloadFromS3(string bucketName, string objectKey, string region, string accessKey, string secretKey)
{
var method = "GET";
var service = "s3";
var host = $"{bucketName}.s3.{region}.amazonaws.com";
var uri = $"https://{host}/{objectKey}";
var requestDate = DateTime.UtcNow;
var amzDate = requestDate.ToString("yyyyMMddTHHmmssZ");
var dateStamp = requestDate.ToString("yyyyMMdd");
var canonicalUri = "/" + objectKey;
var signedHeaders = "host;x-amz-content-sha256;x-amz-date";
var payloadHash = HashSHA256(string.Empty); // Required even for GET

var canonicalRequest = $"{method}\n{canonicalUri}\n\nhost:{host}\nx-amz-content-sha256:{payloadHash}\nx-amz-date:{amzDate}\n\n{signedHeaders}\n{payloadHash}";
var credentialScope = $"{dateStamp}/{region}/{service}/aws4_request";
var stringToSign = $"AWS4-HMAC-SHA256\n{amzDate}\n{credentialScope}\n{HashSHA256(canonicalRequest)}";

var signingKey = GetSignatureKey(secretKey, dateStamp, region, service);
var signature = ToHexString(HmacSHA256(signingKey, stringToSign));

var authorizationHeader = $"AWS4-HMAC-SHA256 Credential={accessKey}/{credentialScope}, SignedHeaders={signedHeaders}, Signature={signature}";

var request = (HttpWebRequest)WebRequest.Create(uri);
request.Method = method;
request.Headers["Authorization"] = authorizationHeader;
request.Headers["x-amz-date"] = amzDate;
request.Headers["x-amz-content-sha256"] = payloadHash;

try
{
    using (var response = (HttpWebResponse)request.GetResponse())
    using (var responseStream = response.GetResponseStream())
    using (var memoryStream = new MemoryStream())
    {
        responseStream.CopyTo(memoryStream);
        return memoryStream.ToArray();
    }
}
catch (WebException ex)
{
    using (var errorResponse = (HttpWebResponse)ex.Response)
    using (var reader = new StreamReader(errorResponse.GetResponseStream()))
    {
        var errorText = reader.ReadToEnd();
        throw new Exception($"S3 request failed: {errorText}", ex);
    }
}

}
πŸ”§ Supporting Methods


private static string HashSHA256(string text)
{
using (var sha256 = SHA256.Create())
{
return ToHexString(sha256.ComputeHash(Encoding.UTF8.GetBytes(text)));
}
}
private static byte[] HmacSHA256(byte[] key, string data)
{
using (var hmac = new HMACSHA256(key))
{
return hmac.ComputeHash(Encoding.UTF8.GetBytes(data));
}
}
private static byte[] GetSignatureKey(string secretKey, string dateStamp, string region, string service)
{
var kSecret = Encoding.UTF8.GetBytes("AWS4" + secretKey);
var kDate = HmacSHA256(kSecret, dateStamp);
var kRegion = HmacSHA256(kDate, region);
var kService = HmacSHA256(kRegion, service);
return HmacSHA256(kService, "aws4_request");
}
private static string ToHexString(byte[] bytes)
{
return BitConverter.ToString(bytes).Replace("-", "").ToLowerInvariant();
}


πŸ“ Uploading to S3 Without the AWS SDK
You can extend the same technique for PUT requests. The only differences are:

You calculate the SHA-256 hash of the file content

You include a Content-Type and Content-Length header

You use PUT instead of GET

Let me know in the comments if you’d like the full upload version β€” it follows the same Signature V4 pattern.

βœ… Summary
Feature AWS SDK for .NET Manual Signature V4
.NET Framework 4.8 support ❌ Increasingly broken βœ… Fully supported
Heavy NuGet dependencies βœ… ❌ Minimal
Simple download/upload βœ… βœ… (with more code)
Presigned URLs βœ… 🟑 Manual support

Final Thoughts
If you’re stuck on .NET Framework 4.8 and running into weird AWS SDK issues β€” you’re not alone. But you’re not stuck either. Dropping the SDK and using HTTP + Signature V4 is entirely viable, especially for simple tasks like uploading/downloading S3 files.

Let me know if you’d like a full upload example, presigned URL generator, or if you’re considering migrating to .NET 6+.

  1. No comments yet.
  1. No trackbacks yet.

Leave a comment