Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ public class ErrorHandlerTest : TestBase
[Test]
public void Should_Throw_Error_When_ThrowErrorOnFailure_Is_True()
{
var ex = Assert.ThrowsAsync<Exception>(() =>
AmazonS3.ListObjectVersions(DefaultInput(), DefaultConnection(), DefaultOptions(), CancellationToken.None));
var ex = Assert.ThrowsAsync<Exception>((Func<Task>)(() =>
AmazonS3.ListObjectVersions(DefaultInput(), DefaultConnection(), DefaultOptions(), CancellationToken.None)));
Assert.That(ex, Is.Not.Null);
}

Expand All @@ -33,8 +33,8 @@ public void Should_Use_Custom_ErrorMessageOnFailure()
{
var options = DefaultOptions();
options.ErrorMessageOnFailure = CustomErrorMessage;
var ex = Assert.ThrowsAsync<Exception>(() =>
AmazonS3.ListObjectVersions(DefaultInput(), DefaultConnection(), options, CancellationToken.None));
var ex = Assert.ThrowsAsync<Exception>((Func<Task>)(() =>
AmazonS3.ListObjectVersions(DefaultInput(), DefaultConnection(), options, CancellationToken.None)));
Assert.That(ex, Is.Not.Null);
Assert.That(ex.Message, Contains.Substring(CustomErrorMessage));
}
Expand Down
6 changes: 6 additions & 0 deletions Frends.AmazonS3.ListObjects/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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

Comment thread
MichalFrends1 marked this conversation as resolved.
## [2.1.0] - 2025-12-29
### Changed
- Updated AWS SDK version.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public class ListObjectsTest

Connection? _connection = null;
Input? _input = null;
Options? _options = null;
Options? _options;

public ListObjectsTest()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public class BucketObject
/// The date and time the object was last modified.
/// </summary>
/// <example>2022-04-22T00:16:40+02:00</example>
public DateTime LastModified { get; set; }
public DateTime? LastModified { get; set; }
Comment thread
MichalFrends1 marked this conversation as resolved.

}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Version>2.1.0</Version>
<Version>2.2.0</Version>
<Authors>Frends</Authors>
<Copyright>Frends</Copyright>
<Company>Frends</Company>
Expand All @@ -20,12 +20,12 @@
</None>
</ItemGroup>
<ItemGroup>
<PackageReference Include="AWSSDK.Core" Version="4.0.3.5" />
<PackageReference Include="AWSSDK.S3" Version="4.0.14.2" />
<PackageReference Include="AWSSDK.Core" Version="4.0.8" />
<PackageReference Include="AWSSDK.S3" Version="4.0.24.1" />
<PackageReference Include="dotenv.net" Version="4.0.0" />
</ItemGroup>
<ItemGroup>
<Content Include="migration.json" PackagePath="/" Pack="true" />
<Content Include="../CHANGELOG.md" PackagePath="/" Pack="true" />
</ItemGroup>
</Project>
</Project>
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -14,7 +15,7 @@ namespace Frends.AmazonS3.ListObjects
/// <summary>
/// Amazon S3 task.
/// </summary>
public class AmazonS3
public static class AmazonS3
{
/// <summary>
/// Lists objects from specified AWS S3 Bucket.
Expand All @@ -25,18 +26,26 @@ public class AmazonS3
/// <param name="options">Options for the task</param>
/// <param name="cancellationToken">Token to stop ListObjects. This is generated by Frends.</param>
/// <returns>Result { List (BucketObject) Objects, bool Success, Error Error } where BucketObject contains { string BucketName, string Key, string Etag, long Size, DateTime LastModified }</returns>
public static async Task<Result> ListObjects([PropertyTab] Connection connection, [PropertyTab] Input input, [PropertyTab] Options options, CancellationToken cancellationToken)
public static async Task<Result> 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);
}

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)
Expand All @@ -53,7 +62,8 @@ public static async Task<Result> ListObjects([PropertyTab] Connection connection
/// <param name="options">Options for filtering and limiting results</param>
/// <param name="cancellationToken">Token to cancel the operation</param>
/// <returns>A list of BucketObject instances representing the objects in the bucket</returns>
private static async Task<List<BucketObject>> ListBucketContentsAsync(AmazonS3Client client, Input input, Options options, CancellationToken cancellationToken)
private static async Task<List<BucketObject>> ListBucketContentsAsync(AmazonS3Client client, Input input,
Options options, CancellationToken cancellationToken)
{
var data = new List<BucketObject>();
var request = GetListObjectsV2Request(input, options);
Expand All @@ -62,25 +72,40 @@ private static async Task<List<BucketObject>> ListBucketContentsAsync(AmazonS3Cl
{
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)
{
cancellationToken.ThrowIfCancellationRequested();
data.Add(new BucketObject
{
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
break;
}
while (true);
} while (true);

return data;
}
Expand Down Expand Up @@ -112,6 +137,7 @@ private static ListObjectsV2Request GetListObjectsV2Request(Input input, Options
/// </summary>
/// <param name="region">The region enum value to convert</param>
/// <returns>The corresponding AWS RegionEndpoint instance</returns>
[ExcludeFromCodeCoverage]
private static RegionEndpoint RegionSelection(Region region)
{
switch (region)
Expand Down
Loading