TableStorage.Abstractions 2.1.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package TableStorage.Abstractions --version 2.1.0
NuGet\Install-Package TableStorage.Abstractions -Version 2.1.0
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="TableStorage.Abstractions" Version="2.1.0" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add TableStorage.Abstractions --version 2.1.0
#r "nuget: TableStorage.Abstractions, 2.1.0"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install TableStorage.Abstractions as a Cake Addin
#addin nuget:?package=TableStorage.Abstractions&version=2.1.0

// Install TableStorage.Abstractions as a Cake Tool
#tool nuget:?package=TableStorage.Abstractions&version=2.1.0

TableStorage.Abstractions

Repository wrapper for Azure Table Storage in C# .NET 4.5.2, .NET 4.6, .NET 4.6.1

Starting work with Azure Table Storage has been interesting and very different from working with SQL Server which I have done for many years. After reading a number of articles about it and using it I realised a generic wrapper would be useful to create and so this is that creation.

Based on multiple articles from Microsoft and others to try and get a performant wrapper and aid unit testing of code using Azure Table Storage.

https://blogs.msdn.microsoft.com/windowsazurestorage/2010/06/25/nagles-algorithm-is-not-friendly-towards-small-requests/

https://azure.microsoft.com/en-gb/blog/managing-concurrency-in-microsoft-azure-storage-2/

https://docs.microsoft.com/en-us/azure/storage/storage-table-design-guide

https://docs.particular.net/nservicebus/azure-storage-persistence/performance-tuning

http://robertgreiner.com/2012/06/why-is-azure-table-storage-so-slow/

Optimisations are controlled by the Table Storage Options Class. The defaults are applied as below if not overridden:

public class TableStorageOptions
{
    public bool UseNagleAlgorithm { get; set; } = false;

    public bool Expect100Continue { get; set; } = false;

    public int ConnectionLimit { get; set; } = 10;

    public int Retries { get; set; } = 3;

    public double RetryWaitTimeInSeconds { get; set; } = 1;

    public bool EnsureTableExists { get; set; } = true;
}

Example entity:

public class TestTableEntity : TableEntity
{
    public int Age { get; set; }
    public string Email { get; set; }

    public TestTableEntity() {}

    public TestTableEntity(string name, string surname)
    {
        PartitionKey = surname;
        RowKey = name;
    }
}

Example usage:

var tableStorage = new TableStore<TestTableEntity>("MyTable", "UseDevelopmentStorage=true");
var entity = new TestTableEntity("John", "Smith") { Age = 21, Email = "john.smith@something.com" };

await tableStorage.InsertAsync(entity);

// Get the entries by the row key
var result = tableStorage.GetByRowKey("John").ToList();

Inserting multiple entries into table storage requires each entry to have the same partition key for a batch. This implementation in the wrapper does this job for you so that you can just pass a list of entities.

Example Insert of multiple records

var tableStorage = new TableStore<TestTableEntity>("MyTable", "UseDevelopmentStorage=true");
var entries = new List<TestTableEntity>
{
    new TestTableEntity("John", "Smith") {Age = 21, Email = "john.smith@something.com"},
    new TestTableEntity("Jane", "Smith") {Age = 28, Email = "jane.smith@something.com"},
    new TestTableEntity("Bill", "Smith") { Age = 38, Email = "bill.smith@another.com"},
    new TestTableEntity("Fred", "Jones") {Age = 32, Email = "fred.jones@somewhere.com"},
    new TestTableEntity("Bill", "Jones") {Age = 45, Email = "bill.jones@somewhere.com"},
    new TestTableEntity("Bill", "King") {Age = 45, Email = "bill.king@email.com"},
    new TestTableEntity("Fred", "Bloggs") { Age = 32, Email = "fred.bloggs@email.com" }
};      

await tableStorage.InsertAsync(entries);

The library also includes a factory class to make it easier when using dependency injection

public class TestTableStorageClient
{
    private ITableStore<MyStuff> _store;

    public TestTableStorageClient(ITableStoreFactory factory)
    {
        _store = factory.CreateTableStore<MyStuff>("MyTable", "UseDevelopmentStorage=true");
    }
}

Table Storage does not really have generic way of filtering data as yet. So there are some methods to help with that. NOTE: The filtering works by getting all records so on large datasets this will be slow. Testing showed ~1.3 seconds for 10,000 records Testing when paged by 100 ~0.0300 seconds for 10,000 records returning 100 records

var tableStorage = new TableStore<TestTableEntity>("MyTable", "UseDevelopmentStorage=true");
var results = tableStorage.GetRecordsByFilter(x => x.Age > 21 && x.Age < 25);

And with basic paging starting at 0 and returning 100 NOTE: The start is number of records e.g. 20, 100 would start at record 20 and then return a maxiumum of 100 after that

var tableStorage = new TableStore<TestTableEntity>("MyTable", "UseDevelopmentStorage=true");
var results = tableStorage.GetRecordsByFilter(x => x.Age > 21 && x.Age < 25, 0, 100);

There is also the consideration of using Reactive Extensions (RX - http://reactivex.io/) to observe the results from a get all records call or a get filtered records.

var tableStorage = new TableStore<TestTableEntity>("MyTable", "UseDevelopmentStorage=true");
var theObserver = tableStorage.GetAllRecordsObservable();
theObserver.Where(x => x.Age > 21 && x.Age < 25).Take(100).Subscribe(x =>
{
   // Do something with the table entry
});

or

var tableStorage = new TableStore<TestTableEntity>("MyTable", "UseDevelopmentStorage=true");
var theObserver = tableStorage.GetRecordsByFilterObservable(x => x.Age > 21 && x.Age < 25, 0, 100);
theObserver.Subscribe(x =>
{
   // Do something with the table entry
});
Product Compatible and additional computed target framework versions.
.NET Framework net452 is compatible.  net46 is compatible.  net461 is compatible.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (2)

Showing the top 2 NuGet packages that depend on TableStorage.Abstractions:

Package Downloads
TableStorage.Abstractions.POCO

A repository wrapper for Azure Table Storage that uses POCOs (Plain Old CLR Objects) instead of objects that implemeent ITableEntity. The Azure Storage SDK requires that objects that it works with to implement the ITableEntity interface. This puts us into one of two places that are often not desirable: You implement the ITableEntity interace, or inherit from TableEntity. This is easy, but now you've got a leaky abstraction, as well as properties that won't make much sense in your domain (e.g. instead of a UserId, you've now got a RowKey, of the wrong type), or you have fields that are out of place, like ETag and Timestamp. You create DTOs to save to ship data back and forth from the domain to Table Storage. This is a common style, but often is overkill, especially if we're just looking for a simple abstraction on top of Azure Table Storage. This simple library seeks to take care of the mapping for us, so that you can continue to write your domain objects as POCOs, while still being able to leverage the Azure Storage SDK. The library will convert simple properties to fields in Azure Table Storage. Complex types will serialize as json.

TableStorage.Abstractions.Trie

An implementation of a trie-like data structure using Azure Table Storage to enable type-ahead style searching. Targets netcoreapp2.1, netstandard2.0 and net461.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
3.3.10 11,842 6/11/2023
3.3.9 553 6/11/2023
3.3.7 1,696 2/7/2023
3.3.6 657 2/4/2023
3.3.0 24,881 1/15/2022
3.2.4 25,864 11/7/2020
3.2.2 7,061 5/3/2020
3.2.1 1,140 5/3/2020
3.1.0 10,967 2/23/2020
3.0.1-preview 1,020 2/2/2020
3.0.0 1,522 1/26/2020
2.3.0 23,743 4/28/2019
2.2.0 8,329 1/6/2019
2.1.2 3,494 10/8/2018
2.1.1 1,939 7/1/2018
2.1.0 1,702 4/22/2018
2.0.0 1,884 2/11/2018
1.1.1 3,153 2/11/2018
1.1.0 6,296 9/3/2017
1.0.6 9,357 8/22/2017
1.0.5 1,767 8/19/2017
1.0.4 1,776 8/19/2017
1.0.3 1,594 7/29/2017
1.0.2 1,634 1/8/2017
1.0.1 4,554 11/20/2016

Added time string style searching to most of the search methods. The time can be specified using value and time type e.g. 10m for 10 minutes, 1h for 1 hour, 1d for 1 day, etc.