From 71f044fbba79d088c52038ca5d74d5567ea915db Mon Sep 17 00:00:00 2001 From: Nattapong Nunpan Date: Thu, 28 Aug 2025 15:21:31 +0700 Subject: [PATCH 1/8] set Content-Type based on file extension - Modified WriteAsync to detect MIME type from blob path using _mime.TryGetContentType - Falls back to "application/octet-stream" when no mapping is found - Uses BlobUploadOptions with BlobHttpHeaders to ensure Content-Type is stored - Fixes issue where browsers download images instead of rendering inline --- FluentStorage.Azure.Blobs/AzureBlobStorage.cs | 13 +++++++++++++ .../FluentStorage.Azure.Blobs.csproj | 1 + 2 files changed, 14 insertions(+) diff --git a/FluentStorage.Azure.Blobs/AzureBlobStorage.cs b/FluentStorage.Azure.Blobs/AzureBlobStorage.cs index fb040c6..1eac877 100644 --- a/FluentStorage.Azure.Blobs/AzureBlobStorage.cs +++ b/FluentStorage.Azure.Blobs/AzureBlobStorage.cs @@ -14,6 +14,7 @@ using Azure.Storage.Sas; using Blobs; using Microsoft.Identity.Client; +using Microsoft.AspNetCore.StaticFiles; using FluentStorage.Blobs; using FluentStorage.Azure.Blobs.Gen2.Model; @@ -28,6 +29,8 @@ class AzureBlobStorage : IAzureBlobStorage { private readonly string _containerName; private readonly ConcurrentDictionary _containerNameToContainerClient = new ConcurrentDictionary(); + private static readonly FileExtensionContentTypeProvider _mime = + new FileExtensionContentTypeProvider(); public AzureBlobStorage( BlobServiceClient blobServiceClient, @@ -129,9 +132,19 @@ public async Task WriteAsync(string fullPath, Stream dataStream, BlockBlobClient client = container.GetBlockBlobClient(path); + string contentType; + if (!_mime.TryGetContentType(path, out contentType)) { + contentType = "application/octet-stream"; + } try { + var options = new BlobUploadOptions { + HttpHeaders = new BlobHttpHeaders { + ContentType = contentType + } + }; await client.UploadAsync( new StorageSourceStream(dataStream), + options: options, cancellationToken: cancellationToken).ConfigureAwait(false); } catch (RequestFailedException ex) when (ex.ErrorCode == "OperationNotAllowedInCurrentState") { diff --git a/FluentStorage.Azure.Blobs/FluentStorage.Azure.Blobs.csproj b/FluentStorage.Azure.Blobs/FluentStorage.Azure.Blobs.csproj index 49bae01..ddc8a11 100644 --- a/FluentStorage.Azure.Blobs/FluentStorage.Azure.Blobs.csproj +++ b/FluentStorage.Azure.Blobs/FluentStorage.Azure.Blobs.csproj @@ -29,6 +29,7 @@ + From 68605e515377474a36cd5221c6425f600b4289ab Mon Sep 17 00:00:00 2001 From: IonutSur Date: Mon, 29 Sep 2025 17:31:45 +0300 Subject: [PATCH 2/8] Update AWS packages --- FluentStorage.AWS/Blobs/AwsS3BlobStorage.cs | 6 +++--- FluentStorage.AWS/Blobs/Converter.cs | 4 ++-- FluentStorage.AWS/FluentStorage.AWS.csproj | 8 ++++---- .../FluentStorage.Azure.Blobs.csproj | 4 ++-- FluentStorage/FluentStorage.csproj | 4 ++-- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/FluentStorage.AWS/Blobs/AwsS3BlobStorage.cs b/FluentStorage.AWS/Blobs/AwsS3BlobStorage.cs index c4159ff..b8a292b 100644 --- a/FluentStorage.AWS/Blobs/AwsS3BlobStorage.cs +++ b/FluentStorage.AWS/Blobs/AwsS3BlobStorage.cs @@ -335,7 +335,7 @@ public async Task GetPresignedUrlAsync(string fullPath, string mimeType, public async Task GetPresignedUrlAsync(string fullPath, string mimeType, int expiresInSeconds, HttpVerb verb, Protocol protocol) { IAmazonS3 client = await GetClientAsync().ConfigureAwait(false); - return client.GetPreSignedURL(new GetPreSignedUrlRequest() { + return await client.GetPreSignedURLAsync(new GetPreSignedUrlRequest() { BucketName = _bucketName, ContentType = mimeType, Expires = DateTime.UtcNow.AddSeconds(expiresInSeconds), @@ -360,11 +360,11 @@ public async Task SetAcl(string fullPath, string acl) throw new ArgumentException($"don't know '{acl}' acl", acl); } - await client.PutACLAsync(new PutACLRequest + await client.PutObjectAclAsync(new PutObjectAclRequest { BucketName = _bucketName, Key = StoragePath.Normalize(fullPath, true), - CannedACL = s3CannedAcl + ACL = s3CannedAcl }); } } diff --git a/FluentStorage.AWS/Blobs/Converter.cs b/FluentStorage.AWS/Blobs/Converter.cs index 49ec005..13f99e0 100644 --- a/FluentStorage.AWS/Blobs/Converter.cs +++ b/FluentStorage.AWS/Blobs/Converter.cs @@ -57,7 +57,7 @@ public static Blob ToBlob(this GetObjectMetadataResponse obj, string fullPath) { var r = new Blob(fullPath); r.MD5 = obj.ETag.Trim('\"'); //ETag contains actual MD5 hash, not sure why! r.Size = obj.ContentLength; - r.LastModificationTime = obj.LastModified.ToUniversalTime(); + r.LastModificationTime = obj.LastModified.Value.ToUniversalTime(); AddMetadata(r, obj); @@ -94,7 +94,7 @@ public static Blob ToBlob(this S3Object s3Obj) { blob.Size = s3Obj.Size; blob.MD5 = s3Obj.ETag.Trim('\"'); - blob.LastModificationTime = s3Obj.LastModified.ToUniversalTime(); + blob.LastModificationTime = s3Obj.LastModified.Value.ToUniversalTime(); blob.Properties["StorageClass"] = s3Obj.StorageClass; blob.Properties["ETag"] = s3Obj.ETag; diff --git a/FluentStorage.AWS/FluentStorage.AWS.csproj b/FluentStorage.AWS/FluentStorage.AWS.csproj index 4bfa080..8ce7841 100644 --- a/FluentStorage.AWS/FluentStorage.AWS.csproj +++ b/FluentStorage.AWS/FluentStorage.AWS.csproj @@ -23,10 +23,10 @@ True - - - - + + + + diff --git a/FluentStorage.Azure.Blobs/FluentStorage.Azure.Blobs.csproj b/FluentStorage.Azure.Blobs/FluentStorage.Azure.Blobs.csproj index 49bae01..46218ab 100644 --- a/FluentStorage.Azure.Blobs/FluentStorage.Azure.Blobs.csproj +++ b/FluentStorage.Azure.Blobs/FluentStorage.Azure.Blobs.csproj @@ -27,12 +27,12 @@ - + - + diff --git a/FluentStorage/FluentStorage.csproj b/FluentStorage/FluentStorage.csproj index d10d1cd..a9da8d9 100644 --- a/FluentStorage/FluentStorage.csproj +++ b/FluentStorage/FluentStorage.csproj @@ -30,11 +30,11 @@ - + - + From 55abb9ee74c73bbf3ac080615929e19a7384f67a Mon Sep 17 00:00:00 2001 From: Robin Rodricks Date: Wed, 1 Oct 2025 16:43:15 +0530 Subject: [PATCH 3/8] FluentStorage 6.0.0 --- .gitignore | 2 ++ FluentStorage.AWS/FluentStorage.AWS.csproj | 8 +++-- .../FluentStorage.Azure.Blobs.csproj | 8 +++-- .../FluentStorage.Azure.DataLake.csproj | 8 +++-- .../FluentStorage.Azure.EventHub.csproj | 8 +++-- .../FluentStorage.Azure.Files.csproj | 8 +++-- .../FluentStorage.Azure.KeyVault.csproj | 8 +++-- .../FluentStorage.Azure.Queues.csproj | 8 +++-- .../FluentStorage.Azure.ServiceBus.csproj | 8 +++-- .../FluentStorage.Azure.ServiceFabric.csproj | 8 +++-- .../FluentStorage.Databricks.csproj | 8 +++-- FluentStorage.FTP/FluentStorage.FTP.csproj | 10 +++--- FluentStorage.GCP/FluentStorage.GCP.csproj | 8 +++-- FluentStorage.SFTP/FluentStorage.SFTP.csproj | 10 +++--- .../FluentStorage.Tests.Console.csproj | 2 +- .../FluentStorage.Tests.FTP.csproj | 2 +- .../FluentStorage.Tests.Integration.csproj | 2 +- .../FluentStorage.Tests.csproj | 2 +- FluentStorage/FluentStorage.csproj | 8 +++-- RELEASES.md | 31 +++++++++++++++++++ 20 files changed, 109 insertions(+), 48 deletions(-) diff --git a/.gitignore b/.gitignore index 6e55163..26e3b2b 100644 --- a/.gitignore +++ b/.gitignore @@ -196,4 +196,6 @@ FakesAssemblies/ *.opt out/ +build/ + *.lock.json \ No newline at end of file diff --git a/FluentStorage.AWS/FluentStorage.AWS.csproj b/FluentStorage.AWS/FluentStorage.AWS.csproj index 8ce7841..6168eb2 100644 --- a/FluentStorage.AWS/FluentStorage.AWS.csproj +++ b/FluentStorage.AWS/FluentStorage.AWS.csproj @@ -1,7 +1,7 @@  FluentStorage.AWS - netstandard2.0;netstandard2.1;net50;net60 + netstandard2.0;netstandard2.1;net70;net80;net90 FluentStorage.AWS FluentStorage.AWS Extension to FluentStorage providing integration with AWS S3 blob storage. @@ -9,7 +9,7 @@ true logo-nuget.png Robin Rodricks, Ivan Gavryliuk, FluentStorage Contributors - 5.5.0 + 6.0.0 https://github.com/robinrodricks/FluentStorage https://github.com/robinrodricks/FluentStorage GitHub @@ -17,7 +17,9 @@ latest True ..\FluentStorage\sn.snk - bin\$(Configuration)\$(TargetFramework)\FluentStorage.AWS.xml + $(SolutionDir)build\FluentStorage.AWS.xml + $(SolutionDir)build\ + True diff --git a/FluentStorage.Azure.Blobs/FluentStorage.Azure.Blobs.csproj b/FluentStorage.Azure.Blobs/FluentStorage.Azure.Blobs.csproj index 46218ab..363923e 100644 --- a/FluentStorage.Azure.Blobs/FluentStorage.Azure.Blobs.csproj +++ b/FluentStorage.Azure.Blobs/FluentStorage.Azure.Blobs.csproj @@ -1,7 +1,7 @@  - netstandard2.0;netstandard2.1;net50;net60 + netstandard2.0;netstandard2.1;net70;net80;net90 FluentStorage.Azure.Blobs FluentStorage.Azure.Blobs FluentStorage.Azure.Blobs @@ -10,7 +10,7 @@ true logo-nuget.png Robin Rodricks, Ivan Gavryliuk, FluentStorage Contributors - 5.3.0 + 6.0.0 https://github.com/robinrodricks/FluentStorage https://github.com/robinrodricks/FluentStorage GitHub @@ -18,7 +18,9 @@ latest True ..\FluentStorage\sn.snk - bin\$(Configuration)\$(TargetFramework)\FluentStorage.Azure.Blobs.xml + $(SolutionDir)build\FluentStorage.Azure.Blobs.xml + $(SolutionDir)build\ + diff --git a/FluentStorage.Azure.DataLake.Store/FluentStorage.Azure.DataLake.csproj b/FluentStorage.Azure.DataLake.Store/FluentStorage.Azure.DataLake.csproj index ee33e14..bd09d50 100644 --- a/FluentStorage.Azure.DataLake.Store/FluentStorage.Azure.DataLake.csproj +++ b/FluentStorage.Azure.DataLake.Store/FluentStorage.Azure.DataLake.csproj @@ -1,6 +1,6 @@  - netstandard2.0;netstandard2.1;net50;net60 + netstandard2.0;netstandard2.1;net70;net80;net90 https://github.com/aloneguid/storage/blob/master/LICENSE Extension to FluentStorage providing Azure Data Lake Store integration. Supports only ADLS Gen 1. To use Gen 2, use FluentStorage.Blobs package. FluentStorage.Azure.DataLake @@ -10,7 +10,7 @@ true logo-nuget.png Robin Rodricks, Ivan Gavryliuk, FluentStorage Contributors - 5.2.2 + 6.0.0 https://github.com/robinrodricks/FluentStorage https://github.com/robinrodricks/FluentStorage GitHub @@ -18,7 +18,9 @@ latest True ..\FluentStorage\sn.snk - bin\$(Configuration)\$(TargetFramework)\FluentStorage.Azure.DataLake.xml + $(SolutionDir)build\FluentStorage.Azure.DataLake.xml + $(SolutionDir)build\ + True diff --git a/FluentStorage.Azure.EventHub/FluentStorage.Azure.EventHub.csproj b/FluentStorage.Azure.EventHub/FluentStorage.Azure.EventHub.csproj index 9a1e714..e6418b9 100644 --- a/FluentStorage.Azure.EventHub/FluentStorage.Azure.EventHub.csproj +++ b/FluentStorage.Azure.EventHub/FluentStorage.Azure.EventHub.csproj @@ -1,6 +1,6 @@  - netstandard2.0;netstandard2.1;net50;net60 + netstandard2.0;netstandard2.1;net70;net80;net90 FluentStorage.Azure.EventHub FluentStorage.Azure.EventHub https://github.com/aloneguid/storage/blob/master/LICENSE @@ -11,7 +11,7 @@ true logo-nuget.png Robin Rodricks, Ivan Gavryliuk, FluentStorage Contributors - 5.2.2 + 6.0.0 https://github.com/robinrodricks/FluentStorage https://github.com/robinrodricks/FluentStorage GitHub @@ -19,7 +19,9 @@ latest True ..\FluentStorage\sn.snk - bin\$(Configuration)\$(TargetFramework)\FluentStorage.Azure.EventHub.xml + $(SolutionDir)build\FluentStorage.Azure.EventHub.xml + $(SolutionDir)build\ + True diff --git a/FluentStorage.Azure.Files/FluentStorage.Azure.Files.csproj b/FluentStorage.Azure.Files/FluentStorage.Azure.Files.csproj index 21e1f29..93e88e0 100644 --- a/FluentStorage.Azure.Files/FluentStorage.Azure.Files.csproj +++ b/FluentStorage.Azure.Files/FluentStorage.Azure.Files.csproj @@ -1,7 +1,7 @@  - netstandard2.0;netstandard2.1;net50;net60 + netstandard2.0;netstandard2.1;net70;net80;net90 FluentStorage.Azure.Files FluentStorage.Azure.Files Extension to FluentStorage providing Azure Storage Files support. @@ -9,7 +9,7 @@ true logo-nuget.png Robin Rodricks, Ivan Gavryliuk, FluentStorage Contributors - 5.2.2 + 6.0.0 https://github.com/robinrodricks/FluentStorage https://github.com/robinrodricks/FluentStorage GitHub @@ -17,7 +17,9 @@ latest True ..\FluentStorage\sn.snk - bin\$(Configuration)\$(TargetFramework)\FluentStorage.Azure.Files.xml + $(SolutionDir)build\FluentStorage.Azure.Files.xml + $(SolutionDir)build\ + diff --git a/FluentStorage.Azure.KeyVault/FluentStorage.Azure.KeyVault.csproj b/FluentStorage.Azure.KeyVault/FluentStorage.Azure.KeyVault.csproj index fd2e3cb..a047d25 100644 --- a/FluentStorage.Azure.KeyVault/FluentStorage.Azure.KeyVault.csproj +++ b/FluentStorage.Azure.KeyVault/FluentStorage.Azure.KeyVault.csproj @@ -1,6 +1,6 @@  - netstandard2.0;netstandard2.1;net50;net60 + netstandard2.0;netstandard2.1;net70;net80;net90 Extension to FluentStorage providing integration with Azure Key vault as blob storage. 1.0.0.0 1.0.0.0 @@ -12,7 +12,7 @@ true logo-nuget.png Robin Rodricks, Ivan Gavryliuk, FluentStorage Contributors - 5.2.2 + 6.0.0 https://github.com/robinrodricks/FluentStorage https://github.com/robinrodricks/FluentStorage GitHub @@ -20,7 +20,9 @@ latest True ..\FluentStorage\sn.snk - bin\$(Configuration)\$(TargetFramework)\FluentStorage.Azure.KeyVault.xml + $(SolutionDir)build\FluentStorage.Azure.KeyVault.xml + $(SolutionDir)build\ + True diff --git a/FluentStorage.Azure.Queues/FluentStorage.Azure.Queues.csproj b/FluentStorage.Azure.Queues/FluentStorage.Azure.Queues.csproj index 52ed1e1..5dfd9e7 100644 --- a/FluentStorage.Azure.Queues/FluentStorage.Azure.Queues.csproj +++ b/FluentStorage.Azure.Queues/FluentStorage.Azure.Queues.csproj @@ -1,14 +1,14 @@  - netstandard2.0;netstandard2.1;net50;net60 + netstandard2.0;netstandard2.1;net70;net80;net90 FluentStorage.Azure.Queues Extension to FluentStorage providing Azure Queue Storage as messaging storage. Copyright (c) 2023 Robin Rodricks and FluentStorage Contributors true logo-nuget.png Robin Rodricks, Ivan Gavryliuk, FluentStorage Contributors - 5.2.2 + 6.0.0 https://github.com/robinrodricks/FluentStorage https://github.com/robinrodricks/FluentStorage GitHub @@ -16,7 +16,9 @@ latest True ..\FluentStorage\sn.snk - bin\$(Configuration)\$(TargetFramework)\FluentStorage.Azure.Queues.xml + $(SolutionDir)build\FluentStorage.Azure.Queues.xml + $(SolutionDir)build\ + diff --git a/FluentStorage.Azure.ServiceBus/FluentStorage.Azure.ServiceBus.csproj b/FluentStorage.Azure.ServiceBus/FluentStorage.Azure.ServiceBus.csproj index 9876525..b99cfaf 100644 --- a/FluentStorage.Azure.ServiceBus/FluentStorage.Azure.ServiceBus.csproj +++ b/FluentStorage.Azure.ServiceBus/FluentStorage.Azure.ServiceBus.csproj @@ -1,6 +1,6 @@  - netstandard2.0;netstandard2.1;net50;net60 + netstandard2.0;netstandard2.1;net70;net80;net90 FluentStorage.Azure.ServiceBus FluentStorage.Azure.ServiceBus 1.0.0.0 @@ -13,7 +13,7 @@ true logo-nuget.png Robin Rodricks, Ivan Gavryliuk, Giampaolo Gabba, FluentStorage Contributors - 6.0.1 + 6.0.2 https://github.com/robinrodricks/FluentStorage https://github.com/robinrodricks/FluentStorage GitHub @@ -21,7 +21,9 @@ latest True ..\FluentStorage\sn.snk - bin\$(Configuration)\$(TargetFramework)\FluentStorage.Azure.ServiceBus.xml + $(SolutionDir)build\FluentStorage.Azure.ServiceBus.xml + $(SolutionDir)build\ + True diff --git a/FluentStorage.Azure.ServiceFabric/FluentStorage.Azure.ServiceFabric.csproj b/FluentStorage.Azure.ServiceFabric/FluentStorage.Azure.ServiceFabric.csproj index d10e15e..0b13725 100644 --- a/FluentStorage.Azure.ServiceFabric/FluentStorage.Azure.ServiceFabric.csproj +++ b/FluentStorage.Azure.ServiceFabric/FluentStorage.Azure.ServiceFabric.csproj @@ -1,6 +1,6 @@  - netstandard2.0;netstandard2.1;net50;net60 + netstandard2.0;netstandard2.1;net70;net80;net90 https://github.com/aloneguid/storage/blob/master/LICENSE 2.6.204.0 2.0.0.0 @@ -13,7 +13,7 @@ true logo-nuget.png Robin Rodricks, Ivan Gavryliuk, FluentStorage Contributors - 5.2.2 + 6.0.0 https://github.com/robinrodricks/FluentStorage https://github.com/robinrodricks/FluentStorage GitHub @@ -21,7 +21,9 @@ latest True ..\FluentStorage\sn.snk - bin\$(Configuration)\$(TargetFramework)\FluentStorage.Azure.ServiceFabric.xml + $(SolutionDir)build\FluentStorage.Azure.ServiceFabric.xml + $(SolutionDir)build\ + True diff --git a/FluentStorage.Databricks/FluentStorage.Databricks.csproj b/FluentStorage.Databricks/FluentStorage.Databricks.csproj index 43d940a..52c51fd 100644 --- a/FluentStorage.Databricks/FluentStorage.Databricks.csproj +++ b/FluentStorage.Databricks/FluentStorage.Databricks.csproj @@ -1,7 +1,7 @@  - netstandard2.0;netstandard2.1;net50;net60 + netstandard2.0;netstandard2.1;net70;net80;net90 FluentStorage.Databricks Extension to FluentStorage providing Databricks integration, including DBFS, secrets, clusters, workbooks and so on. Azure and AWS are fully supported. FluentStorage.Databricks @@ -10,7 +10,7 @@ true logo-nuget.png Robin Rodricks, Ivan Gavryliuk, FluentStorage Contributors - 5.2.2 + 6.0.0 https://github.com/robinrodricks/FluentStorage https://github.com/robinrodricks/FluentStorage GitHub @@ -18,7 +18,9 @@ latest True ..\FluentStorage\sn.snk - bin\$(Configuration)\$(TargetFramework)\FluentFTP.xml + $(SolutionDir)build\FluentFTP.xml + $(SolutionDir)build\ + diff --git a/FluentStorage.FTP/FluentStorage.FTP.csproj b/FluentStorage.FTP/FluentStorage.FTP.csproj index 208ddc0..8ad1c26 100644 --- a/FluentStorage.FTP/FluentStorage.FTP.csproj +++ b/FluentStorage.FTP/FluentStorage.FTP.csproj @@ -1,7 +1,7 @@  - netstandard2.0;netstandard2.1;net50;net60 + netstandard2.0;netstandard2.1;net70;net80;net90 Extension to FluentStorage providing FTP and FTPS support using FluentFTP. FluentStorage.FTP FluentStorage.FTP @@ -10,7 +10,7 @@ true logo-nuget.png Robin Rodricks, Ivan Gavryliuk, FluentStorage Contributors - 5.4.0 + 6.0.0 https://github.com/robinrodricks/FluentStorage https://github.com/robinrodricks/FluentStorage GitHub @@ -18,11 +18,13 @@ latest True ..\FluentStorage\sn.snk - bin\$(Configuration)\$(TargetFramework)\FluentStorage.FTP.xml + $(SolutionDir)build\FluentStorage.FTP.xml + $(SolutionDir)build\ + - + diff --git a/FluentStorage.GCP/FluentStorage.GCP.csproj b/FluentStorage.GCP/FluentStorage.GCP.csproj index 8c487a0..4449384 100644 --- a/FluentStorage.GCP/FluentStorage.GCP.csproj +++ b/FluentStorage.GCP/FluentStorage.GCP.csproj @@ -1,7 +1,7 @@  - netstandard2.0;netstandard2.1;net50;net60 + netstandard2.0;netstandard2.1;net70;net80;net90 FluentStorage.GCP FluentStorage.GCP FluentStorage.GCP @@ -10,7 +10,7 @@ true logo-nuget.png Robin Rodricks, Ivan Gavryliuk, FluentStorage Contributors - 5.3.0 + 6.0.0 https://github.com/robinrodricks/FluentStorage https://github.com/robinrodricks/FluentStorage GitHub @@ -18,7 +18,9 @@ latest True ..\FluentStorage\sn.snk - bin\$(Configuration)\$(TargetFramework)\FluentStorage.GCP.xml + $(SolutionDir)build\FluentStorage.GCP.xml + $(SolutionDir)build\ + diff --git a/FluentStorage.SFTP/FluentStorage.SFTP.csproj b/FluentStorage.SFTP/FluentStorage.SFTP.csproj index 09db995..c505b3e 100644 --- a/FluentStorage.SFTP/FluentStorage.SFTP.csproj +++ b/FluentStorage.SFTP/FluentStorage.SFTP.csproj @@ -1,7 +1,7 @@  - netstandard2.0;netstandard2.1;net50;net60 + netstandard2.0;netstandard2.1;net70;net80;net90 Extension to FluentStorage providing SFTP support using SSH.NET. FluentStorage.SFTP FluentStorage.SFTP @@ -10,7 +10,7 @@ true logo-nuget.png Robin Rodricks, Ivan Gavryliuk, FluentStorage Contributors - 5.3.1 + 6.0.0 https://github.com/robinrodricks/FluentStorage https://github.com/robinrodricks/FluentStorage GitHub @@ -18,12 +18,14 @@ latest True ..\FluentStorage\sn.snk - bin\$(Configuration)\$(TargetFramework)\FluentStorage.SFTP.xml + $(SolutionDir)build\FluentStorage.SFTP.xml + $(SolutionDir)build\ + - + diff --git a/FluentStorage.Tests.Console/FluentStorage.Tests.Console.csproj b/FluentStorage.Tests.Console/FluentStorage.Tests.Console.csproj index 15b37b7..b4b8d39 100644 --- a/FluentStorage.Tests.Console/FluentStorage.Tests.Console.csproj +++ b/FluentStorage.Tests.Console/FluentStorage.Tests.Console.csproj @@ -2,7 +2,7 @@ Exe - net60 + net90 diff --git a/FluentStorage.Tests.FTP/FluentStorage.Tests.FTP.csproj b/FluentStorage.Tests.FTP/FluentStorage.Tests.FTP.csproj index 5551aeb..fdbd89b 100644 --- a/FluentStorage.Tests.FTP/FluentStorage.Tests.FTP.csproj +++ b/FluentStorage.Tests.FTP/FluentStorage.Tests.FTP.csproj @@ -1,7 +1,7 @@ - net6.0 + net9.0 enable enable diff --git a/FluentStorage.Tests.Integration/FluentStorage.Tests.Integration.csproj b/FluentStorage.Tests.Integration/FluentStorage.Tests.Integration.csproj index e9b3f74..5c149dc 100644 --- a/FluentStorage.Tests.Integration/FluentStorage.Tests.Integration.csproj +++ b/FluentStorage.Tests.Integration/FluentStorage.Tests.Integration.csproj @@ -1,7 +1,7 @@  - net6.0 + net9.0 latest diff --git a/FluentStorage.Tests/FluentStorage.Tests.csproj b/FluentStorage.Tests/FluentStorage.Tests.csproj index 55d6a0e..0458d7d 100644 --- a/FluentStorage.Tests/FluentStorage.Tests.csproj +++ b/FluentStorage.Tests/FluentStorage.Tests.csproj @@ -1,6 +1,6 @@  - net6.0 + net9.0 FluentStorage.Tests latest diff --git a/FluentStorage/FluentStorage.csproj b/FluentStorage/FluentStorage.csproj index a9da8d9..c1b5bfe 100644 --- a/FluentStorage/FluentStorage.csproj +++ b/FluentStorage/FluentStorage.csproj @@ -1,7 +1,7 @@  FluentStorage - netstandard2.0;netstandard2.1;net50;net60 + netstandard2.0;netstandard2.1;net70;net80;net90 FluentStorage FluentStorage FluentStorage, originally known as Storage.NET, is a polycloud .NET cloud storage library to interface with multiple cloud providers from a single unified interface. Provides Blob storage (AWS S3, GCP, FTP, SFTP, Azure Blob/File/Event Hub/Data Lake) and Messaging (AWS SQS, Azure Queue/ServiceBus). Supports .NET 5+ and .NET Standard 2.0+. Pure C#. MIT license. Commercial use allowed. @@ -9,7 +9,7 @@ true logo-nuget.png Robin Rodricks, Ivan Gavryliuk, FluentStorage Contributors - 5.6.0 + 6.0.0 https://github.com/robinrodricks/FluentStorage https://github.com/robinrodricks/FluentStorage GitHub @@ -17,7 +17,9 @@ latest True sn.snk - bin\$(Configuration)\$(TargetFramework)\FluentStorage.xml + $(SolutionDir)build\FluentStorage.xml + $(SolutionDir)build\ + True diff --git a/RELEASES.md b/RELEASES.md index 1af2b39..066ce2e 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,5 +1,36 @@ # Release Notes +#### FluentStorage 6.0.0 + + - **FluentStorage** + - Allow setting text content when writing dummy files + - Update `TestableIO` packages due to binary incompatibility + - Respect `createIfNotExists` in `GetFilePath` and prevent unintended directory creation + - **FluentStorage.Azure.Blobs** + - Allow passing `BlobClientOptions` + - Update `OpenReadAsync` to use `OpenReadAsync` from Azure SDK + - `OpenReadAsync` for efficient streaming over `DownloadAsync` + - Minimise platform dependencies + - Update `Azure.Identity` Nuget package to latest versions + - **FluentStorage.Azure.DataLake.Store** + - Update `Microsoft` Nuget package to latest versions + - **FluentStorage.AWS** + - Allow passing the Protocol property to the `PresignedRequest` + - Use `ContentType` when setting AWS Metadata + - Handle response with null S3 objects + - Update AWS Nuget packages from v3.7 to v4.0 + - **FluentStorage.Tests** + - Upgrade projects from NET 6 to NET 9 + - **FluentStorage.FTP** + - Upgrade FluentFTP to the latest version 53.0.1 + - **FluentStorage.SFTP** + - Upgrade SSH.NET to the latest version 2025.0.0 + - **All projects** + - Reduce .NET platform Nuget dependencies + - Drop support for `net50`,`net60` + - Add support for `net70`,`net80`,`net90` + - Cleanup folder structure and add a common `build` folder for all projects + #### FluentStorage 5.6.0 - Fix: Update to latest `Microsoft.IO.RecyclableMemoryStream` package (thanks @dammitjanet) - New: Use `IFileSystem` package to improve testability of `DiskDirectoryBlobStorage` (thanks @gerrewsb) From 9781afedee305e1c6a63c90d90b29a3d9b35418c Mon Sep 17 00:00:00 2001 From: Robin Rodricks Date: Fri, 3 Oct 2025 16:15:00 +0530 Subject: [PATCH 4/8] fix logo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6efe3ae..691ed1a 100644 --- a/README.md +++ b/README.md @@ -187,7 +187,7 @@ FluentStorage has received major sponsorship from these generous organizations: - Microsoft Corporation + Microsoft Corporation From 485fa282a74130b82a8197eaa9cad66df44d9b4d Mon Sep 17 00:00:00 2001 From: Robin Rodricks Date: Mon, 20 Oct 2025 16:23:10 +0530 Subject: [PATCH 5/8] fix nullref at AWS ListAsync --- FluentStorage.AWS/Blobs/AwsS3DirectoryBrowser.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/FluentStorage.AWS/Blobs/AwsS3DirectoryBrowser.cs b/FluentStorage.AWS/Blobs/AwsS3DirectoryBrowser.cs index 635a018..343b50a 100644 --- a/FluentStorage.AWS/Blobs/AwsS3DirectoryBrowser.cs +++ b/FluentStorage.AWS/Blobs/AwsS3DirectoryBrowser.cs @@ -25,7 +25,7 @@ public async Task> ListAsync(ListOptions options, Canc var container = new List(); _limiter = new AsyncLimiter(options.NumberOfRecursionThreads ?? ListOptions.MAX_THREADS); - + await ListFolderAsync(container, options.FolderPath, options, cancellationToken).ConfigureAwait(false); return options.MaxResults == null @@ -57,10 +57,13 @@ private async Task ListFolderAsync(List container, string path, ListOption response = await _client.ListObjectsV2Async(request, cancellationToken).ConfigureAwait(false); } - folderContainer.AddRange(response.ToBlobs(options)); + if (response != null) { + folderContainer.AddRange(response.ToBlobs(options)); + } - if (response.NextContinuationToken == null) + if (response.NextContinuationToken == null) { break; + } request.ContinuationToken = response.NextContinuationToken; } @@ -113,4 +116,4 @@ public void Dispose() { _limiter?.Dispose(); } } -} +} \ No newline at end of file From bfcaf073060ceebdb127cd68c40cf8020dc11fb2 Mon Sep 17 00:00:00 2001 From: Robin Rodricks Date: Mon, 20 Oct 2025 16:23:14 +0530 Subject: [PATCH 6/8] FluentStorage 6.0.1 --- FluentStorage.AWS/FluentStorage.AWS.csproj | 2 +- RELEASES.md | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/FluentStorage.AWS/FluentStorage.AWS.csproj b/FluentStorage.AWS/FluentStorage.AWS.csproj index 6168eb2..bab510d 100644 --- a/FluentStorage.AWS/FluentStorage.AWS.csproj +++ b/FluentStorage.AWS/FluentStorage.AWS.csproj @@ -9,7 +9,7 @@ true logo-nuget.png Robin Rodricks, Ivan Gavryliuk, FluentStorage Contributors - 6.0.0 + 6.0.1 https://github.com/robinrodricks/FluentStorage https://github.com/robinrodricks/FluentStorage GitHub diff --git a/RELEASES.md b/RELEASES.md index 066ce2e..6503ecc 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,5 +1,9 @@ # Release Notes +#### FluentStorage 6.0.1 + - **FluentStorage.AWS** + - Fix: Null Exception at `ListAsync` + #### FluentStorage 6.0.0 - **FluentStorage** From fc9960217a5d1fb03617cd556f585525a42c64b2 Mon Sep 17 00:00:00 2001 From: Nattapong Nunpan Date: Thu, 28 Aug 2025 15:21:31 +0700 Subject: [PATCH 7/8] set Content-Type based on file extension - Modified WriteAsync to detect MIME type from blob path using _mime.TryGetContentType - Falls back to "application/octet-stream" when no mapping is found - Uses BlobUploadOptions with BlobHttpHeaders to ensure Content-Type is stored - Fixes issue where browsers download images instead of rendering inline --- FluentStorage.Azure.Blobs/AzureBlobStorage.cs | 13 +++++++++++++ .../FluentStorage.Azure.Blobs.csproj | 1 + 2 files changed, 14 insertions(+) diff --git a/FluentStorage.Azure.Blobs/AzureBlobStorage.cs b/FluentStorage.Azure.Blobs/AzureBlobStorage.cs index fb040c6..1eac877 100644 --- a/FluentStorage.Azure.Blobs/AzureBlobStorage.cs +++ b/FluentStorage.Azure.Blobs/AzureBlobStorage.cs @@ -14,6 +14,7 @@ using Azure.Storage.Sas; using Blobs; using Microsoft.Identity.Client; +using Microsoft.AspNetCore.StaticFiles; using FluentStorage.Blobs; using FluentStorage.Azure.Blobs.Gen2.Model; @@ -28,6 +29,8 @@ class AzureBlobStorage : IAzureBlobStorage { private readonly string _containerName; private readonly ConcurrentDictionary _containerNameToContainerClient = new ConcurrentDictionary(); + private static readonly FileExtensionContentTypeProvider _mime = + new FileExtensionContentTypeProvider(); public AzureBlobStorage( BlobServiceClient blobServiceClient, @@ -129,9 +132,19 @@ public async Task WriteAsync(string fullPath, Stream dataStream, BlockBlobClient client = container.GetBlockBlobClient(path); + string contentType; + if (!_mime.TryGetContentType(path, out contentType)) { + contentType = "application/octet-stream"; + } try { + var options = new BlobUploadOptions { + HttpHeaders = new BlobHttpHeaders { + ContentType = contentType + } + }; await client.UploadAsync( new StorageSourceStream(dataStream), + options: options, cancellationToken: cancellationToken).ConfigureAwait(false); } catch (RequestFailedException ex) when (ex.ErrorCode == "OperationNotAllowedInCurrentState") { diff --git a/FluentStorage.Azure.Blobs/FluentStorage.Azure.Blobs.csproj b/FluentStorage.Azure.Blobs/FluentStorage.Azure.Blobs.csproj index 363923e..5226849 100644 --- a/FluentStorage.Azure.Blobs/FluentStorage.Azure.Blobs.csproj +++ b/FluentStorage.Azure.Blobs/FluentStorage.Azure.Blobs.csproj @@ -31,6 +31,7 @@ + From 7dd21dd1b94d5304f01404edf066a3133ac27dab Mon Sep 17 00:00:00 2001 From: Nattapong Nunpan Date: Mon, 17 Nov 2025 20:05:03 +0700 Subject: [PATCH 8/8] Replace StaticFiles with MimeMapping for MIME type detection Switched from Microsoft.AspNetCore.StaticFiles to MimeMapping for determining MIME types in AzureBlobStorage. Updated the project dependencies and refactored code to use MimeUtility.GetMimeMapping instead of FileExtensionContentTypeProvider. --- FluentStorage.Azure.Blobs/AzureBlobStorage.cs | 9 ++------- .../FluentStorage.Azure.Blobs.csproj | 2 +- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/FluentStorage.Azure.Blobs/AzureBlobStorage.cs b/FluentStorage.Azure.Blobs/AzureBlobStorage.cs index 1eac877..f3f5d48 100644 --- a/FluentStorage.Azure.Blobs/AzureBlobStorage.cs +++ b/FluentStorage.Azure.Blobs/AzureBlobStorage.cs @@ -14,7 +14,7 @@ using Azure.Storage.Sas; using Blobs; using Microsoft.Identity.Client; -using Microsoft.AspNetCore.StaticFiles; +using MimeMapping; using FluentStorage.Blobs; using FluentStorage.Azure.Blobs.Gen2.Model; @@ -29,8 +29,6 @@ class AzureBlobStorage : IAzureBlobStorage { private readonly string _containerName; private readonly ConcurrentDictionary _containerNameToContainerClient = new ConcurrentDictionary(); - private static readonly FileExtensionContentTypeProvider _mime = - new FileExtensionContentTypeProvider(); public AzureBlobStorage( BlobServiceClient blobServiceClient, @@ -132,10 +130,7 @@ public async Task WriteAsync(string fullPath, Stream dataStream, BlockBlobClient client = container.GetBlockBlobClient(path); - string contentType; - if (!_mime.TryGetContentType(path, out contentType)) { - contentType = "application/octet-stream"; - } + string contentType = MimeUtility.GetMimeMapping(path); try { var options = new BlobUploadOptions { HttpHeaders = new BlobHttpHeaders { diff --git a/FluentStorage.Azure.Blobs/FluentStorage.Azure.Blobs.csproj b/FluentStorage.Azure.Blobs/FluentStorage.Azure.Blobs.csproj index 5226849..94a842b 100644 --- a/FluentStorage.Azure.Blobs/FluentStorage.Azure.Blobs.csproj +++ b/FluentStorage.Azure.Blobs/FluentStorage.Azure.Blobs.csproj @@ -31,7 +31,7 @@ - +