This web application architecture guidance is still in draft and is subject to change.
Package Management
This guide explains how to manage dependencies in RMC .NET applications using NuGet packages and project references.
Overview
RMC applications use two methods to reference external libraries:
| Method | When to Use | Example |
|---|---|---|
| Project Reference | Active development, both projects change frequently | Local calculation library |
| Package Reference | Stable releases, published libraries | RMC.Numerics, third-party packages |
Project References
Project references point to source code in another project. Changes in the referenced project are immediately visible.
Adding a Project Reference
<!-- In WebApp.API.csproj -->
<ItemGroup>
<ProjectReference Include="..\..\CalcLibrary\CalcLibrary.csproj" />
</ItemGroup>
Or via command line:
dotnet add reference ../CalcLibrary/CalcLibrary.csproj
When to Use Project References
- Active development: Both projects are being modified
- Local testing: Need to debug across project boundaries
- Before publishing: Library is not yet packaged
Directory Structure Example
C:\GitHub\
├── MyWebApp\
│ └── backend\
│ └── WebApp.API\
│ └── WebApp.API.csproj ←── References CalcLibrary
│
└── CalcLibrary\
└── CalcLibrary.csproj ←── Referenced project
Package References (NuGet)
Package references download pre-built binaries from a NuGet server.
Adding a Package Reference
<!-- In WebApp.API.csproj -->
<ItemGroup>
<PackageReference Include="RMC.Numerics" Version="1.0.0" />
<PackageReference Include="Serilog" Version="3.1.1" />
</ItemGroup>
Or via command line:
dotnet add package RMC.Numerics --version 1.0.0
Configuring NuGet Sources
RMC uses a private NuGet feed. Add it to the NuGet configuration:
# Add USACE Nexus source
dotnet nuget add source https://www.hec.usace.army.mil/nexus/repository/consequences-nuget-public/ --name USACENexus
Or create a nuget.config file in the solution root:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
<add key="USACENexus" value="https://www.hec.usace.army.mil/nexus/repository/consequences-nuget-public/" />
</packageSources>
</configuration>
Version Management
Semantic Versioning
NuGet packages follow semantic versioning (SemVer):
| Component | When to Increment | Example Change |
|---|---|---|
| Major (X.0.0) | Breaking changes to public API | Method signature changed, class removed |
| Minor (0.X.0) | New features, backward compatible | New calculation method added |
| Patch (0.0.X) | Bug fixes, backward compatible | Fixed calculation bug |
| Prerelease (-beta) | Preview/testing releases | Testing before stable release |
Version Constraints
Specify version requirements in the project file:
<!-- Exact version -->
<PackageReference Include="RMC.Numerics" Version="1.0.0" />
<!-- Minimum version -->
<PackageReference Include="RMC.Numerics" Version="1.0.0" />
<!-- Version range (at least 1.0.0, less than 2.0.0) -->
<PackageReference Include="RMC.Numerics" Version="[1.0.0, 2.0.0)" />
<!-- Any 1.x version -->
<PackageReference Include="RMC.Numerics" Version="1.*" />
<!-- Floating prerelease -->
<PackageReference Include="RMC.Numerics" Version="1.0.0-*" />
Recommendation
For RMC applications, use exact versions to ensure reproducible builds:
<PackageReference Include="RMC.Numerics" Version="1.0.0" />
Development Workflow
During Active Development
When both the web application and calculation library are changing frequently:
<!-- Use project reference for rapid iteration -->
<ItemGroup>
<ProjectReference Include="..\..\CalcLibrary\CalcLibrary.csproj" />
</ItemGroup>
Benefits:
- Changes visible immediately
- Single debugging session across projects
- No version coordination needed
For Stable Releases
When the calculation library is stable and versioned:
<!-- Use NuGet package for reproducible builds -->
<ItemGroup>
<PackageReference Include="CalcLibrary" Version="1.0.0" />
</ItemGroup>
Benefits:
- Reproducible builds
- Clear version dependencies
- No need for library source locally
- CI/CD compatible
Hybrid Approach
During transition, keep both options available:
<ItemGroup>
<!-- Uncomment ONE of these: -->
<!-- For development (modifying library): -->
<!-- <ProjectReference Include="..\..\CalcLibrary\CalcLibrary.csproj" /> -->
<!-- For production (stable package): -->
<PackageReference Include="CalcLibrary" Version="1.0.0" />
</ItemGroup>
Common Operations
Restore Packages
Download all packages defined in the project:
dotnet restore
Update a Package
# Update to latest stable version
dotnet add package RMC.Numerics
# Update to specific version
dotnet add package RMC.Numerics --version 1.1.0
List Installed Packages
dotnet list package
Remove a Package
dotnet remove package RMC.Numerics
Clear NuGet Cache
To resolve package resolution issues:
dotnet nuget locals all --clear
Project File Structure
A typical RMC project file:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<!-- External NuGet packages -->
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.0" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.0" />
<PackageReference Include="Serilog.AspNetCore" Version="8.0.0" />
<PackageReference Include="RMC.Numerics" Version="1.0.0" />
</ItemGroup>
<!-- Local project references (development) -->
<ItemGroup>
<ProjectReference Include="..\..\CalcLibrary\CalcLibrary.csproj" />
</ItemGroup>
</Project>
Transitive Dependencies
NuGet automatically handles transitive dependencies—packages that project packages depend on.
Viewing the Dependency Graph
dotnet list package --include-transitive
Pinning Transitive Versions
To override a transitive dependency version:
<ItemGroup>
<PackageReference Include="System.Text.Json" Version="8.0.0" />
</ItemGroup>
CI/CD Considerations
Package Restoration in CI
Always restore packages before building:
# GitHub Actions example
steps:
- name: Restore packages
run: dotnet restore
- name: Build
run: dotnet build --no-restore
- name: Test
run: dotnet test --no-build
Private Feed Authentication
For private NuGet feeds in CI, use environment variables:
- name: Add private NuGet source
run: |
dotnet nuget add source ${{ secrets.NUGET_FEED_URL }} \
--name PrivateFeed \
--username ${{ secrets.NUGET_USERNAME }} \
--password ${{ secrets.NUGET_PASSWORD }} \
--store-password-in-clear-text
Troubleshooting
Package Not Found
-
Verify the package source is configured:
dotnet nuget list source -
Check if the package exists on the source:
dotnet search PackageName --source USACENexus -
Try clearing the cache:
dotnet nuget locals all --clear
Version Conflicts
When two packages require different versions of a shared dependency:
-
Check the conflict:
dotnet list package --include-transitive -
Pin the shared dependency to a compatible version:
<PackageReference Include="SharedDependency" Version="X.Y.Z" />
Restore Fails in CI
- Ensure nuget.config is in the repository root
- Verify feed credentials are configured
- Check that the feed URL is accessible from CI environment
Best Practices
Do
- Use exact versions for reproducibility
- Include nuget.config in version control
- Document required NuGet sources in README
- Update packages regularly (security patches)
- Test after package updates
Don't
- Use floating versions in production
- Commit NuGet packages to version control (use restore)
- Mix project and package references to the same library
- Ignore version conflicts
- Skip restoration in CI pipelines