From 57976d31779490134ae16ec9a3b5efa961404dd3 Mon Sep 17 00:00:00 2001 From: Mateusz Noga-Wojtania Date: Tue, 16 Jun 2026 10:23:25 +0200 Subject: [PATCH 1/4] potential fix the problem --- Frends.AmazonS3.ListObjects/CHANGELOG.md | 6 ++++++ .../Definitions/BucketObject.cs | 2 +- .../Frends.AmazonS3.ListObjects.csproj | 8 ++++---- .../ListObjects.cs | 20 ++++++++++++++++--- 4 files changed, 28 insertions(+), 8 deletions(-) diff --git a/Frends.AmazonS3.ListObjects/CHANGELOG.md b/Frends.AmazonS3.ListObjects/CHANGELOG.md index 0d6a71a..96af826 100644 --- a/Frends.AmazonS3.ListObjects/CHANGELOG.md +++ b/Frends.AmazonS3.ListObjects/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## [2.2.0] - 2026-06-16 +### Changed +- Updated AWSSDK.Core nuget package from 4.0.3.5 to 4.0.8 +- Updated AWSSDK.S3 nuget package from 4.0.14.2 to 4.0.24.1 +- Introduce more null checks to avoid unexpected exceptions + ## [2.1.0] - 2025-12-29 ### Changed - Updated AWS SDK version. diff --git a/Frends.AmazonS3.ListObjects/Frends.AmazonS3.ListObjects/Definitions/BucketObject.cs b/Frends.AmazonS3.ListObjects/Frends.AmazonS3.ListObjects/Definitions/BucketObject.cs index 3e8982b..e4288e6 100644 --- a/Frends.AmazonS3.ListObjects/Frends.AmazonS3.ListObjects/Definitions/BucketObject.cs +++ b/Frends.AmazonS3.ListObjects/Frends.AmazonS3.ListObjects/Definitions/BucketObject.cs @@ -35,7 +35,7 @@ public class BucketObject /// The date and time the object was last modified. /// /// 2022-04-22T00:16:40+02:00 - public DateTime LastModified { get; set; } + public DateTime? LastModified { get; set; } } } diff --git a/Frends.AmazonS3.ListObjects/Frends.AmazonS3.ListObjects/Frends.AmazonS3.ListObjects.csproj b/Frends.AmazonS3.ListObjects/Frends.AmazonS3.ListObjects/Frends.AmazonS3.ListObjects.csproj index d85600e..e4c6396 100644 --- a/Frends.AmazonS3.ListObjects/Frends.AmazonS3.ListObjects/Frends.AmazonS3.ListObjects.csproj +++ b/Frends.AmazonS3.ListObjects/Frends.AmazonS3.ListObjects/Frends.AmazonS3.ListObjects.csproj @@ -2,7 +2,7 @@ net8.0 - 2.1.0 + 2.2.0 Frends Frends Frends @@ -20,12 +20,12 @@ - - + + - \ No newline at end of file + diff --git a/Frends.AmazonS3.ListObjects/Frends.AmazonS3.ListObjects/ListObjects.cs b/Frends.AmazonS3.ListObjects/Frends.AmazonS3.ListObjects/ListObjects.cs index fd69e99..01f02bb 100644 --- a/Frends.AmazonS3.ListObjects/Frends.AmazonS3.ListObjects/ListObjects.cs +++ b/Frends.AmazonS3.ListObjects/Frends.AmazonS3.ListObjects/ListObjects.cs @@ -14,7 +14,7 @@ namespace Frends.AmazonS3.ListObjects /// /// Amazon S3 task. /// - public class AmazonS3 + public static class AmazonS3 { /// /// Lists objects from specified AWS S3 Bucket. @@ -33,6 +33,10 @@ public static async Task ListObjects([PropertyTab] Connection connection { return ErrorHandler.HandleCredentialsError("AWS credentials missing.", options); } + if (string.IsNullOrWhiteSpace(input.BucketName)) + { + return ErrorHandler.HandleCredentialsError("Bucket name is missing.", options); + } var region = RegionSelection(connection.Region); var client = new AmazonS3Client(connection.AwsAccessKeyId, connection.AwsSecretAccessKey, region); @@ -61,6 +65,15 @@ private static async Task> ListBucketContentsAsync(AmazonS3Cl do { var response = await client.ListObjectsV2Async(request, cancellationToken); + if(response is null ) throw new Exception("Received null response from S3 ListObjectsV2Async call."); + if(response.HttpStatusCode != System.Net.HttpStatusCode.OK) + { + throw new Exception($"Error listing objects: {response.HttpStatusCode}"); + } + if(response.S3Objects is null) + { + throw new Exception("S3Objects property was null in S3 ListObjectsV2Async response."); + } foreach (var item in response.S3Objects) { @@ -69,12 +82,13 @@ private static async Task> ListBucketContentsAsync(AmazonS3Cl { BucketName = item.BucketName, Key = item.Key, - Size = (long)item.Size, + Size = item.Size ?? 0, Etag = item.ETag, - LastModified = (DateTime)item.LastModified + LastModified = item.LastModified, }); } + if (response.IsTruncated is null) throw new Exception("IsTruncated flag was not set in S3 ListObjectsV2Async response."); if ((bool)response.IsTruncated) request.ContinuationToken = response.NextContinuationToken; else From a2e18423156a55110266a1d030880b48170e8472 Mon Sep 17 00:00:00 2001 From: Mateusz Noga-Wojtania Date: Thu, 18 Jun 2026 02:21:21 +0200 Subject: [PATCH 2/4] linter fix + exclude from coverage untestable code --- .../ListObjects.cs | 30 +++++++++++++------ 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/Frends.AmazonS3.ListObjects/Frends.AmazonS3.ListObjects/ListObjects.cs b/Frends.AmazonS3.ListObjects/Frends.AmazonS3.ListObjects/ListObjects.cs index 01f02bb..c891a7d 100644 --- a/Frends.AmazonS3.ListObjects/Frends.AmazonS3.ListObjects/ListObjects.cs +++ b/Frends.AmazonS3.ListObjects/Frends.AmazonS3.ListObjects/ListObjects.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.ComponentModel; +using System.Diagnostics.CodeAnalysis; using System.Threading; using System.Threading.Tasks; using Amazon; @@ -25,14 +26,17 @@ public static class AmazonS3 /// Options for the task /// Token to stop ListObjects. This is generated by Frends. /// Result { List (BucketObject) Objects, bool Success, Error Error } where BucketObject contains { string BucketName, string Key, string Etag, long Size, DateTime LastModified } - public static async Task ListObjects([PropertyTab] Connection connection, [PropertyTab] Input input, [PropertyTab] Options options, CancellationToken cancellationToken) + public static async Task ListObjects([PropertyTab] Connection connection, [PropertyTab] Input input, + [PropertyTab] Options options, CancellationToken cancellationToken) { try { - if (string.IsNullOrWhiteSpace(connection.AwsSecretAccessKey) || string.IsNullOrWhiteSpace(connection.AwsAccessKeyId)) + if (string.IsNullOrWhiteSpace(connection.AwsSecretAccessKey) || + string.IsNullOrWhiteSpace(connection.AwsAccessKeyId)) { return ErrorHandler.HandleCredentialsError("AWS credentials missing.", options); } + if (string.IsNullOrWhiteSpace(input.BucketName)) { return ErrorHandler.HandleCredentialsError("Bucket name is missing.", options); @@ -41,6 +45,7 @@ public static async Task ListObjects([PropertyTab] Connection connection var region = RegionSelection(connection.Region); var client = new AmazonS3Client(connection.AwsAccessKeyId, connection.AwsSecretAccessKey, region); var response = await ListBucketContentsAsync(client, input, options, cancellationToken); + return new Result(response); } catch (Exception ex) @@ -57,7 +62,8 @@ public static async Task ListObjects([PropertyTab] Connection connection /// Options for filtering and limiting results /// Token to cancel the operation /// A list of BucketObject instances representing the objects in the bucket - private static async Task> ListBucketContentsAsync(AmazonS3Client client, Input input, Options options, CancellationToken cancellationToken) + private static async Task> ListBucketContentsAsync(AmazonS3Client client, Input input, + Options options, CancellationToken cancellationToken) { var data = new List(); var request = GetListObjectsV2Request(input, options); @@ -65,12 +71,16 @@ private static async Task> ListBucketContentsAsync(AmazonS3Cl do { var response = await client.ListObjectsV2Async(request, cancellationToken); - if(response is null ) throw new Exception("Received null response from S3 ListObjectsV2Async call."); - if(response.HttpStatusCode != System.Net.HttpStatusCode.OK) + + if (response is null) + throw new Exception("Received null response from S3 ListObjectsV2Async call."); + + if (response.HttpStatusCode != System.Net.HttpStatusCode.OK) { throw new Exception($"Error listing objects: {response.HttpStatusCode}"); } - if(response.S3Objects is null) + + if (response.S3Objects is null) { throw new Exception("S3Objects property was null in S3 ListObjectsV2Async response."); } @@ -88,13 +98,14 @@ private static async Task> ListBucketContentsAsync(AmazonS3Cl }); } - if (response.IsTruncated is null) throw new Exception("IsTruncated flag was not set in S3 ListObjectsV2Async response."); + if (response.IsTruncated is null) + throw new Exception("IsTruncated flag was not set in S3 ListObjectsV2Async response."); + if ((bool)response.IsTruncated) request.ContinuationToken = response.NextContinuationToken; else break; - } - while (true); + } while (true); return data; } @@ -126,6 +137,7 @@ private static ListObjectsV2Request GetListObjectsV2Request(Input input, Options /// /// The region enum value to convert /// The corresponding AWS RegionEndpoint instance + [ExcludeFromCodeCoverage] private static RegionEndpoint RegionSelection(Region region) { switch (region) From 97ead4f876cd6e531ed4be8862384ddf377d9d96 Mon Sep 17 00:00:00 2001 From: Mateusz Noga-Wojtania Date: Thu, 18 Jun 2026 02:28:59 +0200 Subject: [PATCH 3/4] dummy commit --- .../Frends.AmazonS3.ListObjects.Test/UnitTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Frends.AmazonS3.ListObjects/Frends.AmazonS3.ListObjects.Test/UnitTests.cs b/Frends.AmazonS3.ListObjects/Frends.AmazonS3.ListObjects.Test/UnitTests.cs index 59ea646..07c5c10 100644 --- a/Frends.AmazonS3.ListObjects/Frends.AmazonS3.ListObjects.Test/UnitTests.cs +++ b/Frends.AmazonS3.ListObjects/Frends.AmazonS3.ListObjects.Test/UnitTests.cs @@ -33,7 +33,7 @@ public class ListObjectsTest Connection? _connection = null; Input? _input = null; - Options? _options = null; + Options? _options; public ListObjectsTest() { From b8267de566ee510ae43e907ba1f1873f92b1eef9 Mon Sep 17 00:00:00 2001 From: Mateusz Noga-Wojtania Date: Thu, 18 Jun 2026 02:40:21 +0200 Subject: [PATCH 4/4] fix tests in other proj --- .../ErrorHandlerTest.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Frends.AmazonS3.ListObjectVersions/Frends.AmazonS3.ListObjectVersions.Tests/ErrorHandlerTest.cs b/Frends.AmazonS3.ListObjectVersions/Frends.AmazonS3.ListObjectVersions.Tests/ErrorHandlerTest.cs index 83bade2..0b68d08 100644 --- a/Frends.AmazonS3.ListObjectVersions/Frends.AmazonS3.ListObjectVersions.Tests/ErrorHandlerTest.cs +++ b/Frends.AmazonS3.ListObjectVersions/Frends.AmazonS3.ListObjectVersions.Tests/ErrorHandlerTest.cs @@ -13,8 +13,8 @@ public class ErrorHandlerTest : TestBase [Test] public void Should_Throw_Error_When_ThrowErrorOnFailure_Is_True() { - var ex = Assert.ThrowsAsync(() => - AmazonS3.ListObjectVersions(DefaultInput(), DefaultConnection(), DefaultOptions(), CancellationToken.None)); + var ex = Assert.ThrowsAsync((Func)(() => + AmazonS3.ListObjectVersions(DefaultInput(), DefaultConnection(), DefaultOptions(), CancellationToken.None))); Assert.That(ex, Is.Not.Null); } @@ -33,8 +33,8 @@ public void Should_Use_Custom_ErrorMessageOnFailure() { var options = DefaultOptions(); options.ErrorMessageOnFailure = CustomErrorMessage; - var ex = Assert.ThrowsAsync(() => - AmazonS3.ListObjectVersions(DefaultInput(), DefaultConnection(), options, CancellationToken.None)); + var ex = Assert.ThrowsAsync((Func)(() => + AmazonS3.ListObjectVersions(DefaultInput(), DefaultConnection(), options, CancellationToken.None))); Assert.That(ex, Is.Not.Null); Assert.That(ex.Message, Contains.Substring(CustomErrorMessage)); }