EllipticBit.SDLang.DependencyInjection 2.0.0

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

EllipticBit.SDLang

A fast SDLang (Simple Declarative Language) parser, mutable DOM, and object serializer for .NET, designed to feel like System.Text.Json.

SDLang is a concise, human-friendly document language similar to XML or JSON. EllipticBit.SDLang lets you:

  • Parse and emit SDLang documents through a high-performance, span-based UTF-8 reader and writer.
  • Work with a mutable DOM (SdlDocument, Tag, SdlValue) — the SDLang analog of JsonDocument/JsonElement.
  • Serialize and deserialize .NET object graphs with attributes and options that mirror System.Text.Json.

pipeline status

Targets .NET 10 (net10.0). AOT support is out of scope for this project at this time.

Deprecation notice: The previous release, EllipticBit.SDLang 1.0.1, is deprecated and is superseded by this package. Please upgrade to the current version.


Installation

dotnet add package EllipticBit.SDLang

For Microsoft.Extensions.DependencyInjection integration:

dotnet add package EllipticBit.SDLang.DependencyInjection

For ASP.NET Core (MVC and Minimal API) integration:

dotnet add package EllipticBit.SDLang.AspNetCore

SDLang in 30 seconds

// A tag has a name, optional values, optional attributes, and optional children.
greeting "Hello World"

person "Alice" age=42 active=true {
	address "1 Main St" city="Springfield"
}

matrix {
	row 1 2 3
	row 4 5 6
}
  • Values are positional literals ("Alice", 1, true).
  • Attributes are name=value pairs.
  • Children live inside { } blocks.
  • Tags may be namespaced (ns:config).

Quick start: parse and query the DOM

using EllipticBit.SDLang;

SdlDocument document = SdlDocument.Parse("""
	person "Alice" age=42 active=true {
		address "1 Main St" city="Springfield"
	}
	""");

Tag person = document.Tags[0];

string name = person.Value!.AsString();          // "Alice"
int age = person.Attributes["age"].AsInt32();    // 42
bool active = person.Attributes["active"].AsBoolean(); // true

Tag address = person.Children[0];
string city = address.Attributes["city"].AsString(); // "Springfield"

Build and emit a document

using EllipticBit.SDLang;

SdlDocument document = new();
Tag server = document.AddTag("server");
server.SetAttribute("host", "localhost");
server.SetAttribute("port", 8080);
server.AddChild("endpoint").AddValue("/api");

// Compact output...
string sdl = document.ToSdlString();

// ...or pretty-printed with indentation.
string indented = document.ToSdlString(new SdlWriterOptions { Indented = true });

Object serialization

Serialization mirrors System.Text.Json: call the static SdlSerializer facade with your type.

using EllipticBit.SDLang.Serialization;

public sealed class Server
{
	public string Host { get; set; } = "localhost";
	public int Port { get; set; }
	public bool Enabled { get; set; }
}

var server = new Server { Host = "db.local", Port = 5432, Enabled = true };

string sdl = SdlSerializer.Serialize(server);
Server? roundTripped = SdlSerializer.Deserialize<Server>(sdl);

Controlling the shape with attributes

By default, scalar members become attributes. Use attributes to map members onto SDLang's value, attribute, and child roles:

using EllipticBit.SDLang.Serialization;

public sealed class Person
{
	[SdlValue(0)]                       // positional tag value
	public string Name { get; set; } = "";

	[SdlAttribute]                      // name=value attribute
	public int Age { get; set; }

	[SdlChild]                          // nested child tag
	public Address? Home { get; set; }

	[SdlIgnore(Condition = SdlIgnoreCondition.WhenWritingNull)]
	public string? Nickname { get; set; }
}

Other attributes include [SdlPropertyName], [SdlPropertyOrder], [SdlNamespace], [SdlConverter], [SdlConstructor], [SdlInclude], and [SdlExtensionData].

Async and UTF-8 APIs

using EllipticBit.SDLang.Serialization;

// Stream-based async serialization.
await SdlSerializer.SerializeAsync(stream, server);
stream.Position = 0;
Server? result = await SdlSerializer.DeserializeAsync<Server>(stream);

// Stay on UTF-8 bytes to avoid UTF-16 conversions.
byte[] utf8 = SdlSerializer.SerializeToUtf8Bytes(server);
Server? fromBytes = SdlSerializer.Deserialize<Server>(utf8);

Options (parity with JsonSerializerOptions)

using EllipticBit.SDLang.Serialization;

var options = new SdlSerializerOptions
{
	WriteIndented = true,
	PropertyNamingPolicy = SdlNamingPolicy.CamelCase,
	PropertyNameCaseInsensitive = true,
	DefaultIgnoreCondition = SdlIgnoreCondition.WhenWritingNull,
	ReferenceHandler = SdlReferenceHandler.Preserve, // round-trips shared/cyclic graphs via $id/$ref
};

string sdl = SdlSerializer.Serialize(server, options);

Supported options include WriteIndented, MaxDepth, PropertyNamingPolicy, PropertyNameCaseInsensitive, DefaultIgnoreCondition, NumberHandling, UnmappedMemberHandling, ReadCommentHandling, ReferenceHandler, IncludeFields, and custom Converters. Options become read-only on first use, just like System.Text.Json.


Dependency Injection

The EllipticBit.SDLang.DependencyInjection package wires SdlSerializerOptions into the options pattern.

using EllipticBit.SDLang.DependencyInjection;
using EllipticBit.SDLang.Serialization;
using Microsoft.Extensions.DependencyInjection;

services.AddSdlSerializerOptions(options =>
{
	options.WriteIndented = true;
	options.PropertyNamingPolicy = SdlNamingPolicy.CamelCase;
});

// Register a custom converter (instance or type, optionally named).
services.AddSdlConverter<TemperatureConverter>();
services.AddSdlSerializerOptions("compact", options => options.WriteIndented = false);

Resolve the configured options anywhere via constructor injection:

public sealed class ConfigWriter(SdlSerializerOptions options)
{
	public string Write(Server server) => SdlSerializer.Serialize(server, options);
}

Named options are available through IOptionsMonitor<SdlSerializerOptions> / IOptionsSnapshot<SdlSerializerOptions>.


ASP.NET Core

The EllipticBit.SDLang.AspNetCore package lets you use SDLang as an HTTP request and response document language — the SDLang counterpart to the built-in JSON and XML support — for both MVC controllers and Minimal APIs.

Content is negotiated through these media types, and the .sdl URL/format suffix maps to application/sdlang:

Media type Purpose
application/sdlang Primary SDLang media type
text/sdlang Text-oriented SDLang media type

MVC controllers

Register the SDLang formatters on your MVC builder. The optional delegate configures the shared SdlSerializerOptions used to read and write payloads (it flows through AddSdlSerializerOptions):

using EllipticBit.SDLang.Serialization;
using Microsoft.Extensions.DependencyInjection;

builder.Services
	.AddControllers()
	.AddSdlFormatters(options =>
	{
		options.WriteIndented = true;
		options.PropertyNamingPolicy = SdlNamingPolicy.CamelCase;
	});

Controllers then accept and return your types as usual; clients select SDLang via the Accept and Content-Type headers (or a .sdl format suffix):

[ApiController]
[Route("api/servers")]
public sealed class ServersController : ControllerBase
{
	[HttpPost("echo")]
	public Server Echo([FromBody] Server server) => server;

	[HttpGet]
	public Server Get() => new() { Host = "localhost", Port = 8080, Enabled = true };
}

A malformed SDLang request body is reported as a model-state error, producing an HTTP 400 response.

Minimal APIs

Bind an SDLang request body by declaring a parameter of type Sdl<T>, and write SDLang responses with Results.Extensions.Sdl(...):

using EllipticBit.SDLang.AspNetCore.Http;

builder.Services.AddSdlFormatters(); // optional; registers SdlSerializerOptions for the resolver

app.MapPost("/servers/echo", (Sdl<Server> body) => Results.Extensions.Sdl(body.Value));
app.MapGet("/servers", () => Results.Extensions.Sdl(new Server { Host = "localhost", Port = 8080 }));

A malformed body bound through Sdl<T> surfaces as a BadHttpRequestException (HTTP 400).

Prefer to work with the request/response directly? Use the HttpRequest/HttpResponse helpers:

using EllipticBit.SDLang.AspNetCore.Http;

app.MapPost("/servers/raw", async (HttpRequest request, HttpResponse response) =>
{
	Server? server = await request.ReadFromSdlAsync<Server>();
	await response.WriteAsSdlAsync(server);
});

Custom converters

Derive from SdlConverter<T> and register it via options or the [SdlConverter] attribute:

using EllipticBit.SDLang;
using EllipticBit.SDLang.Serialization;

public sealed class TemperatureConverter : SdlConverter<Temperature>
{
	public override Temperature Read(SdlValue value, SdlSerializerOptions options)
		=> new(value.AsDouble());

	public override SdlValue Write(Temperature value, SdlSerializerOptions options)
		=> SdlValue.Create(value.Celsius);
}

[SdlConverter(typeof(TemperatureConverter))]
public sealed class Temperature(double celsius)
{
	public double Celsius { get; } = celsius;
}

Security and performance

SDLang documents frequently come from untrusted sources, so the parser is hardened against malformed input:

  • UTF-8 only end to end, avoiding UTF-16 conversions where possible (ReadOnlySpan<byte>/IBufferWriter<byte>).
  • Strict UTF-8 validation rejects malformed byte sequences with a located SdlReaderException.
  • Configurable MaxDepth guards against deeply nested "depth bomb" inputs.
  • Unterminated strings/comments, invalid base64, and numeric overflow raise typed exceptions with line/column info.
  • Full Unicode support, including emoji (😀) and Kanji (漢字) in identifiers, values, and string literals.

Contributing

Contributions are welcome! Please read CONTRIBUTING.md before opening a pull request.

LLM contributions: Any contribution generated with the assistance of a Large Language Model must include the prompt(s) used to generate it in the PROMPTS.txt file at the repository root.


License

Licensed under the Boost Software License 1.0 (BSL-1.0).

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 (1)

Showing the top 1 NuGet packages that depend on EllipticBit.SDLang.DependencyInjection:

Package Downloads
EllipticBit.SDLang.AspNetCore

Package Description

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2.0.0 111 6/25/2026