Guidance for AI coding agents working in this repository. Human-facing documentation is in README.md.
Spring.NET is a port and extension of the Java Spring Framework for .NET: IoC container, AOP, expression language, declarative transaction management, ADO.NET framework, ASP.NET (WebForms/MVC5/WebAPI) integration, NHibernate 5, Quartz.NET, messaging (MSMQ, NMS, TIBCO EMS), NVelocity templating, and NUnit/MSTest testing support. Apache 2.0 licensed. Packages are published to NuGet from git tags (v*.*.*) via NuGet Trusted Publishing (GitHub OIDC), not a stored API key.
Build orchestration is Fallout (build-support/build), the maintained successor to NUKE. Root-level bootstrap scripts install the pinned .NET SDK if missing (global.json: 10.0.100, rollForward latestMinor), then run the build through the fallout local tool (dotnet tool restore + dotnet fallout).
./build.cmd # Windows (build.sh on Linux/macOS); default target = Compile
./build.cmd Compile # build Spring.Net.sln (+ examples, Windows only)
./build.cmd Test # run the default test suite
./build.cmd Ci # Compile + Test + Pack — what CI runs
./build.cmd Clean
./build.cmd Antlr # regenerate the expression-language parser (Windows only)
Plain dotnet CLI works too — the solution is Spring.Net.sln:
dotnet build Spring.Net.sln
dotnet test test/Spring/Spring.Core.Tests/Spring.Core.Tests.csproj
dotnet test test/Spring/Spring.Core.Tests/Spring.Core.Tests.csproj -f net8.0 --filter "FullyQualifiedName~XmlObjectFactoryTests"
- Test framework is NUnit 3 (
Spring.Testing.Microsoft.Testsalone uses MSTest); mocking uses FakeItEasy. - CI (
.github/workflows/ci.yml) runs./build.cmd cion windows-latest and./build.sh cion ubuntu-latest for every PR tomain. - Warnings are errors in
src/andtest/(TreatWarningsAsErrors=True), and formatting rule IDE0055 is warning severity — a formatting violation fails the build. - Build output goes to
build/$(Configuration)/$(ProjectName)/(not in-placebin/); NuGet packages toartifacts/.
Fallout's Test target excludes *.Integration.Tests projects (and Spring.Web.Conversation.NHibernate5.Tests) by default; they need external infrastructure and are gated behind flags: --test-full, --test-integration-data, --test-integration-nms, --test-integration-ms-mq, --test-integration-ems. Spring.Services.Tests is always excluded. Several test projects are Windows-only (net462: Web, Mvc5, Velocity, Messaging/MSMQ).
- SQL Server-backed tests (
Spring.Data.Integration.Tests,Spring.Data.NHibernate5.Integration.Tests,Spring.Scheduling.Quartz3.Integration.Tests):docker-compose.ymlbrings up SQL Server; setup scripts inbuild-support/*.sqland the test projects'Data/folders. See README.md "Running tests" for the full recipe. - TIBCO EMS projects need
TIBCO.EMS.dll(not in the repo) and are excluded from the solution build; enable with--build-ems.
src/Spring/ has one directory per shipped assembly. All projects use RootNamespace=Spring and source folders mirror namespaces. Dependency spine: Spring.Core → Spring.Aop → Spring.Data → everything else.
| Project | Purpose |
|---|---|
| Spring.Core | IoC container, expression language, validation, dynamic reflection |
| Spring.Aop | AOP framework (dynamic proxies, advice, pointcuts) |
| Spring.Data | Transaction management + ADO.NET framework |
| Spring.Data.NHibernate5 | NHibernate 5 integration (RootNamespace Spring.Data.NHibernate) |
| Spring.Web / .Extensions / .Mvc5 | ASP.NET WebForms / AJAX / MVC5+WebAPI integration (net462 only) |
| Spring.Services | Remoting, web services, Enterprise Services (net462 only) |
| Spring.Messaging / .Nms / .Ems | MSMQ / Apache NMS / TIBCO EMS integration |
| Spring.Scheduling.Quartz3 | Quartz.NET 3.x integration |
| Spring.Template.Velocity(.Castle) | NVelocity templating |
| Spring.Testing.NUnit / .Microsoft | DI-enabled test fixture base classes |
Key mechanics (defined in src/Directory.Build.props and test/Directory.Build.props — there is no root Directory.Build.props):
- Multi-targeting: most libraries target
netstandard2.0;net462; web/services/EMS projects are net462-only. Projects reference the shared MSBuild variable$(TargetFullFrameworkVersion)(= net462) instead of literal TFMs. Framework differences are handled with conditional<Compile Remove>/<ItemGroup>blocks in csproj files, not scattered#ifdirectives. - Strong naming: all assemblies signed with the committed
Spring.Net.snk. - Central package management: versions live in
Directory.Packages.props; csprojPackageReferences are versionless. - ANTLR expression parser: the grammar is
src/Spring/Spring.Core/Expressions/Expression.g. The generated lexer/parser underExpressions/Parser/and a vendored, hand-patched ANTLR 2.7.7 runtime underExpressions/Parser/antlr/are committed — never hand-edit generated files; regenerate with./build.cmd Antlr(seesrc/Spring/Spring.Core/README_ANTLR.txt). - Versioning: the git tag is the version authority (
v3.1.0→ 3.1.0); untagged builds fall back to theProjectVersionplaceholder inbuild-support/build/Build.csplus adev-/preview-suffix. Publishing runs from the tag workflow only.DetermineVersion()sets three distinct facets, applied to bothCompileandPackso packaged andbin/assemblies agree:AssemblyVersionis pinned tomajor.minor.0.0(the assemblies are strong-named, so this is their binding identity — keeping it stable across patches means consumers need no new binding redirect for a fix release),FileVersioncarries the exact numeric version, andInformationalVersionis left to MSBuild so SourceLink can append+<sha>. Never set a bareVersionproperty instead — it overrides the prefix/suffix composition and silently drops the preview suffix. - Trusted publishing:
.github/workflows/publish.ymlis the only workflow allowed to push to nuget.org. It needspermissions: id-token: writeandenvironment: nuget; thePublishtarget exchanges that OIDC token for a short-lived API key inbuild-support/build/Build.Publish.cs. The nuget.org policy is keyed to the workflow filenamepublish.ymlplus thenugetenvironment, so renaming, moving or splitting that workflow breaks publishing until the policy is updated. Do not reintroduce aNUGET_API_KEYsecret — theNuGetApiKeyparameter stays only as a manual override. - In test projects,
ILogis a global using alias forMicrosoft.Extensions.Logging.ILogger.
.editorconfig is authoritative: 4-space indents (2 for XML/props/ps1), Allman braces, System usings first, no this. qualification, language keywords over BCL type names, instance fields _camelCase, static fields s_camelCase. Match the surrounding code's style. (The [src/{Analyzers,...}/**] sections were copied from the Roslyn repo and match nothing here — ignore them.)
Logging: all ILogger calls use constant message templates with PascalCase named placeholders (log.LogDebug("Creating object '{ObjectName}'", name)) — never interpolation, concatenation, or string.Format. Pass exceptions to the exception-first overloads; wrap inherently dynamic text as Log*("{Message}", text). Analyzers CA2254/CA2253/CA2017/CA1727 enforce this as build errors. Only guard a log call with IsEnabled when argument evaluation is expensive (string building, method calls) — templates already defer formatting.
- NAnt-era build files, superseded by the Fallout build but still committed:
Spring.build,*.include,Build-ci.cmd,build-release-all.cmd,appveyor.yml.old, most ofbuild-support/(exception:build-support/tools/antlr-2.7.6is still used by theAntlrtarget). dev-support/,templates/— VS 2008-era templates.lib/— checked-in legacy third-party DLLs.doc/— DocBook sources + vendored toolchain (CI ignoresdoc/**).- Orphan test folders not in the solution (reference removed projects):
test/Spring/Spring.Web.Mvc.Tests,Spring.Messaging.Ems.Tests,Spring.Data.NHibernate.Tests.
website/ is a Gatsby 5 + React + TypeScript site (package manager: yarn). Local dev: yarn install && yarn start. The full build is ./build.sh website (Fallout target; also builds the DocBook reference docs, which require Java on PATH). Deployed to GitHub Pages by .github/workflows/website.yml on pushes to main.