Strongbars 1.3.2
See the version list below for details.
dotnet add package Strongbars --version 1.3.2
NuGet\Install-Package Strongbars -Version 1.3.2
<PackageReference Include="Strongbars" Version="1.3.2" />
<PackageVersion Include="Strongbars" Version="1.3.2" />
<PackageReference Include="Strongbars" />
paket add Strongbars --version 1.3.2
#r "nuget: Strongbars, 1.3.2"
#:package Strongbars@1.3.2
#addin nuget:?package=Strongbars&version=1.3.2
#tool nuget:?package=Strongbars&version=1.3.2
Strongbars
Compile-time, type-safe, zero-runtime-error templates for .NET
Why Strongbars?
Most template engines discover missing variables at runtime. Stronbars discovers them at compile time via a C# source generator. You get:
- IntelliSense for every template parameter
- Build errors instead of blank or broken output
- No reflection, no dynamic compilation, no runtime failures
- Very fast templating (I haven't bothered to benchmark. Sorry)
Think of it as “Razor without the runtime” or “Mustache with a compiler”.
Motivation
I developed Strongbars after using string interpolation for my various micro-webapps. Having used a variety of different templating engines they are all very dependent on dynamically typed input and are in my opinion both way too extensive and too difficult to debug. I was unable to find a templating engine that gave me the compile-time validation so string interpolation seemed to be the only way. However this left me with a lot of HTML code in the middle of a c# file. Not super good developer UX. I missed dedicated files for the templates, but were unable to find any tool that fit my style. This gave me the best of both worlds.
Install
dotnet add package Strongbars
How it works
Add something like this to your *.csproj:
<ItemGroup>
<AdditionalFiles Include="Pages/*.html" StrongbarsNamespace="Sample.Pages" />
</ItemGroup>
Every file in Pages becomes a strongly-typed class.
Hello.html:
<p>
Hello {{ firstName }} {{ lastName }}
</p>
Build → the generator produces:
public class Name
{
public Name(string firstName, string lastName) {
...
}
public string Render() => ...
}
Usage:
using Sample.Pages
var template = new Hello(firstName: "Alex", lastName: "Smith");
Console.WriteLine(template.Render());
Output:
<p>
Hello Alex Smith
</p>
You could also use the same variable multiple times, i.e:
Hello.html:
<p>
Hello {{ firstName }} {{ lastName }} - {{ firstName }} is a pretty name!
</p>
See example for a complete(r) example.
Loops?
Handlebars.js and similar frameworks have loops and other helpers. They are not supported by design. Strongbars encourage high modularity and truely logic less templating. Instead, Strongbars allow a syntax for defining a variable as an array, which will then be concatenatted. This forces you to create very narrow and modular files, for better or worse (IMO better). I.e to implement the same code as in the link you need two files:
PeopleList.html:
<ul class="people_list">
{{ ..items }}
</ul>
ListItem.html:
<li>
{{value}}
</li>
Which can be used like this:
var template = new PeopleList([
new ListItem("Yehuda Katz"),
new ListItem("Alan Johnson"),
new ListItem("Charles Jolley"),
]);
Warning
If a template has a variable of the same name multiple places with both .. and without, it will fail.
Conditionals?
Similar to loops, conditionals are not supported. Any if/else has to be defined in your application-code.
I.e to do the if statement in the handlebar example, you would do:
Entry.html:
<div class="entry">
{{ author? }}
</div>
EntryAuthor.html:
<h1>{{firstName}} {{lastName}}</h1>
Which can be used like this:
var template = new Entry(
author
? new EntryAuthor(firstName: "Casper", lastName: "Bang")
: null
);
If one wanted another fallback (i.e and actual if-else) you'd do:
AuthorUnknown.html:
<h1>Author unknown - Sorry</h1>
var template = new Entry(
author
? new EntryAuthor(firstName: "Casper", lastName: "Bang")
: new AuthorUnknown()
);
Warning
If a variable is both marked as optional and not optional it will fallback to being not-optional.
Current feature set
- Variable injection:
{{foo}} - Iterable variables: a
..preceding a variable name, i.e{{..foo}} - Optional variables: a
?after the variable name, i.e{{foo?}}(Can be combine with iterables) - Whitespace inside delimiters is ignored
- Works in any text-based file (HTML, JSON, SQL, etc.)
- Generated code is internal by default; visibility can be tweaked via item metadata
Roadmap
- Automatic HTML-encoding for
.htmlfiles - Custom delimiters via
.csprojproperty
Thanks to
Strongly inspired and forked from ConstEmbed
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. 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. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- Strongbars.Abstractions (>= 1.3.2)
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 |
|---|---|---|
| 1.4.3 | 699 | 3/19/2026 |
| 1.4.2 | 128 | 3/15/2026 |
| 1.4.0 | 118 | 3/13/2026 |
| 1.3.2 | 111 | 2/16/2026 |
| 1.3.1 | 111 | 2/16/2026 |
| 1.3.0 | 118 | 2/11/2026 |
| 1.2.1 | 119 | 2/11/2026 |
| 1.2.0 | 108 | 2/11/2026 |
| 1.1.10 | 160 | 1/20/2026 |
| 1.1.9 | 112 | 1/20/2026 |
| 1.1.8 | 120 | 1/20/2026 |
| 1.1.7 | 118 | 1/20/2026 |
| 1.1.6 | 117 | 1/20/2026 |
| 1.1.5 | 114 | 1/20/2026 |
| 1.1.4 | 132 | 1/20/2026 |
| 1.1.3 | 134 | 1/20/2026 |
| 1.1.2 | 120 | 1/19/2026 |
| 1.1.1 | 114 | 1/19/2026 |
| 1.0.4 | 120 | 1/16/2026 |
| 1.0.3 | 118 | 1/16/2026 |