Nabs.Launchpad.Core.Resources 10.0.219

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

Nabs Launchpad Core Resources Library

The Nabs Launchpad Core Resources library provides utilities for loading and accessing embedded resources from .NET assemblies. This library simplifies the process of working with embedded files such as text documents, JSON files, images, and other binary resources at runtime.

Key Features

  • Multi-Assembly Support: Load resources from one or multiple assemblies simultaneously
  • Type-Safe Resource Discovery: Query and filter resources using strongly-typed predicates
  • Multiple Content Formats: Retrieve resources as streams, byte arrays, or text
  • Result Pattern Integration: Uses Ardalis.Result for consistent error handling
  • Resource Enumeration: List and discover available embedded resources across assemblies
  • Single Resource Validation: Ensures predicates match exactly one resource for content methods
  • UTF-8 Text Support: Automatic UTF-8 encoding for text resources

Core Components

EmbeddedResourceLoader

The main class for loading embedded resources from assemblies. It provides methods to query and retrieve embedded resources in various formats.

ResourceInfo

A record struct that represents metadata about an embedded resource, including its path and the assembly it belongs to.

Usage Examples

Basic Resource Loading

// Initialize the loader with one or more assembly types
var loader = new EmbeddedResourceLoader(typeof(MyClass), typeof(AnotherClass));

// Get resource information items
var resourceInfos = loader.GetResourceInfoItems(x => x.Path.EndsWith(".json"));

// Load resource as text
var textResult = loader.GetResourceTextContent(x => x.Path.EndsWith("config.json"));
if (textResult.IsSuccess)
{
    var jsonContent = textResult.Value;
    // Process the JSON content
}

// Load resource as stream
var streamResult = loader.GetResourceStreamContent(x => x.Path.EndsWith("template.html"));
if (streamResult.IsSuccess)
{
    using var stream = streamResult.Value;
    // Process the stream
}

// Load resource as bytes (useful for images, binary files)
var bytesResult = loader.GetResourceBytesContent(x => x.Path.EndsWith("logo.png"));
if (bytesResult.IsSuccess)
{
    var imageBytes = bytesResult.Value;
    // Process the binary data
}

Loading JSON Configuration

var loader = new EmbeddedResourceLoader(typeof(Program));

// Load JSON configuration file
var configResult = loader.GetResourceTextContent(x => 
    x.Path.EndsWith("appsettings.embedded.json"));

if (configResult.IsSuccess)
{
    var config = JsonSerializer.Deserialize<AppSettings>(configResult.Value);
    // Use configuration
}

Loading Multiple Text Files

var loader = new EmbeddedResourceLoader(typeof(TemplateEngine));

// Get all template files
var templates = loader.GetResourceInfoItems(x => 
    x.Path.Contains(".Templates.") && x.Path.EndsWith(".txt"));

foreach (var template in templates)
{
    var contentResult = loader.GetResourceTextContent(x => x.Path == template.Path);
    if (contentResult.IsSuccess)
    {
        Console.WriteLine($"Template: {template.Path}");
        Console.WriteLine(contentResult.Value);
    }
}

Loading Image Resources

var loader = new EmbeddedResourceLoader(typeof(ImageResources));

// Load company logo
var logoResult = loader.GetResourceBytesContent(x => 
    x.Path.EndsWith("company-logo.png"));

if (logoResult.IsSuccess)
{
    var imageBytes = logoResult.Value;
    
    // Save to file
    await File.WriteAllBytesAsync("logo.png", imageBytes);
    
    // Or use directly in memory
    using var ms = new MemoryStream(imageBytes);
    var image = Image.Load(ms);
}

Loading SQL Scripts

var loader = new EmbeddedResourceLoader(typeof(DatabaseMigration));

// Load migration script
var scriptResult = loader.GetResourceTextContent(x => 
    x.Path.EndsWith("001_InitialSchema.sql"));

if (scriptResult.IsSuccess)
{
    await connection.ExecuteAsync(scriptResult.Value);
}

Loading HTML Templates

var loader = new EmbeddedResourceLoader(typeof(EmailService));

// Load email template
var templateResult = loader.GetResourceTextContent(x => 
    x.Path.EndsWith("WelcomeEmail.html"));

if (templateResult.IsSuccess)
{
    var html = templateResult.Value
        .Replace("{{UserName}}", userName)
        .Replace("{{ActivationLink}}", link);
    
    await SendEmailAsync(html);
}

Discovering Available Resources

var loader = new EmbeddedResourceLoader(typeof(MyApp));

// List all embedded resources
var allResources = loader.GetResourceInfoItems(x => true);

foreach (var resource in allResources)
{
    Console.WriteLine($"Assembly: {resource.Assembly.GetName().Name}");
    Console.WriteLine($"Path: {resource.Path}");
}

Filtering by Namespace Pattern

var loader = new EmbeddedResourceLoader(typeof(LocalizationResources));

// Get all localization resources
var localizationFiles = loader.GetResourceInfoItems(x => 
    x.Path.Contains(".Localization.") && 
    x.Path.EndsWith(".resx"));

foreach (var file in localizationFiles)
{
    Console.WriteLine($"Localization file: {file.Path}");
}

API Reference

EmbeddedResourceLoader

Constructor
public EmbeddedResourceLoader(params Type[] relativeAssemblyTypes)

Initializes the loader with assemblies determined by the provided types.

Parameters:

  • relativeAssemblyTypes: One or more types used to identify which assemblies to scan for embedded resources

Example:

var loader = new EmbeddedResourceLoader(typeof(MyClass), typeof(OtherClass));
Properties
Warnings
public List<string> Warnings { get; }

Gets a list of warnings encountered during resource loading operations.

Methods

GetResourceInfoItems
public IEnumerable<ResourceInfo> GetResourceInfoItems(
    Func<ResourceInfo, bool> predicate)

Returns all resource information items that match the predicate.

Parameters:

  • predicate: Function to filter resources

Returns: Enumerable collection of matching resource information

Example:

var jsonFiles = loader.GetResourceInfoItems(x => x.Path.EndsWith(".json"));
GetResourceStreamContent
public Result<Stream> GetResourceStreamContent(
    Func<ResourceInfo, bool> predicate)

Retrieves a single resource as a stream. Returns an error if no resource or multiple resources match the predicate.

Parameters:

  • predicate: Function to identify the specific resource

Returns: Result<Stream> containing the resource stream or error

Important: The predicate must match exactly one resource.

Example:

var streamResult = loader.GetResourceStreamContent(x => 
    x.Path == "MyNamespace.Data.template.xml");
GetResourceBytesContent
public Result<byte[]> GetResourceBytesContent(
    Func<ResourceInfo, bool> predicate)

Retrieves a single resource as a byte array. Returns an error if no resource or multiple resources match the predicate.

Parameters:

  • predicate: Function to identify the specific resource

Returns: Result<byte[]> containing the resource bytes or error

Important: The predicate must match exactly one resource.

Example:

var bytesResult = loader.GetResourceBytesContent(x => 
    x.Path.EndsWith("icon.ico"));
GetResourceTextContent
public Result<string> GetResourceTextContent(
    Func<ResourceInfo, bool> predicate)

Retrieves a single resource as a UTF-8 encoded string. Returns an error if no resource or multiple resources match the predicate.

Parameters:

  • predicate: Function to identify the specific resource

Returns: Result<string> containing the resource text or error

Important: The predicate must match exactly one resource.

Example:

var textResult = loader.GetResourceTextContent(x => 
    x.Path.EndsWith("ReadMe.txt"));

ResourceInfo

Properties
Path
public string Path { get; }

Gets the full manifest resource name/path.

Assembly
public Assembly Assembly { get; }

Gets the assembly containing the resource.

Architecture and Design Patterns

Assembly Scanning

On construction, the loader scans all specified assemblies and caches their manifest resource names for efficient querying.

Result Pattern

All content retrieval methods return Result<T> objects for consistent error handling without exceptions.

Single Resource Validation

Content methods enforce that predicates match exactly one resource to prevent ambiguity.

Stream Management

Streams returned from GetResourceStreamContent should be disposed by the caller using using statements.

Error Handling

All content retrieval methods return Result<T> objects that indicate success or failure:

  • Success: The resource was found and loaded successfully
  • Error: No matching resource found, multiple resources matched, or a loading error occurred

Common error scenarios:

  • "No resource info items found." - The predicate didn't match any resources
  • "More than one resource info item found." - The predicate matched multiple resources (content methods require a single match)

Handling Errors

var result = loader.GetResourceTextContent(x => x.Path.EndsWith("config.json"));

if (result.IsSuccess)
{
    var content = result.Value;
    // Use content
}
else
{
    foreach (var error in result.Errors)
    {
        Console.WriteLine($"Error: {error}");
    }
}

Error Prevention

// Bad: Ambiguous predicate
var result = loader.GetResourceTextContent(x => x.Path.Contains(".json"));
// Might match multiple files!

// Good: Specific predicate
var result = loader.GetResourceTextContent(x => 
    x.Path == "MyApp.Config.appsettings.json");

Best Practices

1. Use Specific Predicates

// Good: Specific path
x => x.Path == "MyApp.Resources.Templates.email.html"

// Bad: Might match multiple files
x => x.Path.Contains("email")

2. Check for Single Match First

var matches = loader.GetResourceInfoItems(x => x.Path.EndsWith(".config"));

if (matches.Count() == 1)
{
    var content = loader.GetResourceTextContent(x => x.Path.EndsWith(".config"));
}
else
{
    Console.WriteLine($"Found {matches.Count()} matches - need to be more specific");
}

3. Dispose Streams Properly

var streamResult = loader.GetResourceStreamContent(predicate);

if (streamResult.IsSuccess)
{
    using var stream = streamResult.Value;
    // Process stream
} // Stream disposed here

4. Use Assembly Types Strategically

// Load resources from specific assemblies
var loader = new EmbeddedResourceLoader(
    typeof(CoreResources),      // Core assembly
    typeof(LocalizationData),   // Localization assembly
    typeof(TemplateEngine)      // Templates assembly
);

5. Cache Loader Instances

// Create once, use many times
private static readonly EmbeddedResourceLoader _loader = 
    new(typeof(Program));

public string GetTemplate(string name)
{
    var result = _loader.GetResourceTextContent(x => x.Path.EndsWith(name));
    return result.IsSuccess ? result.Value : string.Empty;
}

6. Handle Encoding Properly

// GetResourceTextContent uses UTF-8 by default
// For other encodings, use stream and specify:
var streamResult = loader.GetResourceStreamContent(predicate);
if (streamResult.IsSuccess)
{
    using var reader = new StreamReader(
        streamResult.Value, 
        Encoding.GetEncoding("ISO-8859-1"));
    var text = reader.ReadToEnd();
}

Embedded Resource Configuration

Project File Setup

<ItemGroup>
  
  <EmbeddedResource Include="Resources\Templates\*.html" />
  <EmbeddedResource Include="Resources\Config\*.json" />
  <EmbeddedResource Include="Resources\Images\*.png" />
  
  
  <EmbeddedResource Remove="Resources\Temp\**\*" />
</ItemGroup>

Naming Conventions

Embedded resources use the following naming pattern:

{DefaultNamespace}.{RelativePath}.{FileName}

Example:

  • Project: MyApp
  • File: Resources/Templates/email.html
  • Resource Name: MyApp.Resources.Templates.email.html

Testing

The library includes comprehensive unit tests demonstrating various usage patterns:

  • Loading text resources
  • Loading JSON resources (arrays and objects)
  • Loading binary resources (images)
  • Handling missing resources
  • Handling ambiguous predicates (multiple matches)

Example Unit Test

[Fact]
public void GetResourceTextContent_ValidResource_ReturnsContent()
{
    // Arrange
    var loader = new EmbeddedResourceLoader(typeof(TestResources));
    
    // Act
    var result = loader.GetResourceTextContent(x => 
        x.Path.EndsWith("TestFile.txt"));
    
    // Assert
    result.IsSuccess.Should().BeTrue();
    result.Value.Should().NotBeNullOrEmpty();
}

[Fact]
public void GetResourceTextContent_MissingResource_ReturnsError()
{
    // Arrange
    var loader = new EmbeddedResourceLoader(typeof(TestResources));
    
    // Act
    var result = loader.GetResourceTextContent(x => 
        x.Path.EndsWith("NonExistent.txt"));
    
    // Assert
    result.IsSuccess.Should().BeFalse();
    result.Errors.Should().Contain("No resource info items found.");
}

Integration with Other Libraries

With Nabs.Launchpad.Core.Serialisation

var loader = new EmbeddedResourceLoader(typeof(Config));
var jsonResult = loader.GetResourceTextContent(x => 
    x.Path.EndsWith("settings.json"));

if (jsonResult.IsSuccess)
{
    var settings = DefaultJsonSerializer.Deserialize<AppSettings>(jsonResult.Value);
}

With Nabs.Launchpad.Core.Persistence

// Load SQL migration scripts
var loader = new EmbeddedResourceLoader(typeof(Migrations));
var scripts = loader.GetResourceInfoItems(x => 
    x.Path.Contains(".Migrations.") && x.Path.EndsWith(".sql"));

foreach (var script in scripts.OrderBy(x => x.Path))
{
    var sqlResult = loader.GetResourceTextContent(x => x.Path == script.Path);
    if (sqlResult.IsSuccess)
    {
        await dbContext.Database.ExecuteSqlRawAsync(sqlResult.Value);
    }
}

Troubleshooting

Resource Not Found

Issue: GetResourceTextContent returns "No resource info items found"

Solutions:

  • Verify the file is marked as EmbeddedResource in the .csproj file
  • Check the exact resource path using GetResourceInfoItems(x => true)
  • Ensure you're passing the correct assembly type to the constructor
  • Verify the file exists in the project

Multiple Resources Matched

Issue: GetResourceTextContent returns "More than one resource info item found"

Solutions:

  • Use more specific predicates (include more of the path)
  • Use the exact resource path: x => x.Path == "Full.Resource.Path.file.txt"
  • List all matches first with GetResourceInfoItems to see what matched

Wrong Content Encoding

Issue: Text content appears garbled

Solutions:

  • GetResourceTextContent uses UTF-8 encoding
  • For other encodings, use GetResourceStreamContent with a custom StreamReader
  • Save the source file with UTF-8 encoding

Performance Issues

Issue: Slow resource loading

Solutions:

  • Create the EmbeddedResourceLoader once and reuse it (it caches resource names)
  • Don't create new loaders for each resource access
  • Consider lazy loading for large resources

Dependencies

  • Ardalis.Result: For result pattern implementation and error handling
  • Nabs.Launchpad.Core.Serialisation: For deserializing JSON/CSV resources
  • Nabs.Launchpad.Core.Persistence: For loading SQL scripts and migrations
  • Nabs.Launchpad.Core.SeedData: For loading seed data from embedded resources
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

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
10.0.219 89 1/5/2026
10.0.218 85 1/4/2026
10.0.217 100 1/4/2026 10.0.217 is deprecated because it is no longer maintained.
10.0.216 94 1/4/2026 10.0.216 is deprecated because it is no longer maintained.
10.0.215 96 1/4/2026 10.0.215 is deprecated because it is no longer maintained.
10.0.214 97 1/1/2026 10.0.214 is deprecated because it is no longer maintained.
10.0.213 97 1/1/2026 10.0.213 is deprecated because it is no longer maintained.
10.0.212 94 1/1/2026 10.0.212 is deprecated because it is no longer maintained.
10.0.211 93 12/31/2025 10.0.211 is deprecated because it is no longer maintained.
10.0.210 102 12/30/2025 10.0.210 is deprecated because it is no longer maintained.
10.0.209 98 12/30/2025 10.0.209 is deprecated because it is no longer maintained.
10.0.208 98 12/30/2025 10.0.208 is deprecated because it is no longer maintained.
10.0.207 102 12/29/2025 10.0.207 is deprecated because it is no longer maintained.
10.0.206 96 12/29/2025 10.0.206 is deprecated because it is no longer maintained.
10.0.205 181 12/24/2025 10.0.205 is deprecated because it is no longer maintained.
10.0.204 185 12/21/2025 10.0.204 is deprecated because it is no longer maintained.
10.0.203 280 12/18/2025 10.0.203 is deprecated because it is no longer maintained.
10.0.202 282 12/17/2025 10.0.202 is deprecated because it is no longer maintained.
10.0.200 277 12/17/2025 10.0.200 is deprecated because it is no longer maintained.
10.0.199 437 12/10/2025 10.0.199 is deprecated because it is no longer maintained.
10.0.197 175 12/5/2025 10.0.197 is deprecated because it is no longer maintained.
10.0.196 681 12/3/2025 10.0.196 is deprecated because it is no longer maintained.
10.0.195 676 12/3/2025 10.0.195 is deprecated because it is no longer maintained.
10.0.194 680 12/3/2025 10.0.194 is deprecated because it is no longer maintained.
10.0.193 683 12/2/2025 10.0.193 is deprecated because it is no longer maintained.
10.0.192 187 11/28/2025 10.0.192 is deprecated because it is no longer maintained.
10.0.190 197 11/27/2025 10.0.190 is deprecated because it is no longer maintained.
10.0.189 180 11/23/2025 10.0.189 is deprecated because it is no longer maintained.
10.0.187 181 11/23/2025 10.0.187 is deprecated because it is no longer maintained.
10.0.186 164 11/23/2025 10.0.186 is deprecated because it is no longer maintained.
10.0.184 415 11/20/2025 10.0.184 is deprecated because it is no longer maintained.
10.0.181-rc3 282 11/11/2025 10.0.181-rc3 is deprecated because it is no longer maintained.
10.0.180 302 11/11/2025 10.0.180 is deprecated because it is no longer maintained.
10.0.179-rc2 293 11/11/2025 10.0.179-rc2 is deprecated because it is no longer maintained.
10.0.178-rc2 255 11/10/2025 10.0.178-rc2 is deprecated because it is no longer maintained.
10.0.177-rc2 242 11/10/2025 10.0.177-rc2 is deprecated because it is no longer maintained.
10.0.176-rc2 198 11/6/2025 10.0.176-rc2 is deprecated because it is no longer maintained.
10.0.175-rc2 207 11/6/2025 10.0.175-rc2 is deprecated because it is no longer maintained.
10.0.174-rc2 202 11/5/2025 10.0.174-rc2 is deprecated because it is no longer maintained.