DRN.Framework.SharedKernel 0.7.0-preview058

Prefix Reserved
This is a prerelease version of DRN.Framework.SharedKernel.
There is a newer prerelease version of this package available.
See the version list below for details.
dotnet add package DRN.Framework.SharedKernel --version 0.7.0-preview058
                    
NuGet\Install-Package DRN.Framework.SharedKernel -Version 0.7.0-preview058
                    
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="DRN.Framework.SharedKernel" Version="0.7.0-preview058" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="DRN.Framework.SharedKernel" Version="0.7.0-preview058" />
                    
Directory.Packages.props
<PackageReference Include="DRN.Framework.SharedKernel" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add DRN.Framework.SharedKernel --version 0.7.0-preview058
                    
#r "nuget: DRN.Framework.SharedKernel, 0.7.0-preview058"
                    
#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.
#:package DRN.Framework.SharedKernel@0.7.0-preview058
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=DRN.Framework.SharedKernel&version=0.7.0-preview058&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=DRN.Framework.SharedKernel&version=0.7.0-preview058&prerelease
                    
Install as a Cake Tool

master develop Quality Gate Status

Security Rating Maintainability Rating Reliability Rating Vulnerabilities Bugs Lines of Code Coverage

DRN.Framework.SharedKernel

Lightweight package containing domain primitives, exceptions, and shared code suitable for Contract and Domain layers.

Package Purpose

SharedKernel is the lightest DRN package with no external DRN dependencies. It can be safely referenced by:

  • Contract/API layers (DTOs, Exceptions)
  • Domain layers (Entities, Aggregates, Events)
  • Any project needing DRN primitives without heavy framework dependencies.

Table of Contents

When to Apply

  • Defining Domain Entities and Aggregates
  • Working with Domain Events
  • Using or extending DRN Exceptions
  • Understanding JSON Serialization conventions
  • Accessing Application Constants

Domain Primitives

Following definitions provide guidance and conventions for rapid and effective domain design. Their usage is optional but highly recommended for compatibility with DrnContext features.

Entity and AggregateRoot

  • SourceKnownEntity: The base class for all entities. Handles identity (long Id internal, Guid EntityId external), domain events, and auditing.
  • AggregateRoot: Marker class for DDD aggregate roots.
  • [EntityType(byte)]: Attribute defining a stable, unique byte identifier for each entity type. Required for ID generation and DrnContext startup validation.

Identity Rule: Always use Guid EntityId (mapped as Id in DTOs) for all public-facing contracts, API route parameters, and external lookups. The internal long Id must never be exposed outside the infrastructure/domain boundaries.

using DRN.Framework.SharedKernel.Domain;

[EntityType(1)] // Mandatory: Unique byte identifier for this entity type
public class User : AggregateRoot 
{
    public string Name { get; private set; }

    public User(string name) 
    {
        Name = name;
        AddDomainEvent(new UserCreated(this)); // Auto-published by DrnContext
    }
}

Domain Events

Entities encapsulate their events. DrnContext publishes them automatically upon saving changes.

public class UserCreated(User user) : EntityCreated(user)
{
    public string UserName => user.Name;
}

public interface IDomainEvent
{
    Guid Id { get; }
    DateTimeOffset Date { get; }
    Guid EntityId { get; }
}

public abstract class DomainEvent(SourceKnownEntity sourceKnownEntity) : IDomainEvent
{
    public Guid Id { get; protected init; } = Guid.NewGuid();
    public Guid EntityId => sourceKnownEntity.EntityId;
    public DateTimeOffset Date { get; protected init; } = DateTimeOffset.UtcNow;
}

public abstract class EntityCreated(SourceKnownEntity sourceKnownEntity) : DomainEvent(sourceKnownEntity);
public abstract class EntityModified(SourceKnownEntity sourceKnownEntity) : DomainEvent(sourceKnownEntity);
public abstract class EntityDeleted(SourceKnownEntity sourceKnownEntity) : DomainEvent(sourceKnownEntity);

SourceKnownEntityId & SourceKnownId

The framework uses a composite identifier system (SourceKnownEntityId) to balance database performance (long) with external security (Guid) and type safety.

// 1. entityId.Valid will be true only if the GUID structure is correct AND matches the User entity type.
var entityId = user.GetEntityId(someGuid, validate: true);

### ID Validation & Retrieval Strategies

The framework provides three distinct ways to validate and retrieve typed identifiers based on the operational context:

**1. Injectable Utility (Recommended for Service Layer)**
Ideal for cross-cutting business logic or when you have the `sourceKnownEntityIdUtils` in scope.
```csharp
var id = sourceKnownEntityIdUtils.Validate<User>(externalGuid);

2. Repository (Recommended for Data Access) Directly available on ISourceKnownRepository<TEntity>. Standardizes validation at the data entry point.

var id = userRepository.GetEntityId(externalGuid); 

3. Domain Entity (Recommended for Domain Logic) Uses helper methods on the SourceKnownEntity base class. Best for intra-domain operations.

var id = userInstance.GetEntityId<User>(externalGuid);

```csharp
namespace DRN.Framework.SharedKernel.Domain;

/// <summary>
/// Application wide Unique Entity Type
/// </summary>
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
public sealed class EntityTypeAttribute(byte entityType) : Attribute
{
    public byte EntityType { get; } = entityType;
}

public abstract class SourceKnownEntity(long id = 0) : IHasEntityId, IEquatable<SourceKnownEntity>, IComparable<SourceKnownEntity>
{
    public const int IdColumnOrder = 0;
    public const int ModifiedAtColumnOrder = 1;

    // ... Internal implementation omitted for brevity ...

    /// <summary>
    /// Internal use only, Use EntityId for external usage
    /// </summary>
    [JsonIgnore]
    [Column(Order = IdColumnOrder)]
    public long Id { get; internal set; } = id;

    /// <summary>
    /// External use only, don't use Id for external usage
    /// </summary>
    [JsonPropertyName(nameof(Id))]
    public Guid EntityId => EntityIdSource.EntityId;

    public DateTimeOffset CreatedAt => EntityIdSource.Source.CreatedAt;

    [ConcurrencyCheck]
    public DateTimeOffset ModifiedAt { get; protected internal set; }

    [JsonIgnore]
    public SourceKnownEntityId EntityIdSource { get; internal set; }
    
    // ... GetEntityId methods ...
}

public abstract class AggregateRoot(long id = 0) : SourceKnownEntity(id);

public abstract class AggregateRoot<TModel>(long id = 0) : AggregateRoot(id), IEntityWithModel<TModel> where TModel : class
{
    public TModel Model { get; set; } = null!;
}
public readonly record struct SourceKnownId(
    long Id,                // The internal database ID (64-bit integer)
    DateTimeOffset CreatedAt, // Timestamp when the ID was generated
    uint InstanceId,        // Generator instance ID (for distributed uniqueness)
    byte AppId,             // Application ID
    byte AppInstanceId      // Application Instance ID
);

public readonly record struct SourceKnownEntityId(
    SourceKnownId Source,   // The decoded internal components
    Guid EntityId,          // The external opaque GUID
    byte EntityType,        // The entity type identifier (from EntityTypeAttribute)
    bool Valid              // Whether the ID structure is valid
)
{
    // Validates that this ID belongs to the specified TEntity type
    public void Validate<TEntity>() where TEntity : SourceKnownEntity 
        => Validate(SourceKnownEntity.GetEntityType<TEntity>());
        
    // Validates ID structure and checks type match
    public void Validate(byte entityType);
}

SourceKnownRepository

ISourceKnownRepository<TEntity> defines a standard contract for repositories managing AggregateRoot entities.

  • Standardized Access: Provides common CRUD operations (CreateAsync, GetAsync, DeleteAsync).
  • Identity Conversion: Includes methods to convert between external Guids and internal SourceKnownEntityIds ensuring IDs are valid.
  • Cancellation Support: Built-in support for CancellationToken propagation and merging.
  • Streaming: Supports IAsyncEnumerable for processing large datasets efficiently.
public interface ISourceKnownRepository<TEntity> where TEntity : AggregateRoot
{
    RepositorySettings<TEntity> Settings { get; set; }
    CancellationToken CancellationToken { get; set; }
    
    // Identity Conversion & Validation
    SourceKnownEntityId GetEntityId(Guid id, bool validate = true);
    SourceKnownEntityId GetEntityId<TOtherEntity>(Guid id) where TOtherEntity : SourceKnownEntity;
    
    // Data Access
    Task<TEntity> GetAsync(Guid id);
    Task<TEntity?> GetOrDefaultAsync(SourceKnownEntityId id, bool validate = true);
    
    // Batch & Counts
    Task<bool> AnyAsync(Expression<Func<TEntity, bool>>? predicate = null);
    Task<long> CountAsync(Expression<Func<TEntity, bool>>? predicate = null);
    
    // Modification
    void Add(params IReadOnlyCollection<TEntity> entities);
    void Remove(params IReadOnlyCollection<TEntity> entities);
    Task<int> SaveChangesAsync();
    
    // Pagination & Streaming
    Task<PaginationResultModel<TEntity>> PaginateAsync(PaginationRequest request, EntityCreatedFilter? filter = null);
    IAsyncEnumerable<PaginationResultModel<TEntity>> PaginateAllAsync(PaginationRequest request, EntityCreatedFilter? filter = null);
    
    // Dangerous
    Task<TEntity[]> GetAllAsync();
}

GetAllAsync() returns all matching entities in a single query. This should be used only when the result set is guaranteed to be small or for specific maintenance tasks. Avoid in public-facing APIs.

Filtering

EntityCreatedFilter provides standardized date-based filtering, useful for time-series data or audit logs.

// Example: Get records created in the last 7 days
var filter = EntityCreatedFilter.After(DateTimeOffset.UtcNow.AddDays(-7));
var result = await repository.PaginateAsync(request, filter);

Pagination

The framework provides a robust cursor-based pagination system to balance performance and usability.

API Integration

PaginationRequest is natively URL-serializable. In Controllers, simply bind it from the query string.

[HttpGet]
public async Task<PaginationResultModel<UserDto>> GetAsync([FromQuery] PaginationRequest request)
{
    var result = await repository.PaginateAsync(request);
    return result.ToModel(user => user.ToDto());
}

Usage

// Example usage in a repository or service
var request = PaginationRequest.DefaultWith(size: 20, direction: PageSortDirection.Descending);
var result = await repository.PaginateAsync(request);

if (result.Info.HasNext) 
{
    // Use result.Info.RequestNextPage() for the next link
}

Exceptions

DrnException types map automatically to HTTP status codes via the ExceptionFor factory.

Factory Method Exception Type HTTP Status
ExceptionFor.Validation(msg) ValidationException 400
ExceptionFor.Unauthorized(msg) UnauthorizedException 401
ExceptionFor.Forbidden(msg) ForbiddenException 403
ExceptionFor.NotFound(msg) NotFoundException 404
ExceptionFor.Conflict(msg) ConflictException 409
ExceptionFor.Expired(msg) ExpiredException 410
ExceptionFor.UnprocessableEntity(msg) UnprocessableEntityException 422
ExceptionFor.Configuration(msg) ConfigurationException 500
ExceptionFor.MaliciousRequest(msg) MaliciousRequestException Abort
namespace DRN.Framework.SharedKernel;

/// <summary>
/// DrnExceptions are handled by scope handler and can be used to short circuit the processing pipeline
/// </summary>
public abstract class DrnException(string message, Exception? ex, string? category, short? status = null)
    : Exception(message, ex)
{
    public const string DefaultCategory = "default";
    public string Category { get; } = category ?? DefaultCategory;
    public short Status { get; } = status ?? 500;
}

public static class ExceptionFor
{
    private const string Default = DrnException.DefaultCategory;

    public static ValidationException Validation(string message, Exception exception = null!, string? category = Default)
        => new(message, exception, category);
        
    public static NotFoundException NotFound(string message, Exception exception = null!, string? category = Default)
        => new(message, exception, category);
        
    // ... other factory methods ...
}

JsonConventions

JsonConventions globally overrides System.Text.Json settings. These are automatically applied by DrnTestContext (in tests) and DrnHostBuilder (in hosted apps).

Applied Settings:

  • JsonSerializerDefaults.Web (CamelCase naming, case-insensitive)
  • JsonStringEnumConverter (Enums as strings)
  • AllowTrailingCommas = true
  • NumberHandling = AllowReadingFromString
namespace DRN.Framework.SharedKernel.Json;

public static class JsonConventions
{
    static JsonConventions()
    {
        UpdateDefaultJsonSerializerOptions();
    }

    public static readonly JsonSerializerOptions DefaultOptions = SetJsonDefaults();

    public static JsonSerializerOptions SetJsonDefaults(JsonSerializerOptions? options = null)
    {
        options ??= new JsonSerializerOptions(JsonSerializerDefaults.Web);

        options.Converters.Add(new JsonStringEnumConverter());
        options.Converters.Add(new Int64ToStringConverter());
        options.Converters.Add(new Int64NullableToStringConverter());
        options.AllowTrailingCommas = true;
        options.PropertyNameCaseInsensitive = true;
        options.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
        options.NumberHandling = JsonNumberHandling.AllowReadingFromString;
        options.MaxDepth = 32;
        // ...
        return options;
    }
}

Attributes

[IgnoreLog]

Excludes sensitive properties or entire classes from scoped logging.

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Property | AttributeTargets.Field)]
public class IgnoreLogAttribute : Attribute;

[SecureKey]

Validates that a string meets secure key requirements (length, character classes).


AppConstants

namespace DRN.Framework.SharedKernel;

public static class AppConstants
{
    public static int ProcessId { get; } = Environment.ProcessId;
    public static Guid AppInstanceId { get; } = Guid.NewGuid();
    public static string EntryAssemblyName { get; } = Assembly.GetEntryAssembly()?.GetName().Name ?? "Entry Assembly Not Found";
    public static string TempPath { get; } = GetTempPath(); //Cleans directory at every startup
    public static string LocalIpAddress { get; } = GetLocalIpAddress();
}

Semper Progressivus: Always Progressive

Commit Info

Author: Duran Serkan KILIÇ
Date: 2026-01-25 19:57:06 +0300
Hash: f166fafb824fc08532b5c8d4c1f34b8786eb2300

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net10.0

    • No dependencies.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on DRN.Framework.SharedKernel:

Package Downloads
DRN.Framework.Utils

DRN.Framework.Utils package contains common codes for other DRN.Framework packages, projects developed with DRN.Framework. ## Commit Info Author: Duran Serkan KILIÇ Date: 2026-02-11 22:40:07 +0300 Hash: 1be6f0a97b8f2e47322fbfcbf623140d706f706b

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.7.0-preview062 104 2/11/2026
0.7.0-preview061 139 2/7/2026
0.7.0-preview060 113 1/28/2026
0.7.0-preview059 117 1/26/2026
0.7.0-preview058 115 1/25/2026
0.7.0-preview057 117 1/25/2026
0.7.0-preview056 119 1/10/2026
0.7.0-preview055 290 12/16/2025
0.7.0-preview054 198 12/13/2025
0.7.0-preview053 143 12/12/2025
0.7.0-preview052 456 12/9/2025
0.7.0-preview051 324 12/7/2025
0.7.0-preview050 231 12/7/2025
0.7.0-preview049 207 11/26/2025
0.7.0-preview048 212 11/24/2025
0.7.0-preview047 182 11/7/2025
0.7.0-preview046 243 11/6/2025
0.7.0-preview045 245 11/3/2025
0.7.0-preview044 240 11/2/2025
0.6.0 253 11/10/2024
Loading failed

Not every version includes changes, features or bug fixes. This project can increment version to keep consistency with other DRN.Framework projects.

## Version 0.6.0

My family celebrates the enduring legacy of Mustafa Kemal Atatürk's enlightenment ideals. This release is dedicated to the memory of Mustafa Kemal Atatürk, founder of the Republic of Türkiye, and to his vision for a modern, enlightened, democratic nation. In his eternal rest, he continues to guide us through his ideals of freedom, progress, and national sovereignty.

## Version 0.5.0

My family celebrates the enduring legacy of Mustafa Kemal Atatürk's enlightenment ideals. This release is dedicated to August 30 Victory Day, a day that marks the decisive victory achieved by the Turkish people against imperialism during the Turkish War of Independence, leading to the establishment of the Republic of Türkiye.

### Breaking Changes

* DrnException implementations - refactored
 * Http status code parameter added
 * ExceptionFor factory class added to create DrnExceptions as needed

## Version 0.4.0~~~~

My family celebrates the enduring legacy of Mustafa Kemal Atatürk's enlightenment ideals. This release is dedicated to 19 May Commemoration of Atatürk, Youth and Sports Day.

## Version 0.3.0

My family celebrates the enduring legacy of Mustafa Kemal Atatürk's enlightenment ideals. This release is dedicated to 23 April National Sovereignty and Children's Day.

### Breaking Changes

* JsonSerializerOptions - moved to JsonConventions. System.Text.Json defaults will be overridden by JsonConventions when
 * DrnTestContext is used in tests
 * DrnHostBuilder is used to build host

### New Features

* Entity and AggregateRoot base classes' ModifiedAt property now has `ConcurrencyCheck` attribute and can be used for optimistic concurrency.

### Bug Fixes

* `AppConstants` LocalIpAddress calculation exception handling

## Version 0.2.0

### New Features

* JsonSerializerOptions - added to AppConstants which is same with default dotnet settings for now.
* AggregateRoot, Entity, DomainEvent

## Version 0.1.0

### New Features

* AppConstants
* DRN Framework exceptions
 * ValidationException
 * NotFoundException
 * NotSavedException
 * ExpiredException
 * ConfigurationException

---

**Semper Progressivus: Always Progressive**  
 
## Commit Info  
Author: Duran Serkan KILIÇ  
Date: 2026-01-25 19:57:06 +0300  
Hash: f166fafb824fc08532b5c8d4c1f34b8786eb2300