From ca4b3be85b76849a0dc9354de7af90a32ff4fe92 Mon Sep 17 00:00:00 2001 From: Eric Graf Date: Fri, 13 Sep 2024 16:40:15 -0400 Subject: [PATCH 1/6] v 1.3.0 - dotnet 8 support, package updates, etc. (#139) (#140) From 17ea6578013a5055c483ed02c60b25def411103c Mon Sep 17 00:00:00 2001 From: Eric Graf Date: Sat, 22 Nov 2025 23:40:21 -0500 Subject: [PATCH 2/6] NET 10 support; NET 6 dropped; AWS and Other Nuget Updates. (#149) - Dropped support for .NET 6 - Added support for .NET 10 - Added support for AWS SDK S3 v4 - Maintaining support for AWS SDK S3 v3 - Build Profiles for AWS SDK versions - Tests against each AWS SDK version --- .github/workflows/dotnet_test.yml | 12 ++--- .github/workflows/publish.yml | 2 +- FileParty.sln | 38 +++++++++++--- src/FileParty.Core/FileParty.Core.csproj | 8 +-- .../AWS.S3Module.cs | 5 +- .../Config/AWSRoleBasedConfiguration.cs | 8 ++- .../Config/AWSSessionCredentials.cs | 10 +++- .../Config/AWSStoredProfileConfiguration.cs | 11 ---- .../FileParty.Providers.AWS.S3.csproj | 35 +++++++++++-- .../FilePartyAWSCredentialFactory.cs | 51 ++++++++++++++++++- .../S3StorageProvider.cs | 16 +++--- .../FileParty.Providers.FileSystem.csproj | 6 ++- .../FileParty.Core.Tests.csproj | 12 +++-- .../AwsSdkVersionTest.cs | 28 ++++++++++ .../CredentialFactoryShould.cs | 32 +++++++++--- .../FileParty.Handlers.AWS.S3.Tests.csproj | 26 ++++++++-- ...FileParty.Handlers.FileSystem.Tests.csproj | 12 +++-- 17 files changed, 242 insertions(+), 70 deletions(-) create mode 100644 test/FileParty.Handlers.AWS.S3.Tests/AwsSdkVersionTest.cs diff --git a/.github/workflows/dotnet_test.yml b/.github/workflows/dotnet_test.yml index 84c57e2..f7daf84 100644 --- a/.github/workflows/dotnet_test.yml +++ b/.github/workflows/dotnet_test.yml @@ -14,13 +14,13 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@v1 with: - dotnet-version: 8.0.x - - name: Restore dependencies - run: dotnet restore - - name: Build - run: dotnet build --no-restore + dotnet-version: 10.0.x - name: Test - run: dotnet test --no-build --verbosity normal + run: | + dotnet test test/FileParty.Core.Tests/FileParty.Core.Tests.csproj --configuration Release --verbosity normal + dotnet test test/FileParty.Handlers.FileSystem.Tests/FileParty.Handlers.FileSystem.Tests.csproj --configuration Release --verbosity normal + dotnet test test/FileParty.Handlers.AWS.S3.Tests/FileParty.Handlers.AWS.S3.Tests.csproj --configuration Release-V3 --verbosity normal + dotnet test test/FileParty.Handlers.AWS.S3.Tests/FileParty.Handlers.AWS.S3.Tests.csproj --configuration Release-V4 --verbosity normal env: "fileparty_s3_region": ${{ secrets.TEST_S3_REGION }} "fileparty_s3_bucket": ${{ secrets.TEST_S3_BUCKET }} diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index bda256e..2b29ade 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -13,7 +13,7 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@v1 with: - dotnet-version: 8.0.x + dotnet-version: 10.0.x - name: Build and Publish Nuget Packages id: csharp_nuget_publish uses: JankwareDotCom/nuget_publish@0.4.0 diff --git a/FileParty.sln b/FileParty.sln index d0bd762..ccd1f3a 100644 --- a/FileParty.sln +++ b/FileParty.sln @@ -27,36 +27,58 @@ Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU + Debug-V4|Any CPU = Debug-V4|Any CPU + Release-V4|Any CPU = Release-V4|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {F4F0963C-2998-4B87-8BFD-2CF12A5ABDA4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F4F0963C-2998-4B87-8BFD-2CF12A5ABDA4}.Debug|Any CPU.Build.0 = Debug|Any CPU {F4F0963C-2998-4B87-8BFD-2CF12A5ABDA4}.Release|Any CPU.ActiveCfg = Release|Any CPU {F4F0963C-2998-4B87-8BFD-2CF12A5ABDA4}.Release|Any CPU.Build.0 = Release|Any CPU + {F4F0963C-2998-4B87-8BFD-2CF12A5ABDA4}.Debug-V4|Any CPU.ActiveCfg = Debug|Any CPU + {F4F0963C-2998-4B87-8BFD-2CF12A5ABDA4}.Debug-V4|Any CPU.Build.0 = Debug|Any CPU + {F4F0963C-2998-4B87-8BFD-2CF12A5ABDA4}.Release-V4|Any CPU.ActiveCfg = Release|Any CPU + {F4F0963C-2998-4B87-8BFD-2CF12A5ABDA4}.Release-V4|Any CPU.Build.0 = Release|Any CPU {792B430A-5277-44B8-9284-2D0C256DF22D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {792B430A-5277-44B8-9284-2D0C256DF22D}.Debug|Any CPU.Build.0 = Debug|Any CPU {792B430A-5277-44B8-9284-2D0C256DF22D}.Release|Any CPU.ActiveCfg = Release|Any CPU {792B430A-5277-44B8-9284-2D0C256DF22D}.Release|Any CPU.Build.0 = Release|Any CPU + {792B430A-5277-44B8-9284-2D0C256DF22D}.Debug-V4|Any CPU.ActiveCfg = Debug|Any CPU + {792B430A-5277-44B8-9284-2D0C256DF22D}.Debug-V4|Any CPU.Build.0 = Debug|Any CPU + {792B430A-5277-44B8-9284-2D0C256DF22D}.Release-V4|Any CPU.ActiveCfg = Release|Any CPU + {792B430A-5277-44B8-9284-2D0C256DF22D}.Release-V4|Any CPU.Build.0 = Release|Any CPU {739F3D2D-5541-47A3-9C97-5329FB8583CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {739F3D2D-5541-47A3-9C97-5329FB8583CE}.Debug|Any CPU.Build.0 = Debug|Any CPU {739F3D2D-5541-47A3-9C97-5329FB8583CE}.Release|Any CPU.ActiveCfg = Release|Any CPU {739F3D2D-5541-47A3-9C97-5329FB8583CE}.Release|Any CPU.Build.0 = Release|Any CPU - {E557D9D3-A8B9-4D31-BD7A-631C13025ABA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E557D9D3-A8B9-4D31-BD7A-631C13025ABA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E557D9D3-A8B9-4D31-BD7A-631C13025ABA}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E557D9D3-A8B9-4D31-BD7A-631C13025ABA}.Release|Any CPU.Build.0 = Release|Any CPU + {739F3D2D-5541-47A3-9C97-5329FB8583CE}.Debug-V4|Any CPU.ActiveCfg = Debug-V4|Any CPU + {739F3D2D-5541-47A3-9C97-5329FB8583CE}.Debug-V4|Any CPU.Build.0 = Debug-V4|Any CPU + {739F3D2D-5541-47A3-9C97-5329FB8583CE}.Release-V4|Any CPU.ActiveCfg = Release-V4|Any CPU + {739F3D2D-5541-47A3-9C97-5329FB8583CE}.Release-V4|Any CPU.Build.0 = Release-V4|Any CPU {C17D1DB1-7C20-413E-BC69-A0656720FA33}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C17D1DB1-7C20-413E-BC69-A0656720FA33}.Debug|Any CPU.Build.0 = Debug|Any CPU {C17D1DB1-7C20-413E-BC69-A0656720FA33}.Release|Any CPU.ActiveCfg = Release|Any CPU {C17D1DB1-7C20-413E-BC69-A0656720FA33}.Release|Any CPU.Build.0 = Release|Any CPU + {C17D1DB1-7C20-413E-BC69-A0656720FA33}.Debug-V4|Any CPU.ActiveCfg = Debug|Any CPU + {C17D1DB1-7C20-413E-BC69-A0656720FA33}.Debug-V4|Any CPU.Build.0 = Debug|Any CPU + {C17D1DB1-7C20-413E-BC69-A0656720FA33}.Release-V4|Any CPU.ActiveCfg = Release|Any CPU + {C17D1DB1-7C20-413E-BC69-A0656720FA33}.Release-V4|Any CPU.Build.0 = Release|Any CPU {4ADB9737-3274-4E6C-ABA0-FE214D89807D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {4ADB9737-3274-4E6C-ABA0-FE214D89807D}.Debug|Any CPU.Build.0 = Debug|Any CPU {4ADB9737-3274-4E6C-ABA0-FE214D89807D}.Release|Any CPU.ActiveCfg = Release|Any CPU {4ADB9737-3274-4E6C-ABA0-FE214D89807D}.Release|Any CPU.Build.0 = Release|Any CPU - {22ED881A-4D94-4A4E-B908-BD1F4CCFB026}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {22ED881A-4D94-4A4E-B908-BD1F4CCFB026}.Debug|Any CPU.Build.0 = Debug|Any CPU - {22ED881A-4D94-4A4E-B908-BD1F4CCFB026}.Release|Any CPU.ActiveCfg = Release|Any CPU - {22ED881A-4D94-4A4E-B908-BD1F4CCFB026}.Release|Any CPU.Build.0 = Release|Any CPU + {4ADB9737-3274-4E6C-ABA0-FE214D89807D}.Debug-V4|Any CPU.ActiveCfg = Debug|Any CPU + {4ADB9737-3274-4E6C-ABA0-FE214D89807D}.Debug-V4|Any CPU.Build.0 = Debug|Any CPU + {4ADB9737-3274-4E6C-ABA0-FE214D89807D}.Release-V4|Any CPU.ActiveCfg = Release|Any CPU + {4ADB9737-3274-4E6C-ABA0-FE214D89807D}.Release-V4|Any CPU.Build.0 = Release|Any CPU + {E557D9D3-A8B9-4D31-BD7A-631C13025ABA}.Debug|Any CPU.ActiveCfg = Debug-V3|Any CPU + {E557D9D3-A8B9-4D31-BD7A-631C13025ABA}.Debug|Any CPU.Build.0 = Debug-V3|Any CPU + {E557D9D3-A8B9-4D31-BD7A-631C13025ABA}.Debug-V4|Any CPU.ActiveCfg = Debug-V4|Any CPU + {E557D9D3-A8B9-4D31-BD7A-631C13025ABA}.Debug-V4|Any CPU.Build.0 = Debug-V4|Any CPU + {E557D9D3-A8B9-4D31-BD7A-631C13025ABA}.Release|Any CPU.ActiveCfg = Release-V3|Any CPU + {E557D9D3-A8B9-4D31-BD7A-631C13025ABA}.Release|Any CPU.Build.0 = Release-V3|Any CPU + {E557D9D3-A8B9-4D31-BD7A-631C13025ABA}.Release-V4|Any CPU.ActiveCfg = Release-V4|Any CPU + {E557D9D3-A8B9-4D31-BD7A-631C13025ABA}.Release-V4|Any CPU.Build.0 = Release-V4|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {4ADB9737-3274-4E6C-ABA0-FE214D89807D} = {5C3F1ED6-EBB2-443C-8222-CC938FF2EB21} diff --git a/src/FileParty.Core/FileParty.Core.csproj b/src/FileParty.Core/FileParty.Core.csproj index 3be2eda..23084f6 100644 --- a/src/FileParty.Core/FileParty.Core.csproj +++ b/src/FileParty.Core/FileParty.Core.csproj @@ -1,15 +1,17 @@  - 1.3.0 + 1.4.0 Jankware Agnostic File Storage, Core Project, Service Registration https://github.com/JankwareDotCom/FileParty https://github.com/JankwareDotCom/FileParty - net6.0;net8.0;netstandard2.0;netstandard2.1 + net8.0;net10.0;netstandard2.0;netstandard2.1 true Jankware FileParty https://raw.githubusercontent.com/JankwareDotCom/FileParty/main/README.md + Debug;Release;Debug-V4;Release-V4 + AnyCPU @@ -24,7 +26,7 @@ - + diff --git a/src/FileParty.Providers.AWS.S3/AWS.S3Module.cs b/src/FileParty.Providers.AWS.S3/AWS.S3Module.cs index 08a2f11..a48b163 100644 --- a/src/FileParty.Providers.AWS.S3/AWS.S3Module.cs +++ b/src/FileParty.Providers.AWS.S3/AWS.S3Module.cs @@ -1,4 +1,5 @@ -using FileParty.Core; +using System; +using FileParty.Core; using FileParty.Core.Registration; using FileParty.Providers.AWS.S3.Interfaces; @@ -6,6 +7,8 @@ namespace FileParty.Providers.AWS.S3 { public class AWS_S3Module : BaseFilePartyModule { + public static readonly bool IsAwsSdkV4 = Type.GetType("Amazon.Runtime.Credentials.DefaultAWSCredentialsIdentityResolver, AWSSDK.Core") != null; + public AWS_S3Module() { this.RegisterModuleDependency AssumeRoleAsync(IFilePartyAWSCredentialFacto ? nameof(FileParty) + "_" + nameof(AWS_S3Module) + "_" + _internalIdentifier : RoleSessionName; - using (var stsClient = new AmazonSecurityTokenServiceClient(credFactory.GetAmazonCredentials(_baseConfig))) + var creds = credFactory.GetAmazonCredentials(_baseConfig); + var config = new AmazonSecurityTokenServiceConfig + { + RegionEndpoint = this.GetRegionEndpoint() + }; + + using (var stsClient = new AmazonSecurityTokenServiceClient(creds, config)) { try { diff --git a/src/FileParty.Providers.AWS.S3/Config/AWSSessionCredentials.cs b/src/FileParty.Providers.AWS.S3/Config/AWSSessionCredentials.cs index 5beb8f8..c11ae5b 100644 --- a/src/FileParty.Providers.AWS.S3/Config/AWSSessionCredentials.cs +++ b/src/FileParty.Providers.AWS.S3/Config/AWSSessionCredentials.cs @@ -1,4 +1,5 @@ using System.Threading.Tasks; +using Amazon; using Amazon.Runtime; using Amazon.SecurityToken; using Amazon.SecurityToken.Model; @@ -43,7 +44,14 @@ internal async Task GetTemporaryCredentialsAsync( return _sessionCredentials; } - using (var stsClient = new AmazonSecurityTokenServiceClient(credFactory.GetAmazonCredentials(_baseConfig))) + var creds = credFactory.GetAmazonCredentials(_baseConfig); + + var config = new AmazonSecurityTokenServiceConfig + { + RegionEndpoint = this.GetRegionEndpoint() + }; + + using (var stsClient = new AmazonSecurityTokenServiceClient(creds, config)) { var getSessionTokenRequest = new GetSessionTokenRequest { diff --git a/src/FileParty.Providers.AWS.S3/Config/AWSStoredProfileConfiguration.cs b/src/FileParty.Providers.AWS.S3/Config/AWSStoredProfileConfiguration.cs index 4399303..f99c8ef 100644 --- a/src/FileParty.Providers.AWS.S3/Config/AWSStoredProfileConfiguration.cs +++ b/src/FileParty.Providers.AWS.S3/Config/AWSStoredProfileConfiguration.cs @@ -33,16 +33,5 @@ public AWSStoredProfileConfiguration(string profileName, string profileLocation) public string ProfileName { get; set; } = "default"; public string ProfileLocation { get; set; } - - internal StoredProfileAWSCredentials GetConfig() - { - return string.IsNullOrWhiteSpace(ProfileLocation) - ? string.IsNullOrWhiteSpace(ProfileName) - ? new StoredProfileAWSCredentials() - : new StoredProfileAWSCredentials(ProfileName) - : string.IsNullOrWhiteSpace(ProfileName) - ? new StoredProfileAWSCredentials("default", ProfileLocation) - : new StoredProfileAWSCredentials(ProfileName, ProfileLocation); - } } } \ No newline at end of file diff --git a/src/FileParty.Providers.AWS.S3/FileParty.Providers.AWS.S3.csproj b/src/FileParty.Providers.AWS.S3/FileParty.Providers.AWS.S3.csproj index cef3887..edef7f3 100644 --- a/src/FileParty.Providers.AWS.S3/FileParty.Providers.AWS.S3.csproj +++ b/src/FileParty.Providers.AWS.S3/FileParty.Providers.AWS.S3.csproj @@ -1,22 +1,49 @@  - net6.0;net8.0;netstandard2.0;netstandard2.1 - 1.3.0 + net8.0;net10.0;netstandard2.0;netstandard2.1 + 1.4.0 Agnostic File Storage, AWS S3 Module https://github.com/JankwareDotCom/FileParty https://github.com/JankwareDotCom/FileParty true + Debug;Release;Debug-V3;Release-V3;Debug-V4;Release-V4 + AnyCPU + + $(DefineConstants);AWS_SDK_ANY + + + + $(DefineConstants);AWS_SDK_V3 + + + + $(DefineConstants);AWS_SDK_V4 + + - - + + + + + + + + + + + + + + + diff --git a/src/FileParty.Providers.AWS.S3/FilePartyAWSCredentialFactory.cs b/src/FileParty.Providers.AWS.S3/FilePartyAWSCredentialFactory.cs index 4529364..e005315 100644 --- a/src/FileParty.Providers.AWS.S3/FilePartyAWSCredentialFactory.cs +++ b/src/FileParty.Providers.AWS.S3/FilePartyAWSCredentialFactory.cs @@ -1,5 +1,10 @@ using System; +using System.IO; +using System.Linq; +using System.Reflection; using Amazon.Runtime; +using Amazon.Runtime.CredentialManagement; +using Amazon.Runtime.Credentials; using Amazon.S3; using Amazon.SecurityToken; using FileParty.Core.Exceptions; @@ -31,9 +36,27 @@ public virtual AWSCredentials GetAmazonCredentials(StorageProviderConfiguration< .GetAwaiter() .GetResult(); case AWSDefaultConfiguration _: - return FallbackCredentialsFactory.GetCredentials(false); + return GetDefaultCredentials(); case AWSStoredProfileConfiguration storedProfileConfiguration: - return storedProfileConfiguration.GetConfig(); + { + var profileLocation = string.IsNullOrWhiteSpace(storedProfileConfiguration.ProfileLocation) + ? null + : Directory.Exists(storedProfileConfiguration.ProfileLocation) + ? Path.Combine(storedProfileConfiguration.ProfileLocation, "credentials") + : storedProfileConfiguration.ProfileLocation; + + var profileName = string.IsNullOrWhiteSpace(storedProfileConfiguration.ProfileName) + ? "default" + : storedProfileConfiguration.ProfileName; + + var chain = string.IsNullOrWhiteSpace(profileLocation) + ? new CredentialProfileStoreChain() + : new CredentialProfileStoreChain(profileLocation); + + return chain.TryGetAWSCredentials(profileName, out var creds) + ? creds + : throw Errors.InvalidConfiguration; + } case AWSInstanceProfileConfiguration instanceConfiguration: return new InstanceProfileAWSCredentials(instanceConfiguration.Role); } @@ -57,5 +80,29 @@ public virtual AWSCredentials GetAmazonCredentials(StorageProviderConfiguration< throw Errors.InvalidConfiguration; } + + private static AWSCredentials GetDefaultCredentials() + { + // v3 support + if (!AWS_S3Module.IsAwsSdkV4) return FallbackCredentialsFactory.GetCredentials(false); + + // v4 support DefaultAWSCredentialsIdentityResolver.GetCredentials(); + return (AWSCredentials)V4GetCredentialsMethod + ?.Invoke( + null, + V4GetCredentialsMethod.GetParameters() + .Select(s => Convert.ChangeType(null, s.ParameterType)).ToArray()) + ?? throw new InvalidOperationException("Unable to get credentials"); + } + + + + private static readonly MethodInfo V4GetCredentialsMethod = + AWS_S3Module.IsAwsSdkV4 + ? Type.GetType("Amazon.Runtime.Credentials.DefaultAWSCredentialsIdentityResolver, AWSSDK.Core") + ?.GetMethod("GetCredentials") + : null; + + } } \ No newline at end of file diff --git a/src/FileParty.Providers.AWS.S3/S3StorageProvider.cs b/src/FileParty.Providers.AWS.S3/S3StorageProvider.cs index ce12270..0e802fe 100644 --- a/src/FileParty.Providers.AWS.S3/S3StorageProvider.cs +++ b/src/FileParty.Providers.AWS.S3/S3StorageProvider.cs @@ -142,7 +142,7 @@ public virtual async Task ExistsAsync(string storagePointer, using (var s3Wrapper = new FilePartyS3ClientWrapper(_s3ClientFactory)) { var _ = await s3Wrapper.ExecuteAsync( - (s3Client) => GetInformationAsync(s3Client, storagePointer, cancellationToken)); + async (s3Client) => await GetInformationAsync(s3Client, storagePointer, cancellationToken)); } return true; @@ -153,12 +153,12 @@ public virtual async Task ExistsAsync(string storagePointer, } } - public virtual Task> ExistsAsync(IEnumerable storagePointers, + public virtual async Task> ExistsAsync(IEnumerable storagePointers, CancellationToken cancellationToken = default) { using (var s3Wrapper = new FilePartyS3ClientWrapper(_s3ClientFactory)) { - return s3Wrapper.ExecuteAsync((s3Client) => + return await s3Wrapper.ExecuteAsync((s3Client) => { IDictionary result = storagePointers .ToDictionary( @@ -170,12 +170,12 @@ public virtual Task> ExistsAsync(IEnumerable s } } - public Task TryGetStoredItemTypeAsync(string storagePointer, + public async Task TryGetStoredItemTypeAsync(string storagePointer, CancellationToken cancellationToken = default) { using (var s3Wrapper = new FilePartyS3ClientWrapper(_s3ClientFactory)) { - return s3Wrapper.ExecuteAsync((s3Client) => + return await s3Wrapper.ExecuteAsync((s3Client) => TryGetStoredItemTypeAsync(s3Client, storagePointer, cancellationToken)); } } @@ -276,7 +276,7 @@ protected virtual async Task GetFileInformation(AmazonS3C result.StoredType = StoredItemType.File; result.Size = omInfo.ContentLength; - result.LastModifiedTimestamp = omInfo.LastModified.ToUniversalTime(); + result.LastModifiedTimestamp = (omInfo.LastModified as DateTime?).GetValueOrDefault().ToUniversalTime(); result.StoragePointer = storagePointer; return result; } @@ -452,9 +452,9 @@ protected virtual async Task DeleteAsync(AmazonS3Client s3Client, IEnumerable s.Key).ToArray(), cancellationToken); + await DeleteAsync(directoryContents.S3Objects?.Select(s => s.Key).ToArray(), cancellationToken); } } } diff --git a/src/FileParty.Providers.FileSystem/FileParty.Providers.FileSystem.csproj b/src/FileParty.Providers.FileSystem/FileParty.Providers.FileSystem.csproj index bb7fef4..86b04ea 100644 --- a/src/FileParty.Providers.FileSystem/FileParty.Providers.FileSystem.csproj +++ b/src/FileParty.Providers.FileSystem/FileParty.Providers.FileSystem.csproj @@ -1,12 +1,14 @@  - net6.0;net8.0;netstandard2.0;netstandard2.1 - 1.3.0 + net8.0;net10.0;netstandard2.0;netstandard2.1 + 1.4.0 Agnostic File Storage, Filesystem Module https://github.com/JankwareDotCom/FileParty https://github.com/JankwareDotCom/FileParty true + Debug;Release;Debug-V4;Release-V4 + AnyCPU diff --git a/test/FileParty.Core.Tests/FileParty.Core.Tests.csproj b/test/FileParty.Core.Tests/FileParty.Core.Tests.csproj index e169b08..8dc5f1e 100644 --- a/test/FileParty.Core.Tests/FileParty.Core.Tests.csproj +++ b/test/FileParty.Core.Tests/FileParty.Core.Tests.csproj @@ -2,24 +2,26 @@ false - net8.0 + net10.0 FileParty.Core.Tests FileParty.Core.Tests FileParty.Core.Tests FileParty.Core.Tests FileParty.Core.Tests FileParty.Core.Tests + Debug;Release;Debug-V4;Release-V4 + AnyCPU - + - - + + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/test/FileParty.Handlers.AWS.S3.Tests/AwsSdkVersionTest.cs b/test/FileParty.Handlers.AWS.S3.Tests/AwsSdkVersionTest.cs new file mode 100644 index 0000000..9f49dad --- /dev/null +++ b/test/FileParty.Handlers.AWS.S3.Tests/AwsSdkVersionTest.cs @@ -0,0 +1,28 @@ +using System.Reflection; +using Xunit; + +namespace FileParty.Handlers.AWS.S3.Tests; + +public class AwsSdkVersionTest +{ + [Theory] +#if AWS_SDK_V3 + [InlineData(3)] +#endif +#if AWS_SDK_V4 + [InlineData(4)] +#endif + public void ShouldUseExpectedAwsSdkVersion(int expectedVersion) + { + var awsS3Assembly = Assembly.Load("AWSSDK.S3"); + + Assert.NotNull(awsS3Assembly); + + var version = awsS3Assembly.GetName().Version; + + // Assert expected version + Assert.True( + version?.Major == expectedVersion, + $"Expected AWS SDK v{expectedVersion}, but got v{version?.Major ?? 0}"); + } +} \ No newline at end of file diff --git a/test/FileParty.Handlers.AWS.S3.Tests/CredentialFactoryShould.cs b/test/FileParty.Handlers.AWS.S3.Tests/CredentialFactoryShould.cs index c1771ac..7791f7e 100644 --- a/test/FileParty.Handlers.AWS.S3.Tests/CredentialFactoryShould.cs +++ b/test/FileParty.Handlers.AWS.S3.Tests/CredentialFactoryShould.cs @@ -12,6 +12,7 @@ using FileParty.Providers.AWS.S3.Config; using FileParty.Providers.AWS.S3.Interfaces; using Microsoft.Extensions.DependencyInjection; +using Moq; using Xunit; namespace FileParty.Handlers.AWS.S3.Tests; @@ -116,20 +117,34 @@ public async Task CreateCredentials_UsingSession() await EnsureFileCreationAndDeletion(cfg); } - [Fact(Skip = "Long Running Test")] + [Fact(Skip = "Long Running Test")] // last manually verified 2025-11-20 public async Task CreateCredentials_ButThrowDueToExpired_UsingSession() { + var sc = new ServiceCollection(); + sc.AddFileParty(c => c.AddModule(null)); + await using var sp = sc.BuildServiceProvider(); + var cfg = new AWSSessionCredentials(_accessKey, _secretKey) { Region = _regionName, Name = _bucketName, - DurationSeconds = 15 * 60 + DurationSeconds = 15 * 60 // 15 minute duration is minimum }; - - await _credFactory.GetAmazonCredentials(cfg).GetCredentialsAsync(); - - await Task.Delay(TimeSpan.FromSeconds(cfg.DurationSeconds), CancellationToken.None); - await Assert.ThrowsAnyAsync(async () => { await EnsureFileCreationAndDeletion(cfg); }); + + var clientFactory = sp.GetRequiredService(); + + var client = clientFactory.GetClient(cfg); + + Assert.True((await client.ListObjectsAsync(cfg.Name)).HttpStatusCode == System.Net.HttpStatusCode.OK); + + await Task.Delay(TimeSpan.FromSeconds(cfg.DurationSeconds + 10), CancellationToken.None); + + var exc = await Assert.ThrowsAsync(async () => + { + await client.ListObjectsAsync(cfg.Name); + }); + + Assert.Equal("The provided token has expired.", exc.Message); } [Fact] @@ -150,6 +165,7 @@ public async Task CreateCredentials_UsingRole() } } + //[Fact] // last manually verified 2025-11-22 [Fact(Skip = "Requires External AWS Account")] public async Task CreateCredentials_UsingRole_ExternalAccount() { @@ -160,7 +176,7 @@ public async Task CreateCredentials_UsingRole_ExternalAccount() var cfg = new AWSRoleBasedConfiguration { Name = externalConfig[0], - Region = _regionName, + Region = externalConfig[3], RoleArn = externalConfig[1], ExternalId = externalConfig[2] }; diff --git a/test/FileParty.Handlers.AWS.S3.Tests/FileParty.Handlers.AWS.S3.Tests.csproj b/test/FileParty.Handlers.AWS.S3.Tests/FileParty.Handlers.AWS.S3.Tests.csproj index ec8d85b..95db476 100644 --- a/test/FileParty.Handlers.AWS.S3.Tests/FileParty.Handlers.AWS.S3.Tests.csproj +++ b/test/FileParty.Handlers.AWS.S3.Tests/FileParty.Handlers.AWS.S3.Tests.csproj @@ -1,18 +1,36 @@  - net8.0 + net10.0 + Debug-V3;Debug-V4;Release-V3;Release-V4 + + + + $(DefineConstants);AWS_SDK_V3 + + + + $(DefineConstants);AWS_SDK_V4 - - - + + + + runtime; build; native; contentfiles; analyzers; buildtransitive all + + + + + + + + diff --git a/test/FileParty.Handlers.FileSystem.Tests/FileParty.Handlers.FileSystem.Tests.csproj b/test/FileParty.Handlers.FileSystem.Tests/FileParty.Handlers.FileSystem.Tests.csproj index 89c6205..dfc809b 100644 --- a/test/FileParty.Handlers.FileSystem.Tests/FileParty.Handlers.FileSystem.Tests.csproj +++ b/test/FileParty.Handlers.FileSystem.Tests/FileParty.Handlers.FileSystem.Tests.csproj @@ -4,17 +4,19 @@ false FileParty.Providers.FileSystem.Tests FileParty.Providers.FileSystem.Tests - net8.0 + net10.0 + Debug;Release;Debug-V4;Release-V4 + AnyCPU - - - + + + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all From 132a2b4858272e5afbc879acb51b5bab430b218d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 22 Nov 2025 23:50:29 -0500 Subject: [PATCH 3/6] Bump AWSSDK.S3 and 2 others (#142) From 3b1adb2fca9c6cff2e63bf09567e04220e0387b5 Mon Sep 17 00:00:00 2001 From: Eric Graf Date: Sat, 22 Nov 2025 23:57:59 -0500 Subject: [PATCH 4/6] Version Bump (#150) --- src/FileParty.Core/FileParty.Core.csproj | 2 +- .../FileParty.Providers.AWS.S3.csproj | 14 +++++++------- .../FileParty.Providers.FileSystem.csproj | 2 +- .../FileParty.Handlers.AWS.S3.Tests.csproj | 4 ++-- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/FileParty.Core/FileParty.Core.csproj b/src/FileParty.Core/FileParty.Core.csproj index 23084f6..894af8a 100644 --- a/src/FileParty.Core/FileParty.Core.csproj +++ b/src/FileParty.Core/FileParty.Core.csproj @@ -1,7 +1,7 @@  - 1.4.0 + 2.0.0 Jankware Agnostic File Storage, Core Project, Service Registration https://github.com/JankwareDotCom/FileParty diff --git a/src/FileParty.Providers.AWS.S3/FileParty.Providers.AWS.S3.csproj b/src/FileParty.Providers.AWS.S3/FileParty.Providers.AWS.S3.csproj index edef7f3..e491904 100644 --- a/src/FileParty.Providers.AWS.S3/FileParty.Providers.AWS.S3.csproj +++ b/src/FileParty.Providers.AWS.S3/FileParty.Providers.AWS.S3.csproj @@ -2,7 +2,7 @@ net8.0;net10.0;netstandard2.0;netstandard2.1 - 1.4.0 + 2.0.0 Agnostic File Storage, AWS S3 Module https://github.com/JankwareDotCom/FileParty https://github.com/JankwareDotCom/FileParty @@ -32,18 +32,18 @@ - - + + - - + + - - + + diff --git a/src/FileParty.Providers.FileSystem/FileParty.Providers.FileSystem.csproj b/src/FileParty.Providers.FileSystem/FileParty.Providers.FileSystem.csproj index 86b04ea..9ac7ed5 100644 --- a/src/FileParty.Providers.FileSystem/FileParty.Providers.FileSystem.csproj +++ b/src/FileParty.Providers.FileSystem/FileParty.Providers.FileSystem.csproj @@ -2,7 +2,7 @@ net8.0;net10.0;netstandard2.0;netstandard2.1 - 1.4.0 + 2.0.0 Agnostic File Storage, Filesystem Module https://github.com/JankwareDotCom/FileParty https://github.com/JankwareDotCom/FileParty diff --git a/test/FileParty.Handlers.AWS.S3.Tests/FileParty.Handlers.AWS.S3.Tests.csproj b/test/FileParty.Handlers.AWS.S3.Tests/FileParty.Handlers.AWS.S3.Tests.csproj index 95db476..24754da 100644 --- a/test/FileParty.Handlers.AWS.S3.Tests/FileParty.Handlers.AWS.S3.Tests.csproj +++ b/test/FileParty.Handlers.AWS.S3.Tests/FileParty.Handlers.AWS.S3.Tests.csproj @@ -24,11 +24,11 @@ - + - + From 7b52647dc2262fad04af5fd278d0c314d6613a53 Mon Sep 17 00:00:00 2001 From: Eric Graf Date: Mon, 24 Nov 2025 11:35:31 -0500 Subject: [PATCH 5/6] DI Dependency Range --- src/FileParty.Core/FileParty.Core.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/FileParty.Core/FileParty.Core.csproj b/src/FileParty.Core/FileParty.Core.csproj index 894af8a..25955c4 100644 --- a/src/FileParty.Core/FileParty.Core.csproj +++ b/src/FileParty.Core/FileParty.Core.csproj @@ -26,7 +26,7 @@ - + From 1f9a73c68e8b16fe86392284b6a310aa047dc9a7 Mon Sep 17 00:00:00 2001 From: Eric Graf Date: Mon, 24 Nov 2025 12:05:24 -0500 Subject: [PATCH 6/6] AWS V3 FallbackFactory should also be reflection, for when it's removed in later V4 packages. (#153) --- .../FilePartyAWSCredentialFactory.cs | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/FileParty.Providers.AWS.S3/FilePartyAWSCredentialFactory.cs b/src/FileParty.Providers.AWS.S3/FilePartyAWSCredentialFactory.cs index e005315..1ffde02 100644 --- a/src/FileParty.Providers.AWS.S3/FilePartyAWSCredentialFactory.cs +++ b/src/FileParty.Providers.AWS.S3/FilePartyAWSCredentialFactory.cs @@ -83,16 +83,14 @@ public virtual AWSCredentials GetAmazonCredentials(StorageProviderConfiguration< private static AWSCredentials GetDefaultCredentials() { - // v3 support - if (!AWS_S3Module.IsAwsSdkV4) return FallbackCredentialsFactory.GetCredentials(false); - - // v4 support DefaultAWSCredentialsIdentityResolver.GetCredentials(); - return (AWSCredentials)V4GetCredentialsMethod - ?.Invoke( - null, - V4GetCredentialsMethod.GetParameters() - .Select(s => Convert.ChangeType(null, s.ParameterType)).ToArray()) - ?? throw new InvalidOperationException("Unable to get credentials"); + return !AWS_S3Module.IsAwsSdkV4 + ? (AWSCredentials) V3GetCredentialsMethod + ?.Invoke(null, new object[]{false}) + ?? throw new InvalidOperationException("Unable to get v3 credentials") + : (AWSCredentials) V4GetCredentialsMethod + ?.Invoke(null, V4GetCredentialsMethod.GetParameters() + .Select(s => Convert.ChangeType(null, s.ParameterType)).ToArray()) + ?? throw new InvalidOperationException("Unable to get credentials"); } @@ -103,6 +101,10 @@ private static AWSCredentials GetDefaultCredentials() ?.GetMethod("GetCredentials") : null; - + private static readonly MethodInfo V3GetCredentialsMethod = + !AWS_S3Module.IsAwsSdkV4 + ? Type.GetType("Amazon.Runtime.FallbackCredentialsFactory, AWSSDK.Core") + ?.GetMethod("GetCredentials", new[]{typeof(bool)}) + : null; } } \ No newline at end of file