Rystem.Content.Abstractions 10.0.7

dotnet add package Rystem.Content.Abstractions --version 10.0.7
                    
NuGet\Install-Package Rystem.Content.Abstractions -Version 10.0.7
                    
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="Rystem.Content.Abstractions" Version="10.0.7" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Rystem.Content.Abstractions" Version="10.0.7" />
                    
Directory.Packages.props
<PackageReference Include="Rystem.Content.Abstractions" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Rystem.Content.Abstractions --version 10.0.7
                    
#r "nuget: Rystem.Content.Abstractions, 10.0.7"
                    
#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.
#:package Rystem.Content.Abstractions@10.0.7
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Rystem.Content.Abstractions&version=10.0.7
                    
Install as a Cake Addin
#tool nuget:?package=Rystem.Content.Abstractions&version=10.0.7
                    
Install as a Cake Tool

Rystem.Content.Abstractions

Rystem.Content.Abstractions contains the shared content API, the registration builder, and the cross-provider migration service.

It does not implement storage by itself. Real storage arrives through provider packages such as Blob, File Share, SharePoint, or InMemory.

Installation

dotnet add package Rystem.Content.Abstractions

What this package adds

This package defines:

  • IContentRepository
  • IContentRepositoryBuilder
  • ContentRepositoryOptions
  • ContentRepositoryResult
  • ContentRepositoryDownloadResult
  • ContentInformationType
  • IContentMigration

At DI level, AddContentRepository() currently registers:

  • IContentMigration as Transient

Provider registrations are added later through With...Integration(...) extension methods.

Architecture

The core model is intentionally small:

  • IContentRepository is the only storage contract
  • AddContentRepository() returns an IContentRepositoryBuilder
  • providers register named implementations through the shared factory system
  • migrations resolve source and destination repositories from IFactory<IContentRepository>

In the current source tree and tests, named resolution is done with IFactory<IContentRepository>, not an IContentRepositoryFactory abstraction.

Registration API

IContentRepositoryBuilder exposes three registration shapes:

Method Use when Default lifetime
WithIntegration<TRepository>(name, lifetime) repository has no options object Transient
WithIntegration<TRepository, TOptions>(options, name, lifetime) repository needs synchronous options wiring Transient
WithIntegrationAsync<TRepository, TOptions, TConnection>(options, name, lifetime) repository setup is asynchronous and builds a connection wrapper Transient

The built-in Blob, File, and SharePoint providers sit on top of WithIntegrationAsync(...). The InMemory provider uses WithIntegration(...) and overrides the lifetime to Singleton.

The provider-specific WithBlobStorageIntegration(...), WithFileStorageIntegration(...), WithSharepointIntegration(...), and WithInMemoryIntegration(...) extensions are defined by the provider packages, not by this package itself.

Minimal setup

var repositories = services.AddContentRepository();

repositories.WithInMemoryIntegration("inmemory");

When you need a provider with async setup:

var repositories = services.AddContentRepository();

await repositories.WithBlobStorageIntegrationAsync(options =>
{
    options.ContainerName = "supertest";
    options.ConnectionString = configuration["ConnectionString:Storage"];
}, "blobstorage");

Consuming named repositories

The content tests resolve repositories like this:

public sealed class ContentService
{
    private readonly IContentRepository _contentRepository;

    public ContentService(IFactory<IContentRepository> factory)
        => _contentRepository = factory.Create("blobstorage");
}

IContentRepository contract

Method Return type Purpose
ListAsync(prefix, downloadContent, informationRetrieve) IAsyncEnumerable<ContentRepositoryDownloadResult> Enumerate files with optional prefix filtering
DownloadAsync(path, informationRetrieve) Task<ContentRepositoryDownloadResult?> Download bytes and optional metadata
GetPropertiesAsync(path, informationRetrieve) Task<ContentRepositoryResult?> Read metadata without downloading bytes
UploadAsync(path, data, options, overwrite) ValueTask<bool> Create or replace a file
SetPropertiesAsync(path, options) ValueTask<bool> Update headers, metadata, or tags
DeleteAsync(path) ValueTask<bool> Delete a file
ExistAsync(path) ValueTask<bool> Check whether a file exists

Important caveat: overwrite is part of the shared interface, but not every provider enforces it the same way.

Shared models

ContentRepositoryOptions

var options = new ContentRepositoryOptions
{
    HttpHeaders = new ContentRepositoryHttpHeaders
    {
        ContentType = "image/png",
        CacheControl = "max-age=3600",
        ContentDisposition = "attachment; filename=image.png"
    },
    Metadata = new Dictionary<string, string>
    {
        ["author"] = "alice"
    },
    Tags = new Dictionary<string, string>
    {
        ["version"] = "1"
    }
};

ContentInformationType

Value Meaning
None no extra metadata
HttpHeaders include content headers
Metadata include metadata dictionary
Tags include tags when supported
All HttpHeaders | Metadata | Tags

Result models

Type Properties
ContentRepositoryResult Path, Uri, Options
ContentRepositoryDownloadResult everything in ContentRepositoryResult plus Data

Path and Uri are provider-defined. Do not assume they have identical semantics across Blob, File Share, SharePoint, and InMemory.

Migration service

IContentMigration copies content between named providers.

This example matches the usage style in src/Content/Rystem.Content.Tests/Rystem.Content.UnitTest/Integrations/AllStorageTest.cs.

ContentMigrationResult result = await contentMigration.MigrateAsync(
    sourceName: "inmemory",
    destinationName: "filestorage",
    settings: options =>
    {
        options.Prefix = "Test/Folder1/";
        options.OverwriteIfExists = true;
        options.Predicate = item => item.Path?.Contains("fileName6") != true;
        options.ModifyDestinationPath = path => path.Replace("Folder2", "Folder3");
    });

Available settings:

Property Default Meaning
Prefix null restrict source enumeration
Predicate null skip items that do not match
OverwriteIfExists false pass overwrite intent to destination upload
OnErrorContinue true keep going after per-file errors
ModifyDestinationPath null rewrite the output path

Migration behavior notes

The current implementation is a straightforward copy loop:

  • it resolves both repositories through IFactory<IContentRepository>
  • it enumerates source items with ListAsync(..., downloadContent: false, ContentInformationType.None)
  • it downloads each matched item with ContentInformationType.All
  • it uploads the downloaded bytes plus options to the destination repository

Important caveats from the source:

  • NotMigratedPaths exists on ContentMigrationResult, but the current implementation never fills it
  • when an upload returns false, the result currently lands in NotContentPaths
  • there is no provider-native server-side copy or batching logic

Writing a custom provider

If you want your own backend, implement IContentRepository and register it through the builder.

internal sealed class MyContentRepository : IContentRepository
{
    public IAsyncEnumerable<ContentRepositoryDownloadResult> ListAsync(
        string? prefix = null,
        bool downloadContent = false,
        ContentInformationType informationRetrieve = ContentInformationType.None,
        CancellationToken cancellationToken = default)
        => throw new NotImplementedException();

    public Task<ContentRepositoryDownloadResult?> DownloadAsync(
        string path,
        ContentInformationType informationRetrieve = ContentInformationType.None,
        CancellationToken cancellationToken = default)
        => throw new NotImplementedException();

    public Task<ContentRepositoryResult?> GetPropertiesAsync(
        string path,
        ContentInformationType informationRetrieve = ContentInformationType.All,
        CancellationToken cancellationToken = default)
        => throw new NotImplementedException();

    public ValueTask<bool> UploadAsync(
        string path,
        byte[] data,
        ContentRepositoryOptions? options = null,
        bool overwrite = true,
        CancellationToken cancellationToken = default)
        => throw new NotImplementedException();

    public ValueTask<bool> SetPropertiesAsync(
        string path,
        ContentRepositoryOptions? options = null,
        CancellationToken cancellationToken = default)
        => throw new NotImplementedException();

    public ValueTask<bool> DeleteAsync(string path, CancellationToken cancellationToken = default)
        => throw new NotImplementedException();

    public ValueTask<bool> ExistAsync(string path, CancellationToken cancellationToken = default)
        => throw new NotImplementedException();
}

Then register it:

services
    .AddContentRepository()
    .WithIntegration<MyContentRepository>("custom");
  • Rystem.Content.Infrastructure.Storage.Blob
  • Rystem.Content.Infrastructure.Storage.File
  • Rystem.Content.Infrastructure.M365.Sharepoint
  • Rystem.Content.Infrastructure.InMemory

Use this package when you want the contract and migration layer; add a provider package when you want real storage.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (4)

Showing the top 4 NuGet packages that depend on Rystem.Content.Abstractions:

Package Downloads
Rystem.Content.Infrastructure.M365.Sharepoint

Rystem.Content helps you to integrate with azure services or to create an abstraction layer among your infrastructure and your business.

Rystem.Content.Infrastructure.Storage.Blob

Rystem.Content helps you to integrate with azure services or to create an abstraction layer among your infrastructure and your business.

Rystem.Content.Infrastructure.InMemory

Rystem.Content helps you to integrate with azure services or to create an abstraction layer among your infrastructure and your business.

Rystem.Content.Infrastructure.Storage.File

Rystem.Content helps you to integrate with azure services or to create an abstraction layer among your infrastructure and your business.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
10.0.7 80 3/26/2026
10.0.6 170,728 3/3/2026
10.0.5 198 2/22/2026
10.0.4 213 2/9/2026
10.0.3 147,975 1/28/2026
10.0.1 209,176 11/12/2025
9.1.3 434 9/2/2025
9.1.2 764,549 5/29/2025
9.1.1 97,902 5/2/2025
9.0.32 186,762 4/15/2025
9.0.31 5,880 4/2/2025
9.0.30 88,930 3/26/2025
9.0.29 9,061 3/18/2025
9.0.28 299 3/17/2025
9.0.27 302 3/16/2025
9.0.26 321 3/13/2025
9.0.25 52,189 3/9/2025
9.0.23 275 3/9/2025
9.0.21 404 3/6/2025
9.0.20 19,619 3/6/2025
Loading failed