jjm.one.ExceptionFormatter 0.0.1-alpha.2

This is a prerelease version of jjm.one.ExceptionFormatter.
dotnet add package jjm.one.ExceptionFormatter --version 0.0.1-alpha.2
                    
NuGet\Install-Package jjm.one.ExceptionFormatter -Version 0.0.1-alpha.2
                    
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="jjm.one.ExceptionFormatter" Version="0.0.1-alpha.2" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="jjm.one.ExceptionFormatter" Version="0.0.1-alpha.2" />
                    
Directory.Packages.props
<PackageReference Include="jjm.one.ExceptionFormatter" />
                    
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 jjm.one.ExceptionFormatter --version 0.0.1-alpha.2
                    
#r "nuget: jjm.one.ExceptionFormatter, 0.0.1-alpha.2"
                    
#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.
#addin nuget:?package=jjm.one.ExceptionFormatter&version=0.0.1-alpha.2&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=jjm.one.ExceptionFormatter&version=0.0.1-alpha.2&prerelease
                    
Install as a Cake Tool

jjm.one.ExceptionFormatter

A lightweight .NET library to simplify and standardize exception creation with templated messages and structured data.


Table of Contents


Overview

jjm.one.ExceptionFormatter is a lightweight .NET library that lets you:

  • Define exception messages with named placeholders (e.g. "User {UserId} failed on {Operation}").
  • Provide an array of (string Key, object? Value) pairs to fill in every {Key}—leaving unknown placeholders intact.
  • Instantiate any exception type TException via its best‐matching public constructor, preserving inner exceptions when supported.
  • Populate the exception’s Data dictionary with all provided args, even those not present in the template.
  • New: format messages and create exceptions without populating Data, using the Format<T> method.
  • Handle null or empty templates/args gracefully and survive internal formatting or construction errors without blowing up.

Features

  • Single‑pass, span‑based templating via ValueStringBuilder ‒ O(n) time, minimal allocations.
  • Delegate‑cached constructors ‒ reflection only on first use, then direct invocation.
  • Unknown placeholders preserved{Missing} remains literal.
  • All provided args end up in Exception.Data, even unused ones (when using FormatWithData).
  • Optional no‑data mode: call Format<T> to skip Data population entirely.
  • Graceful fallbacks on formatting or constructor failures.
  • Null‑tolerant: template or args may be null.
  • No external dependencies beyond the .NET BCL.

Installation

Install the package from NuGet:

dotnet add package jjm.one.ExceptionFormatter --version <VERSION>

Usage

using jjm.one.ExceptionFormatter;

// --- With Data attachment ---
throw ExceptionFormatter.FormatWithData<InvalidOperationException>(
    "User {UserId} failed on {Operation}",
    new[] { ("UserId", 123), ("Operation", "CreateOrder") }
);

// --- Without Data attachment ---
throw ExceptionFormatter.Format<InvalidOperationException>(
    "User {UserId} failed on {Operation}",
    new[] { ("UserId", 123), ("Operation", "CreateOrder") }
);

Preserving an inner exception:

try
{
    // some code that throws…
}
catch (Exception ex)
{
    // with Data
    throw ExceptionFormatter.FormatWithData<ConfigurationException>(
        "Failed to load config from {Path}",
        new[] { ("Path", configPath) },
        innerException: ex
    );
    
    // or without Data
    // throw ExceptionFormatter.Format<ConfigurationException>(
    //     "Failed to load config from {Path}",
    //     new[] { ("Path", configPath) },
    //     innerException: ex
    // );
}

API Reference

namespace jjm.one.ExceptionFormatter
{
    public static class ExceptionFormatter
    {
        /// <summary>
        /// Formats a message template, creates a TException, and populates its Data dictionary.
        /// </summary>
        public static TException FormatWithData<TException>(
            string? template,
            (string Key, object? Value)[]? args = null,
            Exception? innerException = null
        ) where TException : Exception;

        /// <summary>
        /// Formats a message template, creates a TException, but does NOT populate its Data dictionary.
        /// </summary>
        public static TException Format<TException>(
            string? template,
            (string Key, object? Value)[]? args = null,
            Exception? innerException = null
        ) where TException : Exception;
    }
}

Examples

Basic Formatting

var ex = ExceptionFormatter.FormatWithData<Exception>(
    "Coordinates: {X}, {Y}",
    new[] { ("X", 42), ("Y", -7) }
);
// ex.Message == "Coordinates: 42, -7"
// ex.Data["X"] == 42, ex.Data["Y"] == -7

Unknown Placeholder Preservation

var ex = ExceptionFormatter.FormatWithData<Exception>(
    "Missing: {A}, {B}",
    new[] { ("A", "apple") }
);
// ex.Message == "Missing: apple, {B}"
// ex.Data contains "A" but not "B"

Unused Args Still Added

var ex = ExceptionFormatter.FormatWithData<Exception>(
    "No placeholders here",
    new[] { ("Foo", 100) }
);
// ex.Message == "No placeholders here"
// ex.Data["Foo"] == 100

Formatting Without Data Attachment

var ex1 = ExceptionFormatter.Format<Exception>(
    "User {Id} not found",
    new[] { ("Id", 999) }
);
// ex1.Message == "User 999 not found"
// ex1.Data.Count == 0

var ex2 = ExceptionFormatter.Format<ArgumentException>(
    "Bad argument {Name}",
    new[] { ("Name", "param") },
    new InvalidOperationException("cause")
);
// ex2 is ArgumentException with InnerException == "cause"
// ex2.Data.Count == 0

License

The jjm.one.ExceptionFormatter library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License v3.0 (LGPL‑3.0) as published by the Free Software Foundation.

This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the LICENSE or https://www.gnu.org/licenses/lgpl-3.0.html for more details.


© 2025 jjm.one. Licensed under the GNU Lesser General Public License v3.0.

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 was computed.  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.
  • net9.0

    • No dependencies.

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
0.0.1-alpha.2 104 4/18/2025
0.0.1-alpha.1 104 4/18/2025