Skip to content

Migration Guide

Robin Rodricks edited this page Jul 30, 2026 · 130 revisions

Migrating from FluentStorage v7 to v8+

Rationale

FluentStorage is the successor of Storage.NET, which had many systemic design and architectural issues since I took over the project in 2021. The community that gathered around FluentStorage added a few features over the years, but the API has stayed in mostly the same shape. The library was also very limited, and only offered basic read/write functionality for storage providers, with a focus on Azure. GCP and S3 were an afterthought, and were implemented in a partial, inconsistent and unsatisfactory manner.

In 2026, the scenario has changed. With the world moving onto the cloud, we need a cloud-first approach. We also need an API surface that can unify the needs of AWS, Azure, GCP, and all other cloud storage providers, in addition to offering compatibility with disk based systems like FTP and SFTP.

In this release my goals were:

  1. Redesign the API surface to offer a unified API across all major cloud providers
  2. Add all of the popular cloud storage providers
  3. Add all the "missing" APIs to make this library actually functional in complex projects
  4. Fix broken logic and the broken path system
  5. Fix technical debt by dropping old providers and outdated concepts
  6. Modernize the codebase
  7. Improve code organization
  8. Improve automated tests

Instead of making multiple releases with constant breaking API changes, I decided to roll this into a single large release. v8 is the culmination of all of the above goals.

Overview

  1. New factory API
    • All extension-method factory API has been removed: For example StorageFactory.Blobs and StorageFactory.Messages no longer exist.
    • Factory classes have been introduced on a per-provided basis.
    • Factory classes can be accessed directly to construct new IStore objects: For example StorageFactory.Blobs.AwsS3 is now AwsS3Storage.FromCredentials.
  2. Redesigned API
    • All methods are async and the "Async" suffix has been dropped.
    • All methods have an optional CancellationToken rather than forcing users to provide one.
    • Collections returned by APIs will always be List instead of IReadOnlyCollection.
    • StoragePath has been completely rewritten to offer a unified path system across all disk and cloud stores
    • GetClient() now consistently returns the internal cloud SDK client (Replaces NativeBlobClient).
  3. Behaviour changes in core API
    • At initialization, S3-compatible stores will no longer create the bucket if the specified bucket does not exist. FluentStorage is not an IaC framework and this "feature" has been troublesome for many cloud storage providers.
    • WriteAsync() is renamed to SetObject() and will auto compute the object's MIME type (Content-Type) if it is not supplied.
    • GetPresignedUrl() and its variations will auto compute the object's MIME type (Content-Type).
    • CreateDirectory() will no longer create a "dummy file" in a cloud storage bucket.
    • RenameAsync() is renamed to MoveObject() and will no longer perform a recursive copy and delete, instead it will efficiently move the object/file from the old path to the new path only if it exists.
    • ExistsAsync() is renamed to ObjectExists() and will consistently return true/false if the file or folder exists on the bucket/server.
    • DeleteAsync() is renamed to DeleteObject() and will consistently delete a single file or folder from the bucket/server.
    • DeleteObjects() will consistently delete multiple files or folders from the bucket/server.
    • DeleteObject will no longer delete objects from a virtual directory, use DeleteDirectory() for that.
    • GetObjectMD5 is removed and replaced with GetObjectChecksum that allows many more hashing algorithms.
  4. New providers added
  5. New features added
  6. Outdated providers removed
  7. Improved automated tests
    • Add YAML based configuration for automated test suite
    • Merge all tests into a single project, cleanly seperating unit and integration tests
    • New tests for path normalization, path combination and path splitting
    • New tests for SeekableStream used in seeking/streaming
    • New tests for IStore operations and fixes made to local disk implementation
  8. Code organization
    • Exceptions are moved into the FluentStorage.Exceptions namespace
    • Enums are moved into the FluentStorage.Enums namespace
    • Model objects are moved into the FluentStorage.Model namespace
    • Data sinks are moved into the FluentStorage.Sinks namespace
    • Streams are moved into the FluentStorage.Streaming namespace

Migration steps

  1. Add these imports into code that uses FluentStorage:
using FluentStorage.Enums;
using FluentStorage.Exceptions;
using FluentStorage.Model;
  1. Find and replace the most common terms:
Find Replace
StorageFactory.Blobs.FromConnectionString StorageFactory.FromConnectionString
StorageFactory.Blobs.DirectoryFiles StorageFactory.Disk
StorageFactory.Blobs.AwsS3 AwsS3Storage.FromCredentials
FluentStorage.AWS.Blobs FluentStorage.AWS.Storage
IBlobStorage IStore
IHierarchicalBlobStorage IStore
IExtendedBlobStorage IStore
IAzureBlobStorage IAzureBlobStore
IMessenger IQueue
  1. Switch to the new factory classes instead of using StorageFactory.Blobs.
  2. Delete the suffix "Async" from all API method calls.

Major new API

New factory classes per provider

  • AwsS3Storage
  • AwsSqsStorage
  • BackblazeB2Storage
  • CloudflareR2Storage
  • DigitalOceanSpacesStorage
  • HetznerStorage
  • VultrStorage
  • WasabiStorage
  • AzureBlobStore
  • AzureDataLakeStorage
  • AzureFilesStorage
  • AzureKeyVaultStorage
  • AzureQueueStorage
  • AzureServiceBus
  • GoogleCloudStorage
  • MinioStorage
  • MinioS3Storage
  • AlibabaStorage
  • FtpStorage
  • SftpStorage

New FTP/SFTP API

  • Server info
    • GetServer
  • Directory manipulation
    • CreateDirectory
    • DeleteDirectory
    • DirectoryExists
    • MoveDirectory
    • UploadDirectory
    • DownloadDirectory
  • File manipulation
    • MoveObject
    • DownloadObject
    • UploadObject
    • GetBytes
    • SetBytes
    • GetFilePermissions
    • SetFilePermissions
  • File hashing
    • GetObjectChecksum

New bucket API

  • Client info
    • GetClient
  • File seeking/streaming
    • OpenSeekable
    • OpenRange
    • GetObjectLength
  • File manipulation
    • MoveObject
    • DownloadObject
    • UploadObject
    • OpenRead
    • OpenWrite
  • Directory manipulation
    • CreateDirectory (NOP)
    • DeleteDirectory
    • DirectoryExists
    • UploadDirectory
    • DownloadDirectory
  • Presigned URL generation
    • GetUploadUrl
    • GetDownloadUrl
    • GetPresignedUrl (S3 friendly)
    • GetObjectSas (Azure friendly)
  • Object versioning
    • IsVersioned
    • ListObjectVersions
    • GetObjectVersion
    • RestoreObjectVersion
    • DeleteObjectVersion
  • Object tagging
    • IsTagged
    • GetObjectTags
    • SetObjectTags
    • DeleteObjectTags
  • Object storage tiers
    • IsTiered
    • GetObjectTier
    • SetObjectTier
  • Object hashing
    • GetObjectChecksum

Renamed API

The entire FluentStorage API surface was redesigned from scratch to keep it meaningful, simple and consistent.

Old Class New Class Notes
Blob StoreObject "Object" is the most common terminology across all providers
IBlobStorage IStore "Bucket" is the most common terminology across all providers
IHierarchicalBlobStorage IStore
IExtendedBlobStorage IStore
IAzureBlobStorage IAzureBlobStore "Store" terminology
IAzureDataLakeStorage IAzureDataLakeStore "Store" terminology
IMessenger IQueue "Queue" is the most common terminology across all providers
IMessageReceiver IQueueReceiver
IMessageProcessor IQueueProcessor
IAzureServiceBusMessenger IAzureServiceBus
InMemoryBlobStorage MemoryStore For simplicity
InMemoryMessenger MemoryMessenger For simplicity
StorageConnectionString ConnectionString For consistency
KnownPrefix ConnectionStringPrefix For consistency
KnownParameter ConnectionStringParam For consistency
RecursionMode StorageRecursion For consistency
BlobItemKind StorageObjectType For consistency
ErrorCode StorageErrorCode For consistency
ListOptions StorageListOptions For consistency
Old Static API New Static API Notes
StorageFactory.Modules.UseAwsStorage AwsStorage.Use For connection strings
StorageFactory.Modules.UseAzureBlobStorage AzureBlobStorage.Use For connection strings
StorageFactory.Modules.UseAzureFilesStorage AzureFilesStorage.Use For connection strings
StorageFactory.Modules.UseAzureKeyVault AzureKeyVaultStorage.Use For connection strings
StorageFactory.Modules.UseAzureQueues AzureQueueStorage.Use For connection strings
StorageFactory.Modules.UseFtpStorage FtpStorage.Use For connection strings
StorageFactory.Modules.UseSftpStorage SftpStorage.Use For connection strings
StorageFactory.Modules.UseGoogleCloudStorage GoogleCloudStorage.Use For connection strings
StorageFactory.Blobs.AzureBlob* AzureBlobStorage.From...
StorageFactory.Blobs.AzureFiles* AzureFilesStorage.From...
StorageFactory.Blobs.AzureDataLake* AzureDataLakeStorage.From...
StorageFactory.Blobs.AzureKeyVault* AzureKeyVaultStorage.From...
StorageFactory.Messages.AzureStorageQueue* AzureQueueStorage.From...
StorageFactory.Messages.AzureServiceBus* AzureServiceBus.From...
StorageFactory.Blobs.GoogleCloud* GoogleCloudStorage.From...
StorageFactory.Blobs.AwsS3* AwsS3Storage.From...
StorageFactory.Messages.AwsSQS* AwsSqsStorage.From...
StorageFactory.Blobs.MinIO MinIOStorage.From...
StorageFactory.Blobs.Wasabi WasabiStorage.From...
StorageFactory.Blobs.DigitalOceanSpaces DigitalOceanSpacesStorage.From...
StorageFactory.Blobs.BackblazeB2 BackblazeB2Storage.From...
StorageFactory.Blobs.CloudflareR2 CloudflareR2Storage.From...
StorageFactory.Blobs.Vultr VultrStorage.From...
StorageFactory.Blobs.Hetzner HetznerStorage.From...
StorageFactory.Blobs.Ftp FtpStorage.From...
StorageFactory.Blobs.Sftp SftpStorage.From...
StorageFactory.Blobs.FromConnectionString StorageFactory.FromConnectionString
StorageFactory.Blobs.DirectoryFiles StorageFactory.Disk
StorageFactory.Blobs.InMemory StorageFactory.InMemory
StorageFactory.Messages.MessengerFromConnectionString QueueFactory.FromConnectionString
StorageFactory.Messages.Disk QueueFactory.Disk
StorageFactory.Messages.InMemory QueueFactory.InMemory
Old Dynamic API New Dynamic API Notes
Blob.Kind StorageObject.Type Improved term
Blob.CreatedTime StorageObject.DateCreated "Time" is a misnomer
Blob.LastModificationTime StorageObject.DateModified "Time" is a misnomer
IBlobStorage.ListAsync IStore.ListObjects "Async" removed
IBlobStorage.ListDirectoryAsync IStore.ListDirectory
IBlobStorage.ListFilesAsync IStore.ListFiles
IBlobStorage.ExistsAsync IStore.ObjectExists
IBlobStorage.GetBlobAsync IStore.GetObjectInfo
IBlobStorage.GetBlobsAsync IStore.GetObjectsInfo
IBlobStorage.SetBlobAsync IStore.SetObjectInfo
IBlobStorage.SetBlobsAsync IStore.SetObjectsInfo
IBlobStorage.GetMD5HashAsync IStore.GetObjectChecksum(..., StorageHash.MD5)
IBlobStorage.OpenReadAsync IStore.OpenRead
IBlobStorage.ReadToStreamAsync IStore.GetObject
IBlobStorage.ReadBytesAsync IStore.GetBytes
IBlobStorage.ReadTextAsync IStore.GetText
IBlobStorage.ReadJsonAsync IStore.GetJson
IBlobStorage.ReadToFileAsync IStore.DownloadObject
IBlobStorage.WriteAsync IStore.SetObject / IStore.SetBytes
IBlobStorage.WriteTextAsync IStore.SetText
IBlobStorage.WriteJsonAsync IStore.SetJson
IBlobStorage.WriteFileAsync IStore.UploadObject
IBlobStorage.CopyToAsync IStore.CopyObjectToBucket
IBlobStorage.RenameAsync IStore.RenameObject
IBlobStorage.DeleteAsync IStore.DeleteObject / IStore.DeleteObjects
IBlobStorage.CreateFolderAsync IStore.CreateDirectory
IQueue.CreateChannelsAsync IQueue.CreateChannels "Async" removed
IQueue.ListChannelsAsync IQueue.ListChannels
IQueue.DeleteChannelsAsync IQueue.DeleteChannels
IQueue.GetMessageCountAsync IQueue.GetMessageCount
IQueue.SendAsync IQueue.SendMessages
IQueue.ReceiveAsync IQueue.ReceiveMessages
IQueue.PeekAsync IQueue.PeekMessages
IQueue.DeleteAsync IQueue.DeleteMessages
IQueue.StartMessageProcessorAsync IQueue.StartMessageProcessor
IQueue.SendAsync IQueue.SendMessage
IQueue.CreateChannelAsync IQueue.CreateChannel
IQueue.DeleteChannelAsync IQueue.DeleteChannel
IAzureBlobStorage.AcquireLeaseAsync IAzureBlobStore.AcquireLease "Async" removed
IAzureBlobStorage.BreakLeaseAsync IAzureBlobStore.BreakLease
IAzureBlobStorage.GetContainerPublicAccessAsync IAzureBlobStore.GetContainerPublicAccess
IAzureBlobStorage.SetContainerPublicAccessAsync IAzureBlobStore.SetContainerPublicAccess
IAzureBlobStorage.GetStorageSasAsync IAzureBlobStore.GetStorageSas
IAzureBlobStorage.GetContainerSasAsync IAzureBlobStore.GetContainerSas
IAzureBlobStorage.GetBlobSasAsync IAzureBlobStore.GetBlobSas
IAzureServiceBusMessenger.SendToQueueAsync IAzureServiceBus.SendToQueue "Async" removed
IAzureServiceBusMessenger.SendToTopicAsync IAzureServiceBus.SendToTopic
IAzureServiceBusMessenger.SendToSubscriptionAsync IAzureServiceBus.SendToSubscription
IAzureServiceBusMessenger.CreateQueueAsync IAzureServiceBus.CreateQueue
IAzureServiceBusMessenger.CreateTopicAsync IAzureServiceBus.CreateTopic
IAzureServiceBusMessenger.CreateSubScriptionAsync IAzureServiceBus.CreateSubscription
IAzureServiceBusMessenger.DeleteQueueAsync IAzureServiceBus.DeleteQueue
IAzureServiceBusMessenger.DeleteSubScriptionAsync IAzureServiceBus.DeleteSubscription
IAzureServiceBusMessenger.DeleteTopicAsync IAzureServiceBus.DeleteTopic
IAzureServiceBusMessenger.CountQueueAsync IAzureServiceBus.CountQueue
IAzureServiceBusMessenger.CountSubScriptionAsync IAzureServiceBus.CountSubscription
IAzureServiceBusMessenger.CountTopicAsync IAzureServiceBus.CountTopic
IAzureDataLakeStorage.ListFilesystemsAsync IAzureDataLakeStore.ListFilesystems "Async" removed
IAzureDataLakeStorage.CreateFilesystemAsync IAzureDataLakeStore.CreateFilesystem
IAzureDataLakeStorage.DeleteFilesystemAsync IAzureDataLakeStore.DeleteFilesystem
IAzureDataLakeStorage.SetAccessControlAsync IAzureDataLakeStore.SetAccessControl
IQueueProcessor.ProcessMessagesAsync IAzureDataLakeStore.ProcessMessages
IQueueProcessor.ProcessMessagesAsync IAzureDataLakeStore.ProcessMessages
IQueueReceiver.GetMessageCountAsync IQueueReceiver.GetMessageCount "Async" removed
IQueueReceiver.ConfirmMessagesAsync IQueueReceiver.ConfirmMessages
IQueueReceiver.DeadLetterAsync IQueueReceiver.DeadLetterMessage
IQueueReceiver.PeekMessagesAsync IQueueReceiver.PeekMessages
IQueueReceiver.StartMessagePumpAsync IQueueReceiver.StartMessagePump
IQueueReceiver.KeepAliveAsync IQueueReceiver.KeepAlive
Old Namespace New Namespace
FluentStorage.AWS.Blobs FluentStorage.AWS.Storage
FluentStorage.Azure.Blobs.Gen2.Model FluentStorage.Azure.Blobs.DataLake.Model
FluentStorage.Gcp.CloudStorage FluentStorage.GCP

Deleted API

We have deleted less used functionality to reduce bloat and help focus on our priority offering.

Deleted API Reason
StoragePath Following functions deleted: ComparePath, RemoveRootFolder, GetRootFolder, Rename
ITransaction Transactions were never implemented so this was dead API
EmptyTransaction Transactions were never implemented so this was dead API
VirtualStorage Virtual storage is out of scope and removed
IVirtualStorage Virtual storage is out of scope and removed
StorageFactory.Blobs.Virtual() Virtual storage is out of scope and removed
ZipStore ZIP Archive support is out of scope and removed
StorageFactory.Blobs.ZipFile() ZIP Archive support is out of scope and removed

Deleted libraries

The following libraries have been deprecated and deleted from our codebase, reducing the maintenance effort and helping us focus on the important parts of our offering.

Package Reason
FluentStorage.Databricks We will no longer maintain this package because DBFS is not a mainstream storage backend for a storage abstraction library.
FluentStorage.Azure.EventHub Due to low community usage, we will no longer maintain this library.
FluentStorage.Azure.DataLake We are no longer maintaining this package as it only caters to DataLake Gen 1, which has been superseded by DataLake Gen2. Gen1 is considered a legacy service and is no longer the direction Microsoft recommends for new development.
FluentStorage.Azure.ServiceFabric We will no longer maintain this package because ServiceFabric is not a first-class object storage or messaging service, which is outside our current scope, and it also has extremely low community usage.

Migrating from Storage.NET

Packaging changes

Change your NuGet packages and your imports using this mapping:

Old name New name
Storage.Net FluentStorage
Storage.Net.Amazon.Aws FluentStorage.AWS
Storage.Net.Gcp.CloudStorage FluentStorage.GCP
Storage.Net.Databricks No longer supported
Storage.Net.Ftp FluentStorage.FTP
Storage.Net.Microsoft.Azure.Storage.Blobs FluentStorage.Azure.Blobs
Storage.Net.Microsoft.Azure.Storage.Files FluentStorage.Azure.Files
Storage.Net.Microsoft.Azure.EventHub No longer supported
Storage.Net.Microsoft.Azure.ServiceBus FluentStorage.Azure.ServiceBus
Storage.Net.Microsoft.Azure.KeyVault FluentStorage.Azure.KeyVault
Storage.Net.Microsoft.Azure.ServiceFabric No longer supported
Storage.Net.Microsoft.Azure.Queues FluentStorage.Azure.Queues
Storage.Net.Microsoft.Azure.DataLake.Storage.Gen1 No longer supported

Clone this wiki locally