Open-source project
NetDevPack/NetDevPack avatar
NetDevPack/NetDevPack

NetDevPack: base classes for DDD and CQRS in .NET

A smart set of common classes and implementations to improve your development productivity.

822 stars102 forksC#MIT

At a glance

What is it?
NetDevPack is an MIT licensed NuGet package from Eduardo Pires that provides the base types a .NET application needs for domain driven design, CQRS through a mediator, validation with FluentValidation and domain events, with contracts for entities, repositories, unit of work and handlers. It suits a team that wants the shapes in place without writing them, and it is a poor fit if your application deliberately avoids the repository and mediator patterns.
Who is it for?
NetDevPack suits a .NET team that has decided on domain driven design with CQRS and wants the entity, repository, unit of work, handler and notification shapes already written and consistent, since the package is exactly that set of contracts and nothing more.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Activity is slowing. The repository last received commits 6 months ago.
What is it written in?
Mainly C#, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 25, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A set of base types rather than a framework

NetDevPack is described as a comprehensive set of reusable classes and interfaces designed to improve development experience and productivity in .NET applications, and it encapsulates best practices and common patterns such as Domain-Driven Design, CQRS, Validation, Notification and Mediator.

That is a narrower proposition than a framework, and the feature list makes the boundary concrete. It provides domain-driven design base classes and interfaces, CQRS support via the mediator pattern, FluentValidation integration, domain events and notifications handling, and unit of work and repository base contracts.

The audience is a .NET developer who has drawn these patterns on a whiteboard and would rather not redraw them for the tenth application. The value is in the shape of the contracts rather than in any clever implementation, since an entity base class and a repository interface are not difficult to write. What is difficult, and what this package supplies, is making those decisions the same way in every bounded context, and having the mediator, the validation and the event publishing line up with them.

The author is Eduardo Pires, who developed .NET DevPack under the MIT licence, and the NuGet package is published as NetDevPack. The repository has a solution file, NetDevPack.sln, with src and tests directories, a changelog, and a semantic release configuration in .releaserc.

The recent releases are v7.0.0 on 2026-02-05, v6.1.1 on 2025-04-08 and v6.1.0 on 2023-01-02, and the last push to the repository was on 2026-04-02.

The entity and repository contracts are deliberately small

The domain entity example shows the shape of the base class, and it is worth reading closely because the design decision is in what is protected.

csharp
using NetDevPack.Domain;

public class Customer : Entity
{
    public string Name { get; private set; }

    public Customer(Guid id, string name)
    {
        Id = id;
        Name = name;
    }
}

The entity takes its identity in the constructor and exposes its state through private setters, so a domain object cannot be mutated from outside after creation. The Id is inherited from Entity rather than redeclared, which is the point of the base class: every aggregate in the application gets the same identity handling without repeating it.

The repository contract extends a generic interface.

csharp
using NetDevPack.Data;

public interface ICustomerRepository : IRepository<Customer>
{
    Task<Customer> GetByName(string name);
}

So IRepository<Customer> is the generic contract, presumably carrying the common operations, and the application specific interface adds only what is genuinely domain specific, here a lookup by name. The Task return type is the tell that this is aimed at asynchronous data access.

Together with the unit of work contract listed in the features, this is a persistence abstraction in the classic style: repositories do not commit, the unit of work does. The value for a team is that the boundaries are already drawn, and the cost is that they are drawn for you.

The mediator is where commands become events

The mediator example is the one that shows the CQRS side of the package, and it is a short class.

csharp
public class CustomerCommandHandler : IRequestHandler<RegisterCustomerCommand, ValidationResult>
{
    private readonly IMediatorHandler _mediator;
    
    public CustomerCommandHandler(IMediatorHandler mediator)
    {
        _mediator = mediator;
    }

    public async Task<ValidationResult> Handle(RegisterCustomerCommand request, CancellationToken cancellationToken)
    {
        // Business logic
        await _mediator.PublishEvent(new CustomerRegisteredEvent(...));
        return new ValidationResult();
    }
}

Three things are visible in that shape. The handler implements IRequestHandler for a specific command type and returns a ValidationResult, so validation is part of the command's contract rather than an afterthought in the controller. The mediator is injected as IMediatorHandler, which means the handler does not know which implementation dispatches, and it can be replaced in a test. And the handler publishes a domain event, CustomerRegisteredEvent, through the same mediator, so the command handler does not know who reacts to the event.

That last point is the one that makes the mediator pattern worth the indirection. The alternative, a handler calling every interested service directly, is fewer lines and a hard dependency from one bounded context to another.

The notification handling listed in the features is the same idea applied to user facing messages rather than domain state changes, and the CancellationToken parameter is threaded through the handler signature, which means the dispatch implementation is expected to be cancellable.

FluentValidation is the validation seam

Validation is integrated rather than reimplemented, and the example shows the integration point.

csharp
using FluentValidation;

public class CustomerValidator : AbstractValidator<Customer>
{
    public CustomerValidator()
    {
        RuleFor(c => c.Name).NotEmpty();
    }
}

The validator inherits from AbstractValidator for the Customer type, so the rules are declared in the familiar FluentValidation style, and the rules are attached to the domain type rather than to a request DTO. That is the meaningful design choice: the constraint lives with the entity it constrains, and the same validator can be invoked from a command handler, from a background job or from a test.

The features list names FluentValidation integration, and the handler returns a ValidationResult, so the wiring is that a validator produces the result that the command handler passes back. You do not have to roll your own validation result type or your own rule engine.

The dependencies here are worth noting as a design constraint. FluentValidation is a third party library that this package integrates with, so adopting NetDevPack means taking a dependency on FluentValidation's model, and a team that has already standardised on DataAnnotations or on a different validation approach will find the seam in the wrong place.

One package, and a target framework list to check

Installation is a single command, because the whole library ships as one NuGet package.

bash
dotnet add package NetDevPack

The compatibility section is where you should look before anything else. The package supports .NET Standard 2.1 and .NET 5 through 9, including the latest versions, with legacy support for .NET Core 3.1 and older marked as having limitations.

That list spans a wide range of consumer applications, and the .NET Standard 2.1 entry is what lets the package be consumed from projects that are not on modern .NET at all, including things like .NET Framework based services. The .NET Core 3.1 and older caveat is the one to note, because a limitation in a base class contract is the kind of thing that shows up as a compile error in a project that has no other reason to fail.

There is also a full implementation example linked from the README, the Equinox Project, which is the fastest way to see how the pieces fit together in something larger than a class or two. The repository root has a tests directory alongside src, so the package is tested rather than merely documented, and the .github directory holds the workflows behind the release badges.

The root package.json is release tooling, not the package

A detail in the repository root can mislead anyone who expects every project to be one thing.

The root package.json is named netdevpack at version 1.0.0, and its description field is an HTML image tag pointing at the project banner. Its test script is a placeholder that echoes an error and exits with status 1, its licence field says ISC, and its only dependencies are the semantic-release family, including semantic-release, @semantic-release/changelog, @semantic-release/git and @semantic-release/github.

So the Node package at the root of this repository is not the .NET package. It is the release automation. The semantic-release tooling reads the changelog and the commit history, and the .releaserc file configures how the version and the release are produced, and the root package-lock.json exists to pin that tooling.

That is an ordinary arrangement for a .NET library that publishes to NuGet, and it is worth knowing because the version numbers do not line up. The root package.json says 1.0.0 while the NuGet package is at 7.0.0, and the licence fields disagree, ISC in the Node manifest and MIT in the LICENSE file and the README. The MIT licence stated in the README and in the LICENSE file is the one that applies to the .NET code.

For anyone automating releases, the practical note is that the version comes from semantic-release and the changelog from CHANGELOG.md, so the two are kept in step by the tooling rather than by hand.

A quiet patch cycle and a recent major version

The release history is short and the gaps between it are wide.

Version 6.1.0 came in January 2023, 6.1.1 in April 2025, and 7.0.0 in February 2026, and the last push to the repository was on 2026-04-02. So the project had a long patch-only period, then a major version, then a couple of months of quieter work.

A major version here means a breaking change, and for a package that defines base contracts that your own classes inherit, that is the part to pay attention to. If you were on 6.x and you take 7.0.0, your entities, handlers and validators are the things that need review, because they are the things that implement the contracts.

The compatibility promise is also the main thing to evaluate. Supporting .NET Standard 2.1 and .NET 5 through 9 is a broad range, but the older entries come with the warning about limitations, and a package that spans that many target frameworks has to be conservative in what it uses.

The one external reference worth following for a sense of the library in real use is the Equinox Project, which the README points to as a full implementation example, and the repository's own tests directory. A base class package is only as good as the shape of the contracts it hands you, and reading those two is more informative than any description of the feature list.

Editorial conclusion

NetDevPack suits a .NET team that has decided on domain driven design with CQRS and wants the entity, repository, unit of work, handler and notification shapes already written and consistent, since the package is exactly that set of contracts and nothing more. It does not suit a project that has chosen a different persistence or messaging style, and it does not suit a team that wants a full framework with hosting, configuration and extension methods rather than a set of interfaces. Before you adopt it, read the Entity and IRepository contracts in the source to see how much of your own model they will fit, check that the target framework you are on is covered, since the compatibility list runs from .NET Standard 2.1 through .NET 9 with .NET Core 3.1 and older supported only with limitations, and note that the last push to the repository was on 2026-04-02 with v7.0.0 published on 2026-02-05, so the project is quiet but not finished.

Frequently asked questions

What is NetDevPack?

NetDevPack is an MIT licensed .NET library from Eduardo Pires that packages domain-driven design base classes and interfaces, CQRS support through the mediator pattern, FluentValidation integration, domain event and notification handling, and unit of work and repository base contracts into a single NuGet package named NetDevPack.

How do I install NetDevPack?

Run dotnet add package NetDevPack. The package supports .NET Standard 2.1 and .NET 5 through 9, with legacy support for .NET Core 3.1 and older carrying limitations.

How does the mediator work in NetDevPack?

A command handler implements IRequestHandler for a command type, receives an injected IMediatorHandler, and publishes a domain event through it, so the handler does not need to know which services react to the event. The handler returns a ValidationResult as part of the command contract.

Does NetDevPack use FluentValidation?

Yes. Validation is integrated with FluentValidation, with a validator such as CustomerValidator inheriting from AbstractValidator for the domain type and returning a ValidationResult that the command handler passes back.

What is the package.json in the NetDevPack repository root?

It is the release automation rather than the .NET package. It depends on the semantic-release family and the .releaserc file configures how the version and release are produced, which is why its version number and licence field do not match the NuGet package.

Official sources

  1. Issues
  2. License: MIT
  3. NetDevPack/NetDevPack on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/netdevpack-netdevpack.svg)](https://hysenlabs.com/projects/netdevpack-netdevpack)

Was this useful?