Osirion.Blazor.Cms.Infrastructure 4.0.0

Prefix Reserved
dotnet add package Osirion.Blazor.Cms.Infrastructure --version 4.0.0
                    
NuGet\Install-Package Osirion.Blazor.Cms.Infrastructure -Version 4.0.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="Osirion.Blazor.Cms.Infrastructure" Version="4.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Osirion.Blazor.Cms.Infrastructure" Version="4.0.0" />
                    
Directory.Packages.props
<PackageReference Include="Osirion.Blazor.Cms.Infrastructure" />
                    
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 Osirion.Blazor.Cms.Infrastructure --version 4.0.0
                    
#r "nuget: Osirion.Blazor.Cms.Infrastructure, 4.0.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.
#:package Osirion.Blazor.Cms.Infrastructure@4.0.0
                    
#: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=Osirion.Blazor.Cms.Infrastructure&version=4.0.0
                    
Install as a Cake Addin
#tool nuget:?package=Osirion.Blazor.Cms.Infrastructure&version=4.0.0
                    
Install as a Cake Tool

Osirion.Blazor.Cms.Infrastructure

NuGet License

Infrastructure layer for the Osirion.Blazor CMS ecosystem, implementing repositories, external service integrations, and infrastructure concerns.

Overview

The Infrastructure project implements the Infrastructure layer in the Clean Architecture pattern, providing concrete implementations of the interfaces defined in the Domain and Application layers. It includes repositories, API clients, storage implementations, and external service integrations.

Features

  • GitHub Provider: Content repository implementation using GitHub API
  • File System Provider: Local file system content repository
  • Caching Integration: Memory and distributed cache implementations
  • HTTP Clients: Typed HTTP clients for external service communication
  • Local Storage: Browser local storage adapter for client-side persistence
  • Dependency Injection: Infrastructure service registration extensions

GitHub Provider

Content provider implementation using the GitHub API via Octokit.NET:

public class GitHubContentRepository : IContentRepository
{
    private readonly GitHubClient _client;
    private readonly IMemoryCache _cache;
    private readonly ILogger<GitHubContentRepository> _logger;
    private readonly GitHubContentOptions _options;

    public GitHubContentRepository(
        IHttpClientFactory httpClientFactory,
        IMemoryCache cache,
        IOptions<GitHubContentOptions> options,
        ILogger<GitHubContentRepository> logger)
    {
        _cache = cache;
        _logger = logger;
        _options = options.Value;
        
        _client = new GitHubClient(new ProductHeaderValue("Osirion.Blazor.Cms"));
        
        if (!string.IsNullOrWhiteSpace(_options.PersonalAccessToken))
        {
            _client.Credentials = new Credentials(_options.PersonalAccessToken);
        }
    }

    public async Task<ContentItem?> GetByPathAsync(string path)
    {
        try
        {
            var cacheKey = $"github:content:{path}";
            
            if (_cache.TryGetValue(cacheKey, out ContentItem? cachedItem))
            {
                return cachedItem;
            }
            
            var contentResponse = await _client.Repository.Content.GetAllContents(
                _options.Owner, 
                _options.Repository,
                Path.Combine(_options.ContentPath, path));
                
            var content = contentResponse.FirstOrDefault();
            
            if (content is null)
            {
                return null;
            }
            
            var decodedContent = content.Encoding == ContentEncoding.Base64
                ? Encoding.UTF8.GetString(Convert.FromBase64String(content.Content))
                : content.Content;
                
            var contentItem = await ProcessContentAsync(path, decodedContent);
            
            var cacheOptions = new MemoryCacheEntryOptions()
                .SetSlidingExpiration(TimeSpan.FromMinutes(_options.CacheExpirationMinutes));
                
            _cache.Set(cacheKey, contentItem, cacheOptions);
            
            return contentItem;
        }
        catch (NotFoundException)
        {
            _logger.LogWarning("Content not found in GitHub repository: {Path}", path);
            return null;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error fetching content from GitHub: {Path}", path);
            throw;
        }
    }
    
    // Additional repository methods
}

Configuration Options

Configuration options for the infrastructure providers:

public class GitHubContentOptions
{
    public string Owner { get; set; } = string.Empty;
    public string Repository { get; set; } = string.Empty;
    public string Branch { get; set; } = "main";
    public string ContentPath { get; set; } = "content";
    public string? PersonalAccessToken { get; set; }
    public bool UseCache { get; set; } = true;
    public int CacheExpirationMinutes { get; set; } = 60;
}

public class FileSystemContentOptions
{
    public string BasePath { get; set; } = "content";
    public bool WatchForChanges { get; set; } = false;
    public bool UseCache { get; set; } = true;
    public int CacheExpirationMinutes { get; set; } = 60;
}

GitHub API Clients and Credentials

  • IGitHubApiClientFactory.GetClient(name) and GetDefaultClient() return a new GitHubApiClient on every call. The caller owns it: SetRepository, SetBranch and SetAccessToken change that instance only and never another caller's client.
  • A client sends Accept, User-Agent and Authorization on each request message and never changes HttpClient.DefaultRequestHeaders. An Accept or User-Agent header you configure on the HttpClient is kept.
  • Factory clients take a short-lived HttpClient named GitHub_{ProviderName} from IHttpClientFactory for every operation. Configure it with services.AddHttpClient("GitHub_Blog").
  • Cookies are turned off on the primary handler of the GitHub_*, IGitHubApiClient, IGitHubTokenProvider and IAuthenticationService clients, because a pooled handler is shared by every user. The policy runs after all handler configuration, so a primary handler you configure (through ConfigureHttpClientDefaults or the named client, before or after the Osirion registration) is kept with cookies turned off. In the browser it does nothing, because the fetch API owns cookies there.
  • Repository paths, branch names, owner and repository are percent-encoded per segment. A backslash in a repository path is read as a / separator. A path or branch name with an empty, . or .. segment is rejected with an ArgumentException before any request is sent. URLs built from letters, digits, -, _, ., ~ and / are unchanged.
  • IAuthenticationService and IGitHubAdminService are registered as scoped, one per circuit or request, replacing any earlier registration. The admin service never uses a content provider's ApiToken: it uses the signed-in user's token, or CmsAdminOptions.Authentication.PersonalAccessToken when one is configured. Without either, repository operations send no request; DeleteFileAsync, for example, throws InvalidOperationException instead of sending an unauthenticated delete. Signing out drops the user's token from the admin service of the same scope.
  • AuthenticationService keeps the user's token in memory only. It never writes the token to IStateStorageService (which stores plain text) and never signs anyone in with the configured PersonalAccessToken. InitializeAsync and sign-out remove a github_auth_token value that earlier versions left in browser storage. The admin module keeps a signed-in user's token between page loads in encrypted, user-bound protected browser storage instead.
  • GitHubTokenProvider requests Accept: application/json, sends the redirect_uri and PKCE code_verifier it is given, treats an error field in a 200 response as a rejected exchange, and honours its CancellationToken. The original ExchangeCodeForTokenAsync(code, clientId, clientSecret) overload still works and sends neither value.

Dependencies

The infrastructure layer has the following dependencies:

  • Osirion.Blazor.Cms.Domain: For domain entities and interfaces
  • Osirion.Blazor.Cms.Application: For application services and interfaces
  • Octokit: For GitHub API integration
  • Blazored.LocalStorage: For browser local storage access
  • Microsoft.Extensions.Caching.Memory: For memory caching
  • Microsoft.Extensions.Http: For HTTP client factory

License

This project is licensed under the MIT License - see the LICENSE file for details.

Product Compatible and additional computed target framework versions.
.NET net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  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 (1)

Showing the top 1 NuGet packages that depend on Osirion.Blazor.Cms.Infrastructure:

Package Downloads
Osirion.Blazor.Cms.Core

Core CMS module for Osirion.Blazor - Provides cms management with provider pattern.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
4.0.0 82 10/12/2026
3.0.1 261 9/24/2026
3.0.0 203 8/5/2026
2.1.18 305 12/14/2025
2.1.17 298 12/14/2025
2.1.16 277 12/14/2025
2.1.15 262 12/12/2025
2.1.14 536 12/11/2025
2.1.13 555 12/11/2025
2.1.12 365 9/4/2025
2.1.11 316 8/31/2025
2.1.10 353 8/29/2025
2.1.9 367 8/29/2025
2.1.8 351 8/27/2025
2.1.7 451 8/25/2025
2.1.6 249 8/23/2025
2.1.5 319 6/24/2025
2.1.4 318 6/18/2025
2.1.3 230 5/31/2025
2.1.2 174 5/31/2025
Loading failed