Hmz.Core.SharedKernel
0.1.8
See the version list below for details.
dotnet add package Hmz.Core.SharedKernel --version 0.1.8
NuGet\Install-Package Hmz.Core.SharedKernel -Version 0.1.8
<PackageReference Include="Hmz.Core.SharedKernel" Version="0.1.8" />
<PackageVersion Include="Hmz.Core.SharedKernel" Version="0.1.8" />
<PackageReference Include="Hmz.Core.SharedKernel" />
paket add Hmz.Core.SharedKernel --version 0.1.8
#r "nuget: Hmz.Core.SharedKernel, 0.1.8"
#:package Hmz.Core.SharedKernel@0.1.8
#addin nuget:?package=Hmz.Core.SharedKernel&version=0.1.8
#tool nuget:?package=Hmz.Core.SharedKernel&version=0.1.8
Hmz.Core.SharedKernel (SharedKernel)
The shared kernel library for the Hmz ecosystem providing core abstractions, utilities, and domain building blocks that serve as the foundation for all Hmz projects.
Overview
This project contains reusable patterns and utilities based on Domain-Driven Design (DDD) principles and Clean Architecture. It provides a consistent foundation for building domain-driven applications within the Hmz family of projects.
Features
π‘οΈ Guard Clauses & Validation
Leverage Ardalis.GuardClauses for concise and expressive input validation:
Guard.Against.Null(input);
Guard.Against.NullOrEmpty(text);
Guard.Against.OutOfRange(age, min: 0, max: 120);
π Result Pattern
Use the Hmz-owned structured Result contract for expected application failures:
using Hmz.Core.SharedKernel.Results;
public Result<User> CreateUser(string email)
{
var validationErrors = new List<Error>();
if (string.IsNullOrWhiteSpace(email))
{
validationErrors.Add(Error.Validation(
"user.email_required",
"Email is required.",
"email"));
}
return validationErrors.Count > 0
? Result.Failure<User>(validationErrors)
: Result.Success(new User(email));
}
Errors carry a stable code, a safe human-readable message, a transport-neutral
category, and an optional validation target. A successful generic result always contains a non-null value. A failed result may contain
multiple errors of the same category. Use Match, Map, and Bind to
compose successful operations without losing structured failures.
Error codes use the diagnostic format {app}.{type-prefix}.{app-error-code}.
Generate catalog values with ErrorCode.Create; because the method runs at
runtime, catalogs expose generated values as static readonly rather than
const:
public static readonly string ValidationFailed = ErrorCode.Create(
ErrorType.Validation,
"failed");
// COM.VAL.FAILED
The default application namespace is COM. Use the application-first
overload when a feature belongs to a specific application:
var code = ErrorCode.Create(
"Billing",
ErrorType.Conflict,
"invoice.duplicate");
// BILLING.CONF.INVOICE.DUPLICATE
The contract combines the practical strengths of:
- Milan JovanoviΔ's minimal Result and error catalogs
- Anton Martyniuk's typed and multiple-error guidance
- Ardalis.Result's composition and transport-separation conventions
Only expected failures use Result. Unexpected infrastructure and programming
failures remain exceptions and are handled by the application's exception
boundary. HTTP status codes, Problem Details mapping, and strong row-version
ETags are available under Hmz.Core.SharedKernel.Http. The helpers keep
transport conventions consistent across APIs while leaving domain errors
transport-neutral.
ETags use canonical quoted invariant decimal row versions such as "42".
Clients should treat the complete quoted value as opaque and send it back in
If-Match or If-None-Match unchanged.
Pagination
Use the same pagination response contract across modules and services:
using Hmz.Core.SharedKernel.Contracts.Pagination;
return new PagedResponse<OrderResponse>(items, page, pageSize, totalCount);
π Specification Pattern
Build complex queries in a domain-driven way with Ardalis.Specification and Entity Framework Core integration:
public class ActiveUserSpec : Specification<User>
{
public ActiveUserSpec()
{
Query.Where(u => u.IsActive);
}
}
var users = await repository.ListAsync(new ActiveUserSpec());
π·οΈ Smart Enums
Type-safe enumerations with Ardalis.SmartEnum:
public class UserStatus : SmartEnum<UserStatus>
{
public static readonly UserStatus Active = new("Active", 1);
public static readonly UserStatus Inactive = new("Inactive", 2);
private UserStatus(string name, int value) : base(name, value) { }
}
π§ Startup Services Management
Introspect and list registered services with Ardalis.ListStartupServices.
π ASP.NET Core Integration
ASP.NET Core Result-to-Problem-Details mapping is intentionally kept outside this transport-neutral package.
Project Setup
Configuration
- Target Framework: .NET 10
- C# Language Version: Latest (preview)
- Nullable Reference Types: Enabled
- Implicit Usings: Enabled
- Treat Warnings as Errors: Enabled
Package Information
- Package ID:
Hmz.Core.SharedKernel - Version:
0.1.8-pre30 - Target: Distributed as a NuGet package for use across Hmz projects
Usage
In a .NET Project
- Add package reference:
dotnet add package Hmz.Core.SharedKernel
- Use the utilities:
using Ardalis.GuardClauses;
using Hmz.Core.SharedKernel.Results;
public class OrderService
{
public Result<Order> CreateOrder(OrderRequest request)
{
Guard.Against.Null(request);
Guard.Against.NullOrEmpty(request.CustomerId);
var order = new Order(request.CustomerId);
return Result.Success(order);
}
}
Dependencies
All dependencies are managed through Directory.Packages.props at the solution level:
Ardalis.GuardClauses- Guard clauses and validationArdalis.ListStartupServices- Service introspectionArdalis.SharedKernel- Shared kernel abstractionsArdalis.SmartEnum- Smart enumerationsArdalis.Specification- Specification patternArdalis.Specification.EntityFrameworkCore- EF Core integration
Best Practices
When extending the SharedKernel:
Validation First: Always validate inputs using Guard clauses
Guard.Against.NullOrEmpty(name, nameof(name));Consistent Error Handling: Use Result pattern for operations that can fail
return Result.Failure( Error.NotFound("user.not_found", "User not found."));Domain-Driven Queries: Leverage Specification pattern for complex queries
var spec = new UsersByRoleSpec(role); var users = await repository.ListAsync(spec);Type-Safe Enums: Use SmartEnum for status and state enumerations
if (status == OrderStatus.Pending) { // Handle pending order }
Building and Testing
Build the Project
dotnet build
Run Tests
dotnet test tests/Hmz.Core.SharedKernel.UnitTests/Hmz.Core.SharedKernel.UnitTests.csproj
The SharedKernel unit tests use xUnit v3. Test projects are executable test hosts and are marked as non-packable and non-publishable.
Create NuGet Package
dotnet pack --configuration Release
Architecture
The SharedKernel follows these architectural principles:
- Domain-Driven Design (DDD): Core domain concepts are clearly expressed
- Clean Architecture: Separation of concerns with clear boundaries
- SOLID Principles: Adherence to design principles for maintainability
- Reusability: Components are designed to be used across multiple projects
Contributing
When adding new features to the SharedKernel:
- Ensure compatibility with .NET 10
- Follow the existing patterns and conventions
- Add proper guard clauses and validation
- Use the Result pattern for error handling
- Document public APIs thoroughly
- Update this README if adding major features
Support
For questions or issues regarding the SharedKernel, please refer to the main Hmz.Core documentation or contact the Hmz development team.
π Config-driven advanced search
Hmz.Core.SharedKernel.AdvancedSearch provides a reusable, allow-listed EF Core list-query pipeline. The client sends
structured global-search groups, field filters, strongly typed sort instructions, and pagination. Raw Dynamic LINQ
expressions and delimiter-based sort strings are never accepted from the client.
Register the stateless shared services once:
services.AddAdvancedSearch();
The preferred application flow is:
AdvancedSearchRequest
β
IAdvancedSearchService
ββ validates and normalizes against ISearchConfiguration
ββ resolves optional external values
ββ applies Dynamic LINQ only to allow-listed members
ββ counts, pages, and optionally projects
β
PagedResponse<TResult>
A feature supplies only its ISearchConfiguration, source query, result projection, and optional external resolvers:
public sealed class ProductSearchQuery(
AppDbContext dbContext,
IAdvancedSearchService advancedSearch)
: IAdvancedSearchQuery<ProductListItem>
{
public ValueTask<PagedResponse<ProductListItem>> ExecuteAsync(
AdvancedSearchRequest request,
CancellationToken cancellationToken = default) =>
advancedSearch.ExecutePageAsync(
dbContext.Products.AsNoTracking(),
product => new ProductListItem(product.Id, product.Name, product.Price),
request,
ProductSearchConfiguration.Instance,
cancellationToken: cancellationToken);
}
IAdvancedSearchQuery<TResult> is the generic adapter contract; features do not need one interface per entity. The
projection overload applies Where, OrderBy, Count, Skip, and Take to the source entity/query shape before
constructing the DTO. Configure SearchFieldDefinition.MatchKey when the client-visible field name differs from the
source member used by EF Core.
Important semantics:
- fields inside one
GlobalSearchItemare OR-ed; - separate global-search items use
SearchLogic; - filters default to AND, while multiple positive values inside one filter are OR-ed;
- negative multi-value operators are AND-ed;
- external no-match results remain match-nothing rather than becoming an unconstrained query;
- default ordering should end with a unique field for deterministic pagination;
AdvancedSearchValidationException.Errorsuses exact paths such assearch[0].searchFields[1],filter.filters[0].searchValues[0], andorderBy[0].direction.- search operators accept compact codes such as
CT/EQand readable aliases such ascontains/equals, case-insensitively; - boolean values are invariant strings
trueorfalse; invalid scalar values include accepted formats in their validation message; - call
AddHmzProblemDetails()andUseExceptionHandler()in the host so JSON body-binding failures are returned as sanitized HTTP 400 validation problem details instead of HTTP 500.
The source intentionally uses normal arrays (new[] { value } / Array.Empty<T>()) at public collection boundaries.
This avoids compiler-generated single-element collection helper types appearing in decompiled package APIs.
See the template repository's docs/ADVANCED_SEARCH_GUIDE.md for the full request contract and endpoint example.
| Product | Versions 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. |
-
net10.0
- Ardalis.GuardClauses (>= 5.0.0)
- Ardalis.ListStartupServices (>= 1.1.4)
- Ardalis.SharedKernel (>= 5.0.0)
- Ardalis.SmartEnum (>= 8.2.0)
- Ardalis.Specification (>= 9.3.1)
- Ardalis.Specification.EntityFrameworkCore (>= 9.3.1)
- Mediator.Abstractions (>= 3.0.2)
- Microsoft.AspNetCore.OpenApi (>= 10.0.11)
- Microsoft.EntityFrameworkCore (>= 10.0.11)
- Microsoft.OpenApi (>= 2.12.2)
- System.Linq.Dynamic.Core (>= 1.7.4)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Hmz.Core.SharedKernel:
| Package | Downloads |
|---|---|
|
Hmz.Core.CrudKit
CRUD toolkit for Hmz projects, built on Hmz.Core.SharedKernel |
GitHub repositories
This package is not used by any popular GitHub repositories.