Comprehensive API reference for all DKNet Framework components.
namespace DKNet.Fw.Extensions;
public static class TypeExtensions
{
/// <summary>
/// Checks if a type implements the specified interface.
/// </summary>
/// <typeparam name="TInterface">The interface type to check for.</typeparam>
/// <param name="type">The type to check.</param>
/// <returns>true if the type implements the interface; otherwise, false.</returns>
public static bool ImplementsInterface<TInterface>(this Type type);
/// <summary>
/// Checks if a type implements the specified interface.
/// </summary>
/// <param name="type">The type to check.</param>
/// <param name="interfaceType">The interface type to check for.</param>
/// <returns>true if the type implements the interface; otherwise, false.</returns>
public static bool ImplementsInterface(this Type type, Type interfaceType);
/// <summary>
/// Gets all interfaces implemented by the type.
/// </summary>
/// <param name="type">The type to examine.</param>
/// <returns>An array of interface types.</returns>
public static Type[] GetImplementedInterfaces(this Type type);
}
public static class PropertyExtensions
{
/// <summary>
/// Gets the value of a property by name.
/// </summary>
/// <param name="obj">The object instance.</param>
/// <param name="propertyName">The property name.</param>
/// <returns>The property value or null if not found.</returns>
public static object? GetPropertyValue(this object? obj, string propertyName);
/// <summary>
/// Gets the value of a property by name with type conversion.
/// </summary>
/// <typeparam name="T">The expected return type.</typeparam>
/// <param name="obj">The object instance.</param>
/// <param name="propertyName">The property name.</param>
/// <returns>The property value converted to T or default(T) if not found.</returns>
public static T? GetPropertyValue<T>(this object? obj, string propertyName);
/// <summary>
/// Sets the value of a property by name.
/// </summary>
/// <param name="obj">The object instance.</param>
/// <param name="propertyName">The property name.</param>
/// <param name="value">The value to set.</param>
/// <returns>true if the property was set successfully; otherwise, false.</returns>
public static bool SetPropertyValue(this object obj, string propertyName, object? value);
}
public static class EnumExtensions
{
/// <summary>
/// Gets the description attribute value of an enum member.
/// </summary>
/// <param name="enumValue">The enum value.</param>
/// <returns>The description or the enum name if no description is found.</returns>
public static string GetDescription(this Enum enumValue);
/// <summary>
/// Gets all description attribute values for an enum type.
/// </summary>
/// <typeparam name="T">The enum type.</typeparam>
/// <returns>A dictionary mapping enum values to their descriptions.</returns>
public static Dictionary<T, string> GetAllDescriptions<T>() where T : Enum;
/// <summary>
/// Converts a string to an enum value.
/// </summary>
/// <typeparam name="T">The enum type.</typeparam>
/// <param name="value">The string value.</param>
/// <param name="ignoreCase">Whether to ignore case when parsing.</param>
/// <returns>The enum value if parsing succeeds; otherwise, the default value.</returns>
public static T ToEnum<T>(this string value, bool ignoreCase = true) where T : struct, Enum;
}
public static class AsyncEnumerableExtensions
{
/// <summary>
/// Converts an IAsyncEnumerable to a List asynchronously.
/// </summary>
/// <typeparam name="T">The element type.</typeparam>
/// <param name="source">The async enumerable source.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>A list containing all elements from the async enumerable.</returns>
public static async Task<List<T>> ToListAsync<T>(
this IAsyncEnumerable<T> source,
CancellationToken cancellationToken = default);
/// <summary>
/// Filters elements of an async enumerable based on a predicate.
/// </summary>
/// <typeparam name="T">The element type.</typeparam>
/// <param name="source">The async enumerable source.</param>
/// <param name="predicate">The predicate function.</param>
/// <returns>A filtered async enumerable.</returns>
public static IAsyncEnumerable<T> WhereAsync<T>(
this IAsyncEnumerable<T> source,
Func<T, bool> predicate);
/// <summary>
/// Projects each element of an async enumerable to a new form.
/// </summary>
/// <typeparam name="TSource">The source element type.</typeparam>
/// <typeparam name="TResult">The result element type.</typeparam>
/// <param name="source">The async enumerable source.</param>
/// <param name="selector">The selector function.</param>
/// <returns>A projected async enumerable.</returns>
public static IAsyncEnumerable<TResult> SelectAsync<TSource, TResult>(
this IAsyncEnumerable<TSource> source,
Func<TSource, TResult> selector);
}
namespace DKNet.EfCore.Abstractions;
/// <summary>
/// Base class for all entities with auditing support.
/// </summary>
public abstract class AggregateRoot : IAuditable, IDomainEvents
{
protected AggregateRoot(Guid id, string createdBy)
{
Id = id == Guid.Empty ? Guid.NewGuid() : id;
CreatedBy = createdBy;
CreatedAt = DateTime.UtcNow;
}
public Guid Id { get; protected set; }
public string CreatedBy { get; protected set; }
public DateTime CreatedAt { get; protected set; }
public string? UpdatedBy { get; protected set; }
public DateTime? UpdatedAt { get; protected set; }
/// <summary>
/// Sets the user who updated the entity.
/// </summary>
/// <param name="updatedBy">The user identifier.</param>
protected void SetUpdatedBy(string updatedBy)
{
UpdatedBy = updatedBy;
UpdatedAt = DateTime.UtcNow;
}
private readonly List<DomainEvent> _domainEvents = new();
/// <summary>
/// Adds a domain event to be raised when the entity is saved.
/// </summary>
/// <param name="domainEvent">The domain event.</param>
public void AddEvent(DomainEvent domainEvent) => _domainEvents.Add(domainEvent);
/// <summary>
/// Gets all uncommitted domain events.
/// </summary>
/// <returns>A read-only collection of domain events.</returns>
public IReadOnlyCollection<DomainEvent> GetUncommittedEvents() => _domainEvents.AsReadOnly();
/// <summary>
/// Clears all uncommitted domain events.
/// </summary>
public void ClearEvents() => _domainEvents.Clear();
}
/// <summary>
/// Interface for tenant-aware entities.
/// </summary>
public interface ITenantEntity
{
string TenantId { get; set; }
}
/// <summary>
/// Interface for auditable entities.
/// </summary>
public interface IAuditable
{
string CreatedBy { get; }
DateTime CreatedAt { get; }
string? UpdatedBy { get; }
DateTime? UpdatedAt { get; }
}
/// <summary>
/// Base class for all domain events.
/// </summary>
public abstract record DomainEvent
{
public Guid Id { get; } = Guid.NewGuid();
public DateTime OccurredAt { get; } = DateTime.UtcNow;
}
/// <summary>
/// Interface for domain event handlers.
/// </summary>
/// <typeparam name="TEvent">The domain event type.</typeparam>
public interface IDomainEventHandler<in TEvent> where TEvent : DomainEvent
{
Task Handle(TEvent domainEvent, CancellationToken cancellationToken = default);
}
namespace DKNet.EfCore.Repos.Abstractions;
/// <summary>
/// Generic repository interface for entities.
/// </summary>
/// <typeparam name="TEntity">The entity type.</typeparam>
public interface IRepository<TEntity> where TEntity : class
{
/// <summary>
/// Gets a queryable for the entity.
/// </summary>
/// <returns>An IQueryable for the entity type.</returns>
IQueryable<TEntity> Gets();
/// <summary>
/// Finds an entity by its identifier.
/// </summary>
/// <param name="id">The entity identifier.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>The entity if found; otherwise, null.</returns>
Task<TEntity?> FindAsync(Guid id, CancellationToken cancellationToken = default);
/// <summary>
/// Adds a new entity.
/// </summary>
/// <param name="entity">The entity to add.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>The added entity.</returns>
Task<TEntity> AddAsync(TEntity entity, CancellationToken cancellationToken = default);
/// <summary>
/// Updates an existing entity.
/// </summary>
/// <param name="entity">The entity to update.</param>
void Update(TEntity entity);
/// <summary>
/// Deletes an entity.
/// </summary>
/// <param name="entity">The entity to delete.</param>
void Delete(TEntity entity);
/// <summary>
/// Finds entities matching a specification.
/// </summary>
/// <param name="specification">The specification to apply.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>A collection of matching entities.</returns>
Task<IEnumerable<TEntity>> FindAsync(
Specification<TEntity> specification,
CancellationToken cancellationToken = default);
}
/// <summary>
/// Read-only repository interface for queries.
/// </summary>
/// <typeparam name="TEntity">The entity type.</typeparam>
public interface IReadRepository<TEntity> where TEntity : class
{
/// <summary>
/// Gets a queryable for the entity.
/// </summary>
/// <returns>An IQueryable for the entity type.</returns>
IQueryable<TEntity> Gets();
/// <summary>
/// Gets a queryable projected to a DTO type.
/// </summary>
/// <typeparam name="TDto">The DTO type.</typeparam>
/// <returns>An IQueryable for the DTO type.</returns>
IQueryable<TDto> GetDto<TDto>() where TDto : class;
/// <summary>
/// Gets an entity by its identifier.
/// </summary>
/// <param name="id">The entity identifier.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>The entity if found; otherwise, null.</returns>
Task<TEntity?> GetByIdAsync(Guid id, CancellationToken cancellationToken = default);
}
namespace DKNet.EfCore.Repos;
/// <summary>
/// Base repository implementation.
/// </summary>
/// <typeparam name="TEntity">The entity type.</typeparam>
public class Repository<TEntity> : IRepository<TEntity>, IReadRepository<TEntity>
where TEntity : class
{
protected readonly DbContext Context;
protected readonly DbSet<TEntity> DbSet;
public Repository(DbContext context)
{
Context = context;
DbSet = context.Set<TEntity>();
}
public virtual IQueryable<TEntity> Gets() => DbSet;
public virtual IQueryable<TDto> GetDto<TDto>() where TDto : class
{
return Gets().ProjectToType<TDto>();
}
public virtual async Task<TEntity?> FindAsync(Guid id, CancellationToken cancellationToken = default)
{
return await DbSet.FindAsync(new object[] { id }, cancellationToken);
}
public virtual async Task<TEntity?> GetByIdAsync(Guid id, CancellationToken cancellationToken = default)
{
return await FindAsync(id, cancellationToken);
}
public virtual async Task<TEntity> AddAsync(TEntity entity, CancellationToken cancellationToken = default)
{
var entry = await DbSet.AddAsync(entity, cancellationToken);
return entry.Entity;
}
public virtual void Update(TEntity entity)
{
DbSet.Update(entity);
}
public virtual void Delete(TEntity entity)
{
DbSet.Remove(entity);
}
public virtual async Task<IEnumerable<TEntity>> FindAsync(
Specification<TEntity> specification,
CancellationToken cancellationToken = default)
{
return await Gets()
.Where(specification.ToExpression())
.ToListAsync(cancellationToken);
}
}
namespace DKNet.EfCore.Specifications;
/// <summary>
/// Base class for specifications.
/// </summary>
/// <typeparam name="T">The entity type.</typeparam>
public abstract class Specification<T>
{
/// <summary>
/// Converts the specification to a LINQ expression.
/// </summary>
/// <returns>A LINQ expression representing the specification.</returns>
public abstract Expression<Func<T, bool>> ToExpression();
/// <summary>
/// Combines this specification with another using AND logic.
/// </summary>
/// <param name="specification">The specification to combine.</param>
/// <returns>A new specification representing the AND combination.</returns>
public Specification<T> And(Specification<T> specification)
{
return new AndSpecification<T>(this, specification);
}
/// <summary>
/// Combines this specification with another using OR logic.
/// </summary>
/// <param name="specification">The specification to combine.</param>
/// <returns>A new specification representing the OR combination.</returns>
public Specification<T> Or(Specification<T> specification)
{
return new OrSpecification<T>(this, specification);
}
/// <summary>
/// Creates a specification that negates this specification.
/// </summary>
/// <returns>A new specification representing the negation.</returns>
public Specification<T> Not()
{
return new NotSpecification<T>(this);
}
/// <summary>
/// Implicit conversion from specification to expression.
/// </summary>
/// <param name="specification">The specification.</param>
public static implicit operator Expression<Func<T, bool>>(Specification<T> specification)
{
return specification.ToExpression();
}
}
namespace DKNet.SlimBus.Extensions;
/// <summary>
/// Base interface for commands.
/// </summary>
public interface ICommand
{
/// <summary>
/// Gets or sets the user who initiated the command.
/// </summary>
string? ByUser { get; set; }
}
/// <summary>
/// Interface for commands that return a response.
/// </summary>
/// <typeparam name="TResponse">The response type.</typeparam>
public interface ICommand<TResponse> : ICommand
{
}
/// <summary>
/// Interface for queries that return a response.
/// </summary>
/// <typeparam name="TResponse">The response type.</typeparam>
public interface IQuery<TResponse>
{
}
/// <summary>
/// Interface for command handlers.
/// </summary>
/// <typeparam name="TCommand">The command type.</typeparam>
public interface ICommandHandler<in TCommand> where TCommand : ICommand
{
Task<IResultBase> OnHandle(TCommand command, CancellationToken cancellationToken = default);
}
/// <summary>
/// Interface for command handlers with response.
/// </summary>
/// <typeparam name="TCommand">The command type.</typeparam>
/// <typeparam name="TResponse">The response type.</typeparam>
public interface ICommandHandler<in TCommand, TResponse> where TCommand : ICommand<TResponse>
{
Task<IResult<TResponse>> OnHandle(TCommand command, CancellationToken cancellationToken = default);
}
/// <summary>
/// Interface for query handlers.
/// </summary>
/// <typeparam name="TQuery">The query type.</typeparam>
/// <typeparam name="TResponse">The response type.</typeparam>
public interface IQueryHandler<in TQuery, TResponse> where TQuery : IQuery<TResponse>
{
Task<TResponse> OnHandle(TQuery query, CancellationToken cancellationToken = default);
}
/// <summary>
/// Base interface for operation results.
/// </summary>
public interface IResultBase
{
bool IsSuccess { get; }
bool IsFailure { get; }
string ErrorMessage { get; }
IEnumerable<Error> Errors { get; }
}
/// <summary>
/// Interface for operation results with value.
/// </summary>
/// <typeparam name="T">The value type.</typeparam>
public interface IResult<T> : IResultBase
{
T Value { get; }
}
/// <summary>
/// Represents an operation result.
/// </summary>
public class Result : IResultBase
{
protected Result(bool isSuccess, string errorMessage, IEnumerable<Error>? errors = null)
{
IsSuccess = isSuccess;
ErrorMessage = errorMessage;
Errors = errors ?? Enumerable.Empty<Error>();
}
public bool IsSuccess { get; }
public bool IsFailure => !IsSuccess;
public string ErrorMessage { get; }
public IEnumerable<Error> Errors { get; }
/// <summary>
/// Creates a successful result.
/// </summary>
/// <returns>A successful result.</returns>
public static Result Ok() => new(true, string.Empty);
/// <summary>
/// Creates a failed result.
/// </summary>
/// <param name="errorMessage">The error message.</param>
/// <returns>A failed result.</returns>
public static Result Fail(string errorMessage) => new(false, errorMessage);
/// <summary>
/// Creates a successful result with value.
/// </summary>
/// <typeparam name="T">The value type.</typeparam>
/// <param name="value">The value.</param>
/// <returns>A successful result with value.</returns>
public static Result<T> Ok<T>(T value) => new(true, value, string.Empty);
/// <summary>
/// Creates a failed result with value type.
/// </summary>
/// <typeparam name="T">The value type.</typeparam>
/// <param name="errorMessage">The error message.</param>
/// <returns>A failed result.</returns>
public static Result<T> Fail<T>(string errorMessage) => new(false, default!, errorMessage);
}
namespace DKNet.Svc.BlobStorage.Abstractions;
/// <summary>
/// Interface for blob storage operations.
/// </summary>
public interface IBlobStorageService
{
/// <summary>
/// Uploads a blob to storage.
/// </summary>
/// <param name="blobName">The blob name/path.</param>
/// <param name="stream">The stream containing the blob data.</param>
/// <param name="contentType">The content type.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>The blob URI.</returns>
Task<string> UploadAsync(
string blobName,
Stream stream,
string? contentType = null,
CancellationToken cancellationToken = default);
/// <summary>
/// Downloads a blob from storage.
/// </summary>
/// <param name="blobName">The blob name/path.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>A stream containing the blob data.</returns>
Task<Stream> DownloadAsync(
string blobName,
CancellationToken cancellationToken = default);
/// <summary>
/// Deletes a blob from storage.
/// </summary>
/// <param name="blobName">The blob name/path.</param>
/// <param name="cancellationToken">The cancellation token.</param>
Task DeleteAsync(
string blobName,
CancellationToken cancellationToken = default);
/// <summary>
/// Checks if a blob exists in storage.
/// </summary>
/// <param name="blobName">The blob name/path.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>true if the blob exists; otherwise, false.</returns>
Task<bool> ExistsAsync(
string blobName,
CancellationToken cancellationToken = default);
/// <summary>
/// Lists blobs with optional prefix filter.
/// </summary>
/// <param name="prefix">The prefix filter.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>A collection of blob information.</returns>
Task<IEnumerable<BlobInfo>> ListAsync(
string? prefix = null,
CancellationToken cancellationToken = default);
}
/// <summary>
/// Information about a blob.
/// </summary>
public record BlobInfo
{
public required string Name { get; init; }
public required long Size { get; init; }
public required DateTime LastModified { get; init; }
public string? ContentType { get; init; }
public string? ETag { get; init; }
}
namespace DKNet.Configuration;
/// <summary>
/// Configuration options for DKNet Framework.
/// </summary>
public class DKNetOptions
{
/// <summary>
/// Gets or sets whether audit fields are automatically populated.
/// </summary>
public bool EnableAuditFields { get; set; } = true;
/// <summary>
/// Gets or sets whether soft delete is enabled.
/// </summary>
public bool EnableSoftDelete { get; set; } = true;
/// <summary>
/// Gets or sets the default timezone for date operations.
/// </summary>
public string DefaultTimeZone { get; set; } = "UTC";
/// <summary>
/// Gets or sets the maximum page size for paged queries.
/// </summary>
public int MaxPageSize { get; set; } = 1000;
/// <summary>
/// Gets or sets whether detailed error information is included in responses.
/// </summary>
public bool EnableDetailedErrors { get; set; } = false;
/// <summary>
/// Gets or sets whether sensitive data logging is enabled.
/// </summary>
public bool EnableSensitiveDataLogging { get; set; } = false;
}
namespace Microsoft.Extensions.DependencyInjection;
public static class ServiceCollectionExtensions
{
/// <summary>
/// Adds DKNet core services to the service collection.
/// </summary>
/// <param name="services">The service collection.</param>
/// <param name="configuration">The configuration action.</param>
/// <returns>The service collection.</returns>
public static IServiceCollection AddDKNet(
this IServiceCollection services,
Action<DKNetOptions>? configuration = null);
/// <summary>
/// Adds DKNet repositories for the specified DbContext.
/// </summary>
/// <typeparam name="TContext">The DbContext type.</typeparam>
/// <param name="services">The service collection.</param>
/// <returns>The service collection.</returns>
public static IServiceCollection AddDKNetRepositories<TContext>(
this IServiceCollection services)
where TContext : DbContext;
/// <summary>
/// Adds DKNet blob storage services.
/// </summary>
/// <param name="services">The service collection.</param>
/// <param name="configuration">The configuration action.</param>
/// <returns>The service collection.</returns>
public static IServiceCollection AddDKNetBlobStorage(
this IServiceCollection services,
Action<BlobStorageBuilder> configuration);
/// <summary>
/// Adds DKNet SlimBus integration.
/// </summary>
/// <param name="services">The service collection.</param>
/// <returns>The service collection.</returns>
public static IServiceCollection AddDKNetSlimBus(this IServiceCollection services);
}
For practical usage examples of all APIs, see:
📝 API Documentation: This reference covers the most commonly used APIs. For complete API documentation, see the XML documentation in the source code or generated documentation.