BaseLib.Core 3.1.3

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

BaseLib.Core

Overview

BaseLib.Core is a foundational library for building backend services in .NET. It simplifies the creation of services by providing base classes that implement common patterns and functionalities.

BaseLib.Core services are platform-agnostic, meaning they can run in various environments, such as containers, Azure Functions, or AWS Lambdas.

Key Concepts

The Service Class

A service represents a single backend operation and follows a Request/Response pattern.

Request

Requests are derived from CoreRequestBase.

Example:

public class CheckoutRequest : CoreRequestBase
{
    public int CustomerId { get; set; }
    public string CustomerName { get; set; }
    public string IdentificationNumber { get; set; }
    public CreditCard? CreditCard { get; set; }
    public Product[] Items{ get; set; }
}

Response

Responses are derived from CoreResponseBase and contain a Succeeded property to indicate success.

Example:

public class CheckoutResponse : CoreResponseBase
{
    public long OrderId { get; set; }
}

Service Implementation

Services inherit from CoreServiceBase<TRequest,TResponse>, where TRequest and TResponse are your custom request and response types. The core logic is implemented in the RunAsync() method.

Example:

public class CheckoutService : CoreServiceBase<CheckoutRequest, CheckoutResponse>
{
    protected override async Task<CheckoutResponse> RunAsync()
    {
        // Implementation logic here...
        var order = await CreateOrderAsync(this.Request.CustomerId, this.Request.Items);
        return new CheckoutResponse { Succeeded = true, OrderId = order.Id };
    }
}

Reason codes

Responses include a ReasonCode, which consists of an integer value and a string description.

The ReasonCode can be assigned from Enum types. It maps the integer value from the enum's integer value and the description from the Description attribute, if present; otherwise, it uses the label of the enum value.

This approach offers a convenient way to handle Reason Codes as enums within the application.

Example:

enum EcommerceReasonCode
{
    [Description("Product is not available at this time")]
    NoItemsAvailable = 10448
}


public class CheckoutService : CoreServiceBase<CheckoutRequest, CheckoutResponse>
{
    protected override async Task<CheckoutResponse> RunAsync()
    {
        if (!CheckForAvailability(this.Request.Products))
        {
            return new CheckoutResponse
            {
                Succeeded = false,
                ReasonCode = EcommerceReasonCode.NoItemsAvailable
            };
        }
        // Implementation logic here...
    }
}

Events Support

The ICoreStatusEventSink interface provides support for event-driven choreography between services. This capability enables the asynchronous triggering of actions in response to events.

A typical implementation of ICoreStatusEventSink publishes the event to an external publish/subscribe messaging system, subscribers of the messaging system will react to events published by the service.

In the diagram below, a CheckoutService publish an event to a Topic on a messaging system. The subscribers of this Topic receive the events and subsequently execute the 'create order' and 'create invoice' services, respectively.

flowchart LR;
    s(CheckoutService) -- event --> Topic;
    Topic -- event --> s1-->CreateOrderService;
    Topic -- event -->s2-->CreateInvoiceService;

Service required to report events need to use the build in constructor passing the ICoreStatusEventSink.

Example:

public class CheckoutService : CoreServiceBase<CheckoutRequest, CheckoutResponse>
{

    // A Constructor with the eventsink
    public CheckoutService(ICoreStatusEventSink? eventsink)
        : base(eventSink: eventsink)
    {

    }

    // Implementation Logic here...
}

Long-Running Services

Some operations need to fan out work to child services and wait for all of them to complete before producing a final result. CoreLongRunningServiceBase<TRequest, TResponse> handles this pattern.

How it works

  1. The parent service runs and spawns child services via FireAsync or FireManyAsync.
  2. After RunAsync completes, the framework detects pending children, serialises the service state, and suspends with status Suspended.
  3. When all children finish, an ICoreLongRunningServiceManager triggers ResumeAsync on the parent with the saved operationId.
  4. The parent restores its state and calls ResumeAsync() to produce the final response.
sequenceDiagram
    participant Client
    participant Parent as ParentService (LongRunning)
    participant Fire as ICoreServiceFireOnly
    participant Store as ICoreServiceStateStore
    participant Manager as ICoreLongRunningServiceManager
    participant Child as ChildService

    Client->>Parent: RunAsync(request)
    Parent->>Fire: FireManyAsync<ChildService>(requests)
    Fire-->>Child: (async, fire-and-forget)
    Parent->>Store: WriteAsync(operationId, state)
    Parent-->>Client: Response (Suspended)

    Child-->>Manager: StatusEvent (Finished)
    Manager->>Parent: ResumeAsync(operationId)
    Parent->>Store: ReadAsync(operationId)
    Parent-->>Client: Final Response (Finished)

Implementation

public class BatchInvoiceService : CoreLongRunningServiceBase<BatchInvoiceRequest, BatchInvoiceResponse>
{
    private int[] _orderIds = [];

    public BatchInvoiceService(
        ICoreServiceFireOnly fireOnly,
        ICoreServiceStateStore stateStore,
        ICoreStatusEventSink? eventSink = null)
        : base(fireOnly, stateStore, eventSink: eventSink) { }

    protected override async Task<BatchInvoiceResponse> RunAsync()
    {
        _orderIds = this.Request.OrderIds;

        // Fire one child per order — service suspends until all complete
        await FireManyAsync<CreateInvoiceService>(
            _orderIds.Select(id => new CreateInvoiceRequest { OrderId = id }));

        return new BatchInvoiceResponse { Succeeded = true };
    }

    protected override Task<BatchInvoiceResponse> ResumeAsync()
    {
        // All children finished — produce final result
        return Task.FromResult(new BatchInvoiceResponse
        {
            Succeeded = true,
            InvoiceCount = _orderIds.Length
        });
    }
}

Required dependencies

Dependency Purpose
ICoreServiceFireOnly Dispatches child service invocations without blocking
ICoreServiceStateStore Persists/restores service field state across suspension
ICoreStatusEventSink (Optional) Publishes lifecycle events

AWS implementations: SqsCoreServiceFireOnly (fire), S3CoreServiceStateStore (state).


Input Validation with FluentValidation

Pass a FluentValidation.IValidator<TRequest> to the base constructor. If validation fails, the service returns a failed response with ReasonCode = ValidationResultNotValidRunAsync() is never called.

The WithReasonCode extension maps a domain enum value as the FluentValidation error code and message:

public class CheckoutValidator : AbstractValidator<CheckoutRequest>
{
    public CheckoutValidator()
    {
        RuleFor(r => r.Items)
            .NotEmpty()
            .WithReasonCode(EcommerceReasonCode.NoItemsAvailable);
    }
}

public class CheckoutService : CoreServiceBase<CheckoutRequest, CheckoutResponse>
{
    public CheckoutService(ICoreStatusEventSink? eventSink = null)
        : base(validator: new CheckoutValidator(), eventSink: eventSink) { }

    protected override async Task<CheckoutResponse> RunAsync()
    {
        // Only reached when validation passes
    }
}

Polymorphic JSON Serialization

PolymorphicConverter<T> enables serialization of polymorphic object graphs (e.g. CoreRequestBase subclasses stored in CoreStatusEvent). It embeds a ___type discriminator property with the assembly-qualified type name.

Usage — register on JsonSerializerOptions:

var options = new JsonSerializerOptions();
options.Converters.Add(new PolymorphicConverter<CoreRequestBase>());

var json = JsonSerializer.Serialize<CoreRequestBase>(myRequest, options);
var restored = JsonSerializer.Deserialize<CoreRequestBase>(json, options);
// restored is the correct concrete subclass

PolymorphicConverter is used internally by CoreSerializer when serialising CoreStatusEvent payloads. You normally do not need to configure it manually.

Secure variantSecurePolymorphicConverter<T> works the same way but encrypts properties decorated with [CoreSecret] using an IEncryptionKeyProvider:

options.Converters.Add(new SecurePolymorphicConverter<CoreRequestBase>(encryptionKeyProvider));

Serializers

Class Description
CoreSerializer Static helper using System.Text.Json with PolymorphicConverter pre-registered for CoreRequestBase and CoreResponseBase. Used internally by the framework.
CoreJsonSerializer ICoreSerializer implementation backed by System.Text.Json.
CoreSecureJsonSerializer ICoreSerializer implementation that encrypts [CoreSecret] annotated fields using IEncryptionKeyProvider.

Helper Methods

CoreServiceBase exposes two convenience methods for building responses:

// Fail with a reason code and optional messages
return this.Fail(EcommerceReasonCode.NoItemsAvailable, "No stock remaining");

// Succeed with an optional reason code
return this.Succeed();
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.

NuGet packages (3)

Showing the top 3 NuGet packages that depend on BaseLib.Core:

Package Downloads
FacturaE.Sdk

Package Description

BaseLib.Core.AmazonCloud

Package Description

BaseLib.Core.MySql

Package Description

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
3.1.3 120 4/5/2026
3.1.1 137 2/25/2026
3.1.1-alpha-003 232 9/14/2025
3.1.1-alpha-001 191 9/13/2025
3.1.0 456 9/8/2025
3.0.0-beta-004 219 5/7/2025
3.0.0-beta-003 259 5/7/2025
2.1.0.5 646 3/19/2025
2.1.0.4 1,661 5/22/2024
2.1.0.3 293 5/15/2024
2.1.0.2 945 1/16/2024
2.1.0.1 276 12/30/2023
2.1.0 682 12/28/2023
2.0.2 1,174 11/22/2023
2.0.1 340 11/21/2023
2.0.0 409 11/1/2023
1.1.0 268 10/16/2023
1.1.0-beta-004 3,621 11/22/2022
1.1.0-beta-003 634 11/16/2022
1.1.0-beta-002 368 11/15/2022
Loading failed