Skip to content

Package and Namespace Versioning Strategy for CIM Profile DTOs

Context and Problem Statement

We need to support simultaneous deployment of multiple IEC 61970 CIM profile versions (2.4.15 and 3.0.0) in our Web API while maintaining:

  1. Clear separation between versions
  2. NuGet package independence
  3. CI/CD-friendly versioning
  4. Discoverable DTO structures
  5. Endpoint version parity

How should we structure NuGet packages and namespaces to enable clean version isolation while supporting multiple active API endpoints?

Decision Drivers

  • Need for parallel installation of multiple CIM versions
  • Requirement for explicit version mapping between packages and API endpoints
  • CI/CD pipeline compatibility for automated package generation
  • Prevention of accidental cross-version DTO usage
    • Client clarity in package dependencies
  • Compliance with Semantic Versioning standards

Considered Options

  1. Separate NuGet Package per Full Version (GridLab.Gmss.Cgmes.3.0.0)
  2. Single Package with Versioned Namespaces (GridLab.Gmss.Cgmes)

Decision Outcome

Chosen option: "Separate NuGet Package per Full Version", because it provides:

  • Absolute version isolation at package level
  • Clear dependency tracking in consumer projects
  • Simplified CI/CD pipeline implementation
  • Direct correlation between API version and package version
  • Safe deprecation path for older versions

Consequences

  • Good:

    • Package version directly maps to API version (3.0.0 package ↔ /api/v3.0.0)
    • No possibility of version conflict in dependencies
    • Automated pipeline can generate packages without merge conflicts
    • Enables differential updates between major/minor versions
  • Bad:

    • Potential duplication of identical DTOs across packages
    • Requires strict namespace versioning discipline
    • Slightly increased storage requirements for NuGet repository

Confirmation

Implementation will be verified through:

  1. ArchUnit validation of namespace-version correlation
  2. Pipeline-generated package metadata checks
  3. API version integration tests
// ArchUnit rule example
Classes().That().ResideInNamespace(".*\.Dtos\.V\d+", true)
.Should().BePublic()
.Check();

Pros and Cons of the Options

Separate NuGet Package per Full Version

  • Good:

    • 💡 Explicit PackageReference versions in consumer projects
    • 🛡️ 100% version isolation in IL level
    • 🔀 Enables side-by-side installation
    • 📈 Clear version adoption metrics via NuGet stats
    • 🔧 Simplifies hotfixes to specific versions
  • Neutral:

    • Requires namespace versioning convention
  • Bad:

    • Slightly more complex initial setup

Single Package with Versioned Namespaces

  • Good:

    • Single package to manage
    • Smaller artifact repository footprint
  • Bad:

    • ❗ Risk of implicit version mixing
    • 🔄 Requires full recompilation for version updates
    • 🚫 Impossible to use multiple versions simultaneously
    • 📉 Hard to track actual version usage

More Information

Version Mapping Table

API Endpoint NuGet Package Namespace Suffix
/api/v2.4.15/ GridLab.Gmss.Cgmes.2.4.15 .Dtos.V2
/api/v3.0.0/ GridLab.Gmss.Cgmes.3.0.0 .Dtos.V3

Semantic Versioning Reference