Toy Storage is a lightweight and extensible data access framework for Azure Blob Storage.
Toy Storage is still in early development and has not been published to NuGet, but if you're feeling adventurous, continuous integration builds are on MyGet.
Super-duper quick start:
Create a DocumentCollection
with MiddlewarePipeline
and CloudBlobContainer
.
// create middleware pipeline and configure middleware components
var pipeline = new MiddlewarePipeline()
.Use<JsonFormaterMiddleware>()
.Use<BlobStorageMiddleware>();
// create container
var container = CloudStorageAccount.Parse("UseDevelopmentStorage=true")
.CreateCloudBlobClient()
.GetContainerReference("entities");
// ensure container
await container.CreateIfNotExistsAsync();
// create client
var documentCollection = new DocumentCollection(container, pipeline);
The Middleware
components have access to the request, the response, and the next middleware component in the request-response cycle. This pattern is used in frameworks, such as Express and ASP.NET Core.
The CloudBlobContainer
provides a grouping of a set of blobs. This is part of the WindowsAzure.Storage library.
Now that we have our DocumentContainer
, let's save an entity.
var entity = new MyClass()
{
Name = "Mario",
Profession = "Plumber",
FavoriteColor = "Red"
};
var id = "mario"
await documentCollection.PutAsync(entity, id);
The entity has been serialized to JSON
, then written to the blob mario
inside the container entities
. Like entities\mario
;
Now read our entity
var entity = await documentCollection.GetAsync<MyClass>("mario");
Console.WriteLine($"I have {entity.Name}");
// "I have Mario"
The blob has been read from entities\mario
, then deserialized as type MyClass
.
Now update our entity
enity.Profession = "Adventurer";
await documentCollection.PutAsync(entity, "mario");
The blob entities\mario
is overwritten with our updated entity.
Now delete our entity
await documentCollection.DeleteAsync("mario");
The blob entities\mario
as been deleted.
Middleware components can perform the following tasks:
- Execute any code.
- Make changes to the request and the response objects.
- End the request-response cycle.
- Call the next middleware component in the stack.
The minimal requirements for middleware to accomplish:
- Format request object to a binary representation (serialize) and format binary response to object (deserialize).
- Handle Read/Write/Delete commands to blob storage.
You can add other middleware components to do just about anything required for your application, like validation, compression, optimistic concurrency, caching, logging, security, etc.
The order that middleware components are added in Use
method defines the order in which they are invoked on requests, and the reverse order for the response. This ordering is critical for security, performance, and functionality.
Toy Storage comes with some basic middleware components that cover some common use cases.
- BlobStorageMiddleware - Handles the actual Read/Write/Delete commands to blobs.
- GZipMiddleware - Compress requests and decompress responses.
- IfMatchConditionOnChangeMiddleware - Add unobtrusive optimistic concurrency to data changing requests using the http precondition
If-Match
header. - JsonFormaterMiddleware - Formats request to JSON and response from JSON.
You can easily write your own middleware components.
Write a lambda
middleware.Use(async (ctx, next) =>
{
Console.WriteLine($"Starting {ctx.RequestMethod} to {ctx.CloudBlockBlob.Name}");
await next();
Console.WriteLine("Completed");
});
Implement IMiddlewareComponent
public class LoggerMiddleware : IMiddlewareComponent
{
public async Task Invoke(RequestContext context, RequestDelegate next)
{
Console.WriteLine($"Starting {context.RequestMethod} to {context.CloudBlockBlob.Name}");
await next();
Console.WriteLine("Completed");
}
}
middleware.Use<LoggerMiddleware>();