Ghanavats.Domain.Primitives
1.0.3
dotnet add package Ghanavats.Domain.Primitives --version 1.0.3
NuGet\Install-Package Ghanavats.Domain.Primitives -Version 1.0.3
<PackageReference Include="Ghanavats.Domain.Primitives" Version="1.0.3" />
<PackageVersion Include="Ghanavats.Domain.Primitives" Version="1.0.3" />
<PackageReference Include="Ghanavats.Domain.Primitives" />
paket add Ghanavats.Domain.Primitives --version 1.0.3
#r "nuget: Ghanavats.Domain.Primitives, 1.0.3"
#addin nuget:?package=Ghanavats.Domain.Primitives&version=1.0.3
#tool nuget:?package=Ghanavats.Domain.Primitives&version=1.0.3
Ghanavats.Domain.Primitives
Overview
This package provides essential building blocks for creating expressive and consistent domain layers, including support for Value Objects, Entities, Aggregate Root tagging, and domain event dispatching.
✨ Features
✅ EntityBase with identity and equality support
✅ ValueObject base class with built-in equality and immutability handling
✅ AggregateRoot attribute to clearly tag aggregate roots
✅ Domain event infrastructure to publish and handle domain events
📦 Installation
Install via NuGet:
dotnet add package Ghanavats.Domain.Primitives
🧱 Core Components
EntityBase
Base class for domain entities with identity-based equality comparison.
ValueObject
Base class for creating immutable value objects with structural equality. Example:
public class Money : ValueObject
{
public decimal Amount { get; }
public string Currency { get; }
public Money(decimal amount, string currency)
{
Amount = amount;
Currency = currency;
}
protected override IEnumerable<object> GetEqualityComponents()
{
yield return Amount;
yield return Currency;
}
}
[AggregateRoot] Attribute
Instead of forcing an IAggregateRoot interface, this attribute provides a clean way to tag aggregate roots.
[AggregateRoot]
public class Order : EntityBase
{
// Domain logic...
}
🧩 What's the issue with empty marker interfaces?
In traditional DDD, it’s common to define an interface like this:
public interface IAggregateRoot { }
And then have your aggregates implement it:
public class Order : EntityBase, IAggregateRoot
{
// Domain logic
}
This interface has no methods or properties — it’s purely used as a marker. However, analysers (like from Roslyn or tools like ReSharper and StyleCop) often raise warnings about this pattern:
IDE0067 / CA1040: "Do not declare empty interfaces."
This is because:
- Empty interfaces don’t convey behaviour, which is the primary purpose of an interface in OOP.
- They're hard to reflect on meaningfully in tooling and might cause confusion in large codebases.
- They are often better replaced with attributes, which are purpose-built for adding metadata.
✅ Why [AggregateRoot] is better
By switching to a custom attribute, you're using a more semantically correct and analyser-friendly approach for metadata tagging.
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
public sealed class AggregateRootAttribute : Attribute
{
}
🛠️ Use-case for [AggregateRoot]
If you’re doing something like domain scanning (e.g. identifying aggregate roots at startup or validation), you can reflect on this attribute easily:
var aggregateRootTypes = AppDomain.CurrentDomain
.GetAssemblies()
.SelectMany(a => a.GetTypes())
.Where(t => t.GetCustomAttribute<AggregateRootAttribute>() != null)
.ToList();
This can be useful in:
- Domain model validation
- Automatic registration
- Code generation / source generators
- Documentation tools
Domain Event Dispatching
Built-in support to create, add, and consume domain events from aggregates.
public class User : EntityBase
{
public string Email { get; private set; }
public User(int id, string email)
: base(id)
{
Email = email;
AddDomainEvent(new UserCreatedDomainEvent(id, email));
}
}
✅ When to Use
Use this package in your domain layer if you:
- Want a clean, reusable foundation for DDD modelling
- Need consistent equality and identity rules
- Prefer using attributes for marking aggregate roots
- Want built-in support for collecting and dispatching domain events
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net8.0 is compatible. 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 is compatible. 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. |
-
net8.0
- MediatR (>= 12.5.0)
- Microsoft.Extensions.Logging.Abstractions (>= 9.0.4)
-
net9.0
- MediatR (>= 12.5.0)
- Microsoft.Extensions.Logging.Abstractions (>= 9.0.4)
NuGet packages (2)
Showing the top 2 NuGet packages that depend on Ghanavats.Domain.Primitives:
Package | Downloads |
---|---|
Ghanavats.Domain.Factory
A lightweight .NET library that implements the Factory pattern in line with Domain-Driven Design (DDD) principles. Ghanavats.Domain.Factory enables the creation of complex entities and aggregates through a configurable, reflection-based factory mechanism. Supports customisation via options to ignore or inject properties. Designed to enforce consistency, encapsulate construction logic, and reduce boilerplate in your domain layer. |
|
Ghanavats.Domain.Factory.Abstractions
"Defines the abstraction for domain entity factories following DDD principles. Includes the IDomainFactory interface and configuration structures such as DomainFactoryOption. Ideal for applications that depend on abstractions, want to mock factories for testing, or create custom implementations without referencing the concrete Domain.Factory logic. |
GitHub repositories
This package is not used by any popular GitHub repositories.