This is the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

Dapr Binary Store .NET SDK

Store and retrieve binary files using the Dapr Binary Store .NET SDK

The Dapr Binary Store package lets .NET applications store, retrieve, stream, and delete binary files in a configured Dapr binary store component. It supports stream-based uploads and downloads for large files, as well as byte-array access for files that fit in memory. A source generator can also create a strongly typed client bound to a specific store.

To get started, follow the Dapr Binary Store how-to guide and refer to the client usage guidance for configuration, streaming, and error handling.

1 - How to: Manage binary files with the Dapr Binary Store .NET SDK

Learn how to store, retrieve, stream, and delete binary files using the Dapr Binary Store .NET SDK

Use the Dapr.BinaryStore package to store and retrieve files using a Dapr binary store component. The client streams file content in chunks, so you can work with large files without loading the entire file into memory. In this guide, you will:

  • Register and configure DaprBinaryStoreClient
  • Upload and download files using streams
  • Choose between streaming and in-memory operations
  • Bind a typed client to a store with the source generator

Prerequisites

Install the package in your project:

dotnet add package Dapr.BinaryStore

Configure an in-memory binary store

For local development, create a components directory in your application directory and save the following component as components\filestore.yaml:

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: filestore
spec:
  type: binarystore.in-memory
  version: v1
  metadata:
    - name: maxSize
      value: "4Mi"
    - name: maxTotalSize
      value: "512Mi"

This component stores files in the Dapr sidecar’s memory without requiring an external storage service. It allows files up to 4 MiB and a combined total of 512 MiB. Data is lost when the sidecar stops and is not shared across sidecars, so use it for local development and testing rather than durable storage.

The component’s metadata.name, filestore, is the store name supplied to the client methods or the [BinaryStore] attribute in the examples below.

Register the client

Register the client in dependency injection. By default, it reads the Dapr endpoint and API token from the environment or IConfiguration.

using Dapr.BinaryStore.Extensions;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddDaprBinaryStoreClient();

var app = builder.Build();

Start the application from its project directory with its Dapr sidecar, loading the in-memory component from components:

dapr run --app-id binary-store-example --resources-path .\components -- dotnet run

If you need to override the endpoint, configure the client builder:

builder.Services.AddDaprBinaryStoreClient((sp, clientBuilder) =>
{
    clientBuilder.UseGrpcEndpoint("http://localhost:50001");
});

Upload and download a file

Resolve the registered client and pass the binary store component name, a file name, and a stream. The example uses the filestore component configured above. Place a report.pdf file no larger than 4 MiB in your application’s working directory before running the example. Add the following code after var app = builder.Build(); in Program.cs, with the using directives at the top of the file.

using Dapr.BinaryStore;
using Microsoft.Extensions.DependencyInjection;

var client = app.Services.GetRequiredService<DaprBinaryStoreClient>();
const string storeName = "filestore";
const string fileName = "uploads/report.pdf";

await using (var source = File.OpenRead("report.pdf"))
{
    await client.SetBinaryFileAsync(storeName, fileName, source);
}

await using (var destination = File.Create("downloaded-report.pdf"))
{
    await client.GetBinaryFileAsync(storeName, fileName, destination);
}

The example uploads report.pdf to the in-memory store as uploads/report.pdf and downloads it to downloaded-report.pdf. Run the remaining examples against the same sidecar to use the uploaded file before deleting it.

The Stream overload of SetBinaryFileAsync reads the input stream from its current position and sends it to the runtime in chunks. The default upload chunk size is 32 KiB; pass chunkSize to choose another positive size. Set overwrite: true to replace an existing file. By default, an upload fails if the file already exists.

File names can include nested paths such as uploads/report.pdf. Avoid a leading or trailing slash, empty path segments, . or .. segments, and the characters \, *, ?, [, ], and #; the Dapr runtime rejects these names.

Work with in-memory content

For content that already fits in memory, pass ReadOnlyMemory<byte> to upload or use GetBinaryFileBytesAsync to retrieve the complete file:

byte[] content = [0x01, 0x02, 0x03];
await client.SetBinaryFileAsync(storeName, "data.bin", content);

byte[] downloaded = await client.GetBinaryFileBytesAsync(storeName, "data.bin");

GetBinaryFileBytesAsync buffers the whole file in memory. Prefer GetBinaryFileAsync or GetBinaryFileChunksAsync for large files:

await using var chunkDestination = File.Create("downloaded-report-from-chunks.pdf");

await foreach (var chunk in client.GetBinaryFileChunksAsync(storeName, fileName))
{
    await chunkDestination.WriteAsync(chunk);
}

Delete a file

await client.DeleteBinaryFileAsync(storeName, fileName);

Use a store-bound typed client

The package includes a source generator for a typed client that is bound to one component. Define a partial interface that extends IDaprBinaryStoreClient and use [BinaryStore] to specify the component name:

using Dapr.BinaryStore;

[BinaryStore("filestore")]
public partial interface IFileStore : IDaprBinaryStoreClient
{
}

Register the generated client after registering DaprBinaryStoreClient:

builder.Services
    .AddDaprBinaryStoreClient()
    .WithFileStore();

The generated WithFileStore method registers an implementation of IFileStore. Inject that interface where it is needed; its methods are the same as IDaprBinaryStoreClient but do not take a store name:

public sealed class ReportService(IFileStore fileStore)
{
    public Task SaveAsync(string name, Stream content, CancellationToken cancellationToken) =>
        fileStore.SetBinaryFileAsync(name, content, cancellationToken: cancellationToken);
}

2 - DaprBinaryStoreClient usage

Essential guidance for configuring and using DaprBinaryStoreClient

The operations on this page target SDK 1.19.0. Use that release or later with Dapr runtime 1.19 or later.

Operation surface

OperationAPI
UploadSetBinaryFileAsync with a Stream or ReadOnlyMemory<byte>, optionally overwriting an existing file.
DownloadGetBinaryFileChunksAsync, GetBinaryFileAsync into a destination stream, or GetBinaryFileBytesAsync to buffer the complete file.
DeleteDeleteBinaryFileAsync.
Store-bound access[BinaryStore] on a partial IDaprBinaryStoreClient interface and the generated With... DI registration.

This SDK release does not expose list-files, file metadata, conditional/ETag writes, or range-read methods. Binary store files are not state entries; state transactions and state query APIs do not apply to them.

Client lifetime

DaprBinaryStoreClient uses network resources and implements IDisposable. Reuse a long-lived client rather than creating one for each operation. The dependency injection registration uses ServiceLifetime.Singleton by default; use the optional lifetime argument to select another lifetime when needed.

using Dapr.BinaryStore.Extensions;
using Microsoft.Extensions.DependencyInjection;

builder.Services.AddDaprBinaryStoreClient(lifetime: ServiceLifetime.Singleton);

Client configuration

DaprBinaryStoreClientBuilder inherits the common Dapr client builder configuration. The client reads these values from environment variables or IConfiguration:

SettingDescription
DAPR_GRPC_ENDPOINTgRPC endpoint address for the Dapr sidecar
DAPR_HTTP_ENDPOINTHTTP endpoint address for the Dapr sidecar
DAPR_API_TOKENAPI token used to authenticate with the Dapr sidecar
DAPR_GRPC_PORTgRPC port used if DAPR_GRPC_ENDPOINT is not set
DAPR_HTTP_PORTHTTP port used if DAPR_HTTP_ENDPOINT is not set

Values explicitly set on the builder take precedence over values from configuration:

using Dapr.BinaryStore.Extensions;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

builder.Services.AddDaprBinaryStoreClient((sp, clientBuilder) =>
{
    var configuration = sp.GetRequiredService<IConfiguration>();
    var endpoint = configuration["DaprGrpcEndpoint"];

    if (!string.IsNullOrEmpty(endpoint))
    {
        clientBuilder.UseGrpcEndpoint(endpoint);
    }
});

The builder also supports UseHttpEndpoint, UseDaprApiToken, UseGrpcChannelOptions, and UseTimeout for applications that need to customize the common Dapr client settings.

Streaming and memory use

Use the Stream overload of SetBinaryFileAsync and GetBinaryFileAsync for large files. Uploads use a 32 KiB chunk size by default; specify chunkSize on upload to tune this, and ensure it is greater than zero. GetBinaryFileChunksAsync returns an asynchronous sequence of chunks chosen by the runtime.

The ReadOnlyMemory<byte> overload of SetBinaryFileAsync and GetBinaryFileBytesAsync are convenient for small files already held in memory. GetBinaryFileBytesAsync buffers the complete download in a byte array.

The caller owns the streams. Downloads write at the destination’s current position and do not rewind or truncate it; uploads read at the source’s current position. Chunk enumeration is lazy, and runtime errors can be thrown during enumeration. A failed download can leave partial bytes in the destination, which your application must not treat as a complete file.

Cancellation

All asynchronous operations accept a CancellationToken. Pass the token through uploads, downloads, chunk enumeration, and deletes so the operation can be canceled when the caller no longer needs it:

await client.SetBinaryFileAsync(
    storeName,
    fileName,
    source,
    cancellationToken: cancellationToken);

When canceled, an OperationCanceledException is thrown. For chunk enumeration, pass the token to GetBinaryFileChunksAsync:

await foreach (var chunk in client.GetBinaryFileChunksAsync(
                   storeName,
                   fileName,
                   cancellationToken))
{
    await ProcessChunkAsync(chunk);
}

Errors

The client throws DaprException when the Dapr runtime reports a failure. For example, a file that does not exist cannot be retrieved or deleted, and an upload without overwrite: true fails if a file with the same name already exists. Inspect InnerException for details from the runtime. Invalid client arguments, such as an empty store or file name or a non-positive upload chunk size, result in standard argument exceptions.