GaEpd.AppLibrary 5.2.1

Prefix Reserved
There is a newer version of this package available.
See the version list below for details.
dotnet add package GaEpd.AppLibrary --version 5.2.1                
NuGet\Install-Package GaEpd.AppLibrary -Version 5.2.1                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="GaEpd.AppLibrary" Version="5.2.1" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add GaEpd.AppLibrary --version 5.2.1                
#r "nuget: GaEpd.AppLibrary, 5.2.1"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install GaEpd.AppLibrary as a Cake Addin
#addin nuget:?package=GaEpd.AppLibrary&version=5.2.1

// Install GaEpd.AppLibrary as a Cake Tool
#tool nuget:?package=GaEpd.AppLibrary&version=5.2.1                

Georgia EPD-IT App Library

This repo contains a library created by Georgia EPD-IT to provide common classes and tools for our web applications.

Georgia EPD-IT .NET Test CodeQL SonarCloud Quality Gate Status Lines of Code

(Much of this work was inspired by the ABP Framework.)

How to install

Nuget

To install , search for "GaEpd.AppLibrary" in the NuGet package manager or run the following command:

dotnet add package GaEpd.AppLibrary

What's included

Domain entities

The following interfaces and abstract implementations of domain entities are provided for domain driven design:

  • The basic IEntity<TKey> interface defines an entity with a primary key of the given type.
  • The special case IEntity interface defines an entity with a GUID primary key.
  • IAuditableEntity<TUserKey> adds created/updated properties and methods for basic data auditing.
  • ISoftDelete and ISoftDelete<TUserKey> add properties for "soft deleting" an entity rather than actually
  • deleting it.
  • INamedEntity adds a "Name" string property.
  • IActiveEntity adds an "Active" boolean property.

There are also abstract classes based on the above interfaces from which you should derive your domain entities: Entity<TKey>, AuditableEntity<TKey, TUserKey>, SoftDeleteEntity<TKey, TUserKey>, AuditableSoftDeleteEntity<TKey, TUserKey>, and StandardNamedEntity.

The StandardNamedEntity class derives from AuditableEntity<Guid>, INamedEntity, and IActiveEntity, and includes methods for enforcing the length of the Name. Maximum and minimum name length can be set in the constructor.

Example usage:

public class DerivedNamedEntity : StandardNamedEntity
{
    public override int MinNameLength => 2;
    public override int MaxNameLength => 50;

    public DerivedNamedEntity() { }
    public DerivedNamedEntity(Guid id, string name) : base(id, name) { }
}

ValueObject

An abstract ValueObject record can help add value objects to your domain entities. A value object is a compound of properties, such as an address or date range, that are comparable based solely on their values rather than their references. The properties of a value object are typically stored with its parent class, not as a separate record with its own ID. Value objects should be treated as immutable. When deriving from ValueObject, you must provide a GetEqualityComponents() method to define which properties to use to determine equality.

Example usage:

[Owned]
public record Address : ValueObject
{
    public string Street { get; init; } = string.Empty;
    public string? Street2 { get; init; }
    public string City { get; init; } = string.Empty;
    public string State { get; init; } = string.Empty;

    [DataType(DataType.PostalCode)]
    public string PostalCode { get; init; } = string.Empty;

    protected override IEnumerable<object> GetEqualityComponents()
    {
        yield return Street;
        yield return Street2 ?? string.Empty;
        yield return City;
        yield return State;
        yield return PostalCode;
    }
}

Note: The [Owned] attribute is an Entity Framework attribute defining this as a value object owned by the parent class. See Owned Entity Types for more info on how this is implemented in EF Core.

Data Repositories

Common data repository interfaces define basic entity CRUD operations. The IReadRepository interface defines get and search operations (including paginated search). The IWriteRepository interface defines insert, update, and delete operations. IRepository combines the read and write interfaces. Finally, the INamedEntityRepository adds a find-by-name method.

(Note that these interfaces work directly with domain entities. Your application should define application/domain services that define how the application interacts with the entities & repositories through data transfer objects (DTOs).)

There are two abstract BaseRepository classes that each implement the IRepository interface, one using in-memory data and the other requiring an Entity Framework database context.

There are similarly two abstract NamedEntityRepository classes that each implement the INamedEntityRepository interface.

Example usage:

public interface IDerivedRepository : INamedEntityRepository<DerivedNamedEntity> { }

public sealed class DerivedRepository : NamedEntityRepository<DerivedNamedEntity, AppDbContext>, IDerivedRepository
{
    public DerivedRepository(AppDbContext context) : base(context) { }
}

Predicate builder

Code from C# in a Nutshell is included to enable creating filter expressions that can be combined. The library comes with the commonly used filters WithId(id) for all entities and ExcludedDeleted() for "soft delete" entities.

Example usage:

public static Expression<Func<MyEntity, bool>> IsActive(this Expression<Func<MyEntity, bool>> predicate) =>
    predicate.And(e => e.IsActive);

public static Expression<Func<MyEntity, bool>> ActiveAndNotDeletedPredicate() =>
    PredicateBuilder.True<MyEntity>().IsActive().ExcludeDeleted();

Pagination classes

IPaginatedRequest and IPaginatedResult<T> define how to request and receive paginated (and sorted) search results.

The System.Linq.Dynamic.Core package is included.

List Item record

A ListItem<TKey> record type defines a key-value pair with fields for ID of type TKey and string Name. The ToSelectList() extension method takes a ListItem enumerable and returns an MVC SelectList which can be used to create an HTML <select> element.

Enum extensions

GetDisplayName() and GetDescription() return the DisplayAttribute.Name and DescriptionAttribute values of an enum, respectively.

Guard clauses

The GuardClauses package is included by reference.

What's not included

The File Service and GuardClauses packages have been moved to separate repositories.

Product 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
5.3.1 451 9/11/2024
5.3.0 607 9/10/2024
5.2.1 1,142 4/30/2024
5.2.0 127 4/29/2024
5.1.0 1,032 1/3/2024
5.0.1 123 1/2/2024
5.0.0 137 1/2/2024
4.1.0 586 11/9/2023
4.0.0 213 10/25/2023
3.5.1 358 9/20/2023
3.5.0 166 9/19/2023
3.4.0 135 9/18/2023
3.3.0 345 8/11/2023
3.2.0 605 5/22/2023
3.1.0 420 4/25/2023
3.0.0 733 3/27/2023
2.0.0 295 3/7/2023
1.1.0 676 12/22/2022
1.0.1 432 10/14/2022
1.0.0 860 10/6/2022
0.4.0-beta 222 9/29/2022
0.3.0-beta 205 9/23/2022

# Changelog
## [5.2.1] - 2024-04-30
- Added a `GetOrderedListAsync` overload method with predicate matching.
## [5.2.0] - 2024-04-30
- Added a string `Truncate` function.
- Added a `GetOrderedListAsync` method to the Named Entity Repository.
## [5.1.0] - 2024-01-03
- Updated the included GuardClauses library to v2.0.0.
## [5.0.1] - 2024-01-02
- Updated changelog for v5.0.0 release.
## [5.0.0] - 2024-01-02
- Upgraded to .NET 8.0.
### Added
- Added entity and repository interfaces that default to using a GUID primary key and updated the abstract classes to use these new interfaces.
### Changed
- **Breaking changes:**
- Uses of `EntityNotFoundException` will need to be updated to provide the class type. For example, `EntityNotFoundException(typeof(MyEntity), id)` should be replaced with `EntityNotFoundException<MyEntity>(id)`.
- References to `IEntity<Guid>` may need to be replaced with `IEntity`.
## [4.1.0] - 2023-11-09
- Implement IAsyncDisposable in repositories.
## [4.0.0] - 2023-10-25
- Move GuardClauses to a separate NuGet package.
## [3.5.1] - 2023-09-20
- Derived EF repositories can now specify the DbContext type.
## [3.5.0] - 2023-09-19
- Added an abstract StandardNameEntity along with INamedEntity and IActiveEntity interfaces.
- Added INamedEntityRepository and INamedEntityManager interfaces and implementations.
## [3.4.0] - 2023-09-18
- Included abstract implementations of BaseRepository.
## [3.3.0] - 2023-08-11
- Added a "ConcatWithSeparator" string extension.
- Added "PreviousPageNumber" and "NextPageNumber" properties to the IPaginatedResult interface.
- Made some possible performance improvements to the Enum extensions.
Breaking change: The Enum extensions no longer work with nullable Enum values.
## [3.2.0] - 2023-05-22
- Added a "SetNotDeleted" (undelete) method to the ISoftDelete interface.
## [3.1.0] - 2023-04-25
- Added a "SaveChanges" method to the write repository.
## [3.0.0] - 2023-04-25
- Upgraded the library to .NET 7.
## [2.0.0] - 2023-03-07
- Moved the write repository operations to a separate interface.
- Added "Exists" methods to the read repository interface.
- Renamed the user ID properties on auditable entities.
## [1.1.0] - 2023-03-07
- Added predicate builder and common entity filters.
- Added enum extensions.
- Added the System.Linq.Dynamic.Core package.
## [1.0.1] - 2022-10-14
- Added a Readme file to the package.
## [1.0.0] - 2022-10-06
_Initial release._
[5.2.1]: https://github.com/gaepdit/app-library/releases/tag/v5.2.1
[5.2.0]: https://github.com/gaepdit/app-library/releases/tag/v5.2.0
[5.1.0]: https://github.com/gaepdit/app-library/releases/tag/l%2Fv5.1.0
[5.0.1]: https://github.com/gaepdit/app-library/releases/tag/al%2Fv5.0.1
[5.0.0]: https://github.com/gaepdit/app-library/releases/tag/al%2Fv5.0.0
[4.1.0]: https://github.com/gaepdit/app-library/releases/tag/al%2Fv4.1.0
[4.0.0]: https://github.com/gaepdit/app-library/releases/tag/al%2Fv4.0.0
[3.5.1]: https://github.com/gaepdit/app-library/releases/tag/v3.5.1
[3.5.0]: https://github.com/gaepdit/app-library/releases/tag/v3.5.0
[3.4.0]: https://github.com/gaepdit/app-library/releases/tag/v3.4.0
[3.3.0]: https://github.com/gaepdit/app-library/releases/tag/v3.3.0
[3.2.0]: https://github.com/gaepdit/app-library/releases/tag/v3.2.0
[3.1.0]: https://github.com/gaepdit/app-library/releases/tag/v3.1.0
[3.0.0]: https://github.com/gaepdit/app-library/releases/tag/v3.0.0
[2.0.0]: https://github.com/gaepdit/app-library/releases/tag/v2.0.0
[1.1.0]: https://github.com/gaepdit/app-library/releases/tag/v1.1.0
[1.0.1]: https://github.com/gaepdit/app-library/releases/tag/v1.0.1
[1.0.0]: https://github.com/gaepdit/app-library/releases/tag/v1.0.0