BaseLib.Core
3.1.3
dotnet add package BaseLib.Core --version 3.1.3
NuGet\Install-Package BaseLib.Core -Version 3.1.3
<PackageReference Include="BaseLib.Core" Version="3.1.3" />
<PackageVersion Include="BaseLib.Core" Version="3.1.3" />
<PackageReference Include="BaseLib.Core" />
paket add BaseLib.Core --version 3.1.3
#r "nuget: BaseLib.Core, 3.1.3"
#:package BaseLib.Core@3.1.3
#addin nuget:?package=BaseLib.Core&version=3.1.3
#tool nuget:?package=BaseLib.Core&version=3.1.3
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
- The parent service runs and spawns child services via
FireAsyncorFireManyAsync. - After
RunAsynccompletes, the framework detects pending children, serialises the service state, and suspends with statusSuspended. - When all children finish, an
ICoreLongRunningServiceManagertriggersResumeAsyncon the parent with the savedoperationId. - 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 = ValidationResultNotValid — RunAsync() 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
PolymorphicConverteris used internally byCoreSerializerwhen serialisingCoreStatusEventpayloads. You normally do not need to configure it manually.
Secure variant — SecurePolymorphicConverter<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 | Versions 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. |
-
net8.0
- FluentValidation (>= 11.12.0)
- MimeKit (>= 4.15.1)
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 |