Pr.BuildingBlocks.Cms.Core 5.0.1

dotnet add package Pr.BuildingBlocks.Cms.Core --version 5.0.1
                    
NuGet\Install-Package Pr.BuildingBlocks.Cms.Core -Version 5.0.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="Pr.BuildingBlocks.Cms.Core" Version="5.0.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Pr.BuildingBlocks.Cms.Core" Version="5.0.1" />
                    
Directory.Packages.props
<PackageReference Include="Pr.BuildingBlocks.Cms.Core" />
                    
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 Pr.BuildingBlocks.Cms.Core --version 5.0.1
                    
#r "nuget: Pr.BuildingBlocks.Cms.Core, 5.0.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.
#:package Pr.BuildingBlocks.Cms.Core@5.0.1
                    
#: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=Pr.BuildingBlocks.Cms.Core&version=5.0.1
                    
Install as a Cake Addin
#tool nuget:?package=Pr.BuildingBlocks.Cms.Core&version=5.0.1
                    
Install as a Cake Tool

Pr.BuildingBlocks.Cms.Core

Biblioteka building blocków warstwy domeny dla mikroserwisów CMS Polskiego Radia. Zawiera podstawowe abstrakcje, kontrakty i klasy bazowe — bez zależności od ASP.NET Core, EF Core, Wolverine ani konkretnej infrastruktury. Pakiet startowy każdego mikroserwisu CMS.

  • Target framework: net8.0
  • PackageId: Pr.BuildingBlocks.Cms.Core
  • Wersja: 5.0.1

Spis treści


Instalacja

<PackageReference Include="Pr.BuildingBlocks.Cms.Core" Version="5.0.1" />

Typy domenowe

Bazowe abstrakcje budowy modelu domenowego (DDD).

Entity<TId>

Bazowa encja z typowanym identyfikatorem. Implementuje równość na podstawie typu i wartości Id (operatory == i != plus Equals/GetHashCode). Po zmianie Id zmienia się też hash, więc encje należy traktować jako niezmienne pod tym względem.

public sealed class Episode : Entity<EpisodeId>
{
    public string Title { get; private set; }

    private Episode(EpisodeId id, string title) : base(id) { Title = title; }
}

AggregateRoot<TId>

Bazowy agregat (dziedziczy Entity<TId>, implementuje IAggregateRoot). Udostępnia:

  • IReadOnlyCollection<IDomainEvent> DomainEvents — zdarzenia zarejestrowane podczas operacji.
  • int Version — token wersjonowania dla optimistic concurrency.
  • protected void AddDomainEvent(IDomainEvent @event) — dodaje zdarzenie do kolekcji.
  • protected void IncrementVersion() — inkrementuje Version.
  • void ClearDomainEvents() — czyści listę po publikacji (wołane przez DomainEventsMiddleware).

IAggregateRoot

Interfejs marker eksponujący DomainEvents i ClearDomainEvents(). Wykorzystywany przez DomainEventsMiddleware w warstwie Infrastructure do automatycznego wykrywania agregatów w ChangeTracker EF Core i publikacji ich zdarzeń.

TypedId

Bazowy rekord dla strongly-typed ID. Opakowuje Guid Value. W trybie isRequired = true (domyślnym) walida, że wartość nie jest Guid.Empty (rzuca ArgumentException z komunikatem „Wartość ID nie może być wartością domyślną.").

public sealed record EpisodeId(Guid Value) : TypedId(Value);

Zapewnia bezpieczeństwo typów — nie pomylisz EpisodeId z ArticleId, choć oba opakowują Guid.

IValueObject<T>

Kontrakt obiektu wartości. Wymusza pojedynczą właściwość T Value. Współpracuje z ValueObjectConverterFactory — typy implementujące IValueObject<T> są automatycznie serializowane jako prymityw w JSON.

public sealed record Slug(string Value) : IValueObject<string>;

Zdarzenia domenowe

IDomainEvent

Kontrakt zdarzenia: Guid Id, DateTimeOffset OccurredOn, void SetTime(DateTimeOffset). OccurredOn jest ustawiane na końcu pipeline'u przez DomainEventsMiddleware (Infrastructure) za pomocą IClock.UtcNow, dzięki czemu w testach jednostkowych domena nie zna czasu.

DomainEvent

Bazowa klasa zdarzenia. W konstruktorze generuje Guid.NewGuid() jako Id. Pochodne klasy zwykle są rekordami niosącymi tylko dane:

public sealed record EpisodePublished(EpisodeId EpisodeId, string Title) : DomainEvent;

Komendy

Markery dla komend obsługiwanych przez Wolverine.

  • IInternalCommand — komenda lokalna (in-process). Routing/konwencje Wolverine traktują ten interfejs jako sygnał, że wiadomość ma być obsługiwana przez handler w tym samym procesie.
  • IExternalCommand — komenda przekraczająca granicę procesu (message bus, RabbitMQ, inny mikroserwis). Routing kieruje ją na zewnętrzny transport.

Oba interfejsy są puste (markerami) — używaj ich jako : IInternalCommand / : IExternalCommand na rekordzie komendy.


Wyjątki domenowe

Wszystkie wyjątki domenowe dziedziczą po BaseException, co pozwala middleware ExceptionHandlerMiddleware (Infrastructure) automatycznie mapować je na odpowiedzi HTTP z polskimi komunikatami.

Wyjątek HTTP Tytuł odpowiedzi Kiedy używać
DomainException 400 „Błąd aplikacji" (przez BaseException) Ogólny błąd domenowy.
DomainRuleException 400 „Naruszenie reguły domenowej" Naruszenie konkretnej, nazwanej reguły domenowej.
InvalidValueException 400 „Nieprawidłowa wartość" Walidacja pojedynczego pola; konstruktory z propertyName i providedValue.
InvalidArgumentException 400 „Błąd aplikacji" Niepoprawny argument metody — semantyka domenowa zamiast ArgumentException.
InvalidActionException 400 „Błąd aplikacji" Próba wykonania niedozwolonej akcji w bieżącym stanie.
NotFoundException 404 „Nie znaleziono zasobu" Brak żądanego zasobu (resourceName + resourceId).
ConflictException 409 „Konflikt zasobu" Ogólny konflikt operacji.
ResourceAlreadyExistsException 400 „Błąd aplikacji" Próba utworzenia istniejącego już zasobu.
ForbiddenException 403 „Odmowa dostępu" Brak uprawnień do operacji.
OptimisticConcurrencyException 409 „Konflikt optymistycznej współbieżności" Konflikt wersji agregatu (EntityType, opcjonalne EntityId).
UniqueConstraintViolationException 409 „Naruszenie unikalności" Naruszenie unikalnego klucza w bazie (z opcjonalnym ConstraintName).

Konstruktory większości wyjątków przyjmują albo dwie wartości (np. resourceName + resourceId), albo gotowy komunikat — wybierz to, co lepiej pasuje do kontekstu.

if (episode is null)
    throw new NotFoundException(nameof(Episode), episodeId);

if (versionMismatch)
    throw new OptimisticConcurrencyException(nameof(Episode), episodeId);

Guard clauses

Walidacja wejściowa w stylu Ardalis.GuardClauses. Punkt wejścia: Guard.Against.

Metoda Rzuca Działanie
Null<T>(T?) ArgumentNullException null (klasa) lub HasValue == false (struct).
NullOrWhiteSpace(string?) ArgumentException null, pusty lub same białe znaki.
Empty(Guid) ArgumentException Guid.Empty.
LengthOutOfRange(string, int min, int max) InvalidValueException Długość poza zakresem [min, max].
OutOfRange<T>(T value, T min, T max) gdzie T : IComparable<T> InvalidValueException Wartość poza zakresem [min, max] (włącznie).
InvalidEnum<TEnum>(string raw) InvalidValueException Niepoprawna nazwa enum (case-sensitive). Komunikat zawiera dozwolone wartości.
NegativeOrZero(int) InvalidValueException value <= 0.
Negative(int) InvalidValueException value < 0.
public sealed record CreateEpisodeRequest(string Title, int DurationSeconds, string Status)
{
    public void Validate()
    {
        Guard.Against.NullOrWhiteSpace(Title);
        Guard.Against.LengthOutOfRange(Title, 1, 200);
        Guard.Against.NegativeOrZero(DurationSeconds);
        Guard.Against.InvalidEnum<EpisodeStatus>(Status);
    }
}

Wszystkie metody używają atrybutu [CallerArgumentExpression], dzięki czemu nazwa parametru w komunikacie jest wykrywana automatycznie.


Czas

IClock

Abstrakcja dostawcy czasu — wstrzykuj zamiast DateTime.UtcNow/DateTimeOffset.UtcNow, żeby testy mogły kontrolować czas.

public interface IClock
{
    DateTimeOffset UtcNow { get; }
    DateOnly Today { get; }
}

Domyślna implementacja SystemDateTimeProvider znajduje się w Pr.BuildingBlocks.Cms.Infrastructure i zwraca czas w strefie Europe/Warsaw.


Slugi

ISlugifier

Kontrakt komponentu generującego slug z dowolnego tekstu (string GenerateSlug(string text)). Implementacja Slugifier znajduje się w Pr.BuildingBlocks.Cms.Infrastructure i jest konfigurowalna od v5.0.0 przez services.AddSlugifier(opt => ...) (lower case, collapse dashes, trim, custom replacements). Domyślnie obsługuje polskie znaki diakrytyczne i transliteruje cyrylicę. Szczegóły: README pakietu Infrastructure.


DTO

PagedResultDto<T>

Generyczny DTO wyniku stronicowanego:

Pole Opis
Data Lista elementów na stronie (IReadOnlyList<T>).
Total Łączna liczba rekordów (przed paginacją).
PageNumber Numer strony (1-based).
PageSize Rozmiar strony.
TotalPages Wyliczane: (int)Math.Ceiling(Total / (double)PageSize).

Filtr ApiResponseWrapperFilter (Infrastructure) rozpoznaje ten typ i nie opakowuje go w { data: ... } — paginacja ma już własną strukturę.

return new PagedResultDto<EpisodeDto>(items, totalCount, pageNumber, pageSize);

Konwertery JSON

ValueObjectConverterFactory

Fabryka konwerterów System.Text.Json automatycznie obsługująca każdy typ implementujący IValueObject<T>. Przy odczycie woła statyczną metodę Create(TPrimitive) lub publiczny konstruktor; przy zapisie serializuje samą wartość prymitywną.

services.Configure<JsonOptions>(options =>
{
    options.SerializerOptions.Converters.Add(new ValueObjectConverterFactory());
});

Po rejestracji Slug (z przykładu wyżej) jest serializowany jako goły string, nie obiekt: "abc" zamiast { "value": "abc" }.

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.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  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.
  • net8.0

    • No dependencies.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on Pr.BuildingBlocks.Cms.Core:

Package Downloads
Pr.BuildingBlocks.Cms.Infrastructure

Implementacje infrastruktury (ASP.NET Core, EF Core PostgreSQL, Wolverine) dla mikroserwisów CMS.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
5.0.1 263 4/28/2026
5.0.0 103 4/28/2026
4.0.1 117 4/27/2026
4.0.0 112 4/27/2026
3.5.2 212 3/15/2026
3.5.1 103 3/9/2026
3.5.0 112 3/9/2026
3.3.0 525 1/17/2026
3.2.0 152 1/12/2026
3.1.6 186 12/30/2025
3.1.2 937 10/1/2025
3.1.1 238 10/1/2025
3.1.0 242 9/30/2025
3.0.5 316 9/29/2025
3.0.3 174 9/27/2025
3.0.1 219 9/26/2025
3.0.0 288 9/23/2025
2.1.4 308 9/15/2025
2.1.3 182 9/12/2025
2.1.2 215 9/11/2025
Loading failed