UA.Tenet
10.0.3
dotnet add package UA.Tenet --version 10.0.3
NuGet\Install-Package UA.Tenet -Version 10.0.3
<PackageReference Include="UA.Tenet" Version="10.0.3" />
<PackageVersion Include="UA.Tenet" Version="10.0.3" />
<PackageReference Include="UA.Tenet" />
paket add UA.Tenet --version 10.0.3
#r "nuget: UA.Tenet, 10.0.3"
#:package UA.Tenet@10.0.3
#addin nuget:?package=UA.Tenet&version=10.0.3
#tool nuget:?package=UA.Tenet&version=10.0.3
UA.Tenet
UA.Tenet is the core package of the Tenet framework. It gives a .NET solution one consistent application vocabulary: attributed services and agents, request and result contracts, reusable data helpers, explicit collection and query shaping, smart enums, and process-local messaging and events.
Why this package exists
Use UA.Tenet when you want a stable application core that stays independent from ASP.NET Core while still providing:
- convention-based dependency injection for services and agents
- configuration-first constructor activation for scalar settings
- result-first workflows instead of exception-only happy paths
- reusable JSON, XML, CSV, SQL, HTTP, and text helpers at integration boundaries
- transportable filters, projections, and in-memory coordination primitives
If the host also needs HTTP endpoints, MVC, middleware, or Razor helpers, layer UA.Tenet.Web on top instead of replacing UA.Tenet.
Best fit
Use UA.Tenet when you are building:
- shared libraries and domain or application layers
- background or scheduled components modeled as Tenet agents
- import, export, and integration-heavy services
- API backends that need reusable filters, mapping helpers, or collection shaping
- utility packages that should keep web concerns outside the core assembly
Package characteristics
- Targets
.NET 8,.NET 9, and.NET 10. - Ships XML documentation, SourceLink metadata, package symbols, and a package README.
- Integrates with
Microsoft.Extensions.Configuration.AbstractionsandMicrosoft.Extensions.Logging.Abstractions.
Core feature map
| Area | Main entry points | What you get |
|---|---|---|
| Composition | [TenetService], [TenetAgent], AddTenetServices(), AddTenetAgents(), ServiceBase<TModel, TContext>, AgentBase |
Convention-based DI registration, keyed services, service and agent lifetimes, configuration-first activation |
| Requests and results | Request, Request<T>, Result, Result<T>, Command<T>, Observer, Singleton<TValue>, ResponsabilityChain |
Stable boundary contracts and explicit success or error outcomes |
| Data helpers | Json, Xml, Csv, CsvSerializerOptions, Sql, Http, Text |
Serialization, ADO.NET helpers, HTTP calls, and text normalization |
| Collections and query shaping | Any<T>, CanonicalSet, UniqueIndex<T>, EnumerableExtension, QueryableExtension, ConditionalExpression, RuleExpression, IMappable<TSource, TResult> |
Dynamic filtering, explicit projection semantics, and collection materializers such as ToAny() and ToCanonicalSet() |
| Coordination and richer models | SmartEnum<T>, IMessageBroker, IEventBroker, InMemoryMessageBroker, InMemoryEventBroker |
Process-local messaging, events, and string-backed enum models |
Installation
dotnet add package UA.Tenet
Quick start
Register Tenet services and agents
using UA.Tenet.Agents.Extensions;
using UA.Tenet.Services.Extensions;
builder.Services.AddTenetServices();
builder.Services.AddTenetAgents();
Implement a result-first Tenet service
using Microsoft.Extensions.Logging;
using UA.Tenet.Design;
using UA.Tenet.Services;
public sealed class CustomerModel
{
public string? Name { get; set; }
}
public sealed class CustomerContext
{
}
[TenetService]
public sealed class CustomerService(CustomerContext context, ILogger<CustomerService> logger)
: ServiceBase<CustomerModel, CustomerContext>(context, logger)
{
public Result<string> CreateWelcomeMessage(Request<string> request)
{
if (string.IsNullOrWhiteSpace(request.Value))
return new Result<string>(request).WithErrors("Validation", "Customer name is required.");
Model = new CustomerModel { Name = request.Value };
return new Result<string>(request)
{
Value = $"Tenet is ready for {Model.Name}."
};
}
}
Model an agent with configuration-first scalar activation
using Microsoft.Extensions.Logging;
using UA.Tenet.Agents;
public interface IInvoiceCleanupAgent
{
Task RunAsync(CancellationToken cancellationToken);
}
[TenetAgent(Type = typeof(IInvoiceCleanupAgent), Lifetime = AgentLifetime.Singleton)]
public sealed class InvoiceCleanupAgent(
int retentionDays,
ILogger<InvoiceCleanupAgent> logger) : AgentBase, IInvoiceCleanupAgent
{
public Task RunAsync(CancellationToken cancellationToken)
{
logger.LogInformation("Cleaning invoices older than {RetentionDays} days.", retentionDays);
return Task.CompletedTask;
}
}
{
"InvoiceCleanupAgent": {
"RetentionDays": 30
}
}
Compose data helpers inside a service boundary
using System.Data.Common;
using UA.Tenet.Data;
using UA.Tenet.Design;
using UA.Tenet.Services;
[TenetService]
public sealed class CustomerImportService(DbConnection connection)
{
public async Task<Result<int>> ImportAsync(Uri endpoint, CancellationToken cancellationToken)
{
await using Stream payload = await Http.GetStreamAsync(endpoint, cancellationToken);
IEnumerable<CustomerRow>? rows = await payload.FromCsv<CustomerRow>(cancellationToken: cancellationToken);
int imported = 0;
foreach (CustomerRow row in rows ?? [])
{
if (string.IsNullOrWhiteSpace(row.ExternalCode))
return new Result<int>().WithErrors("Validation", "ExternalCode is required.");
await using DbCommand command = await connection.OpenCommand(
"insert into Customers(ExternalCode, Name) values (@ExternalCode, @Name)");
command.AddParameter("@ExternalCode", row.ExternalCode);
command.AddParameter("@Name", row.Name);
await command.ExecuteNonQueryAsync(cancellationToken);
imported++;
}
return new Result<int>(imported);
}
}
public sealed class CustomerRow
{
public string? ExternalCode { get; set; }
public string? Name { get; set; }
}
Important behavioral notes
- Auto-registration scans assemblies already loaded into the current
AppDomain. - Tenet activates attributed types through the first public constructor it finds, so one public constructor is the safest shape.
- Scalar constructor parameters are read from configuration sections named after the target type before Tenet falls back to DI.
Result<T>.IsSuccessfulis based on whether errors were collected, not on whetherValueis non-null.SmartEnum<T>normalizes names to uppercase and compares them case-insensitively.EnumerableExtensionandQueryableExtensionuse explicit-path projection semantics: direct node requests copy scalar members only, and deeper navigation shaping requires explicit nested paths.- The in-memory message and event brokers are process-local helpers, not durable infrastructure.
Relationship to UA.Tenet.Web
UA.Tenet is the core layer. Add UA.Tenet.Web when the solution needs HTTP composition, OpenAPI, MVC, minimal APIs, or Razor helpers.
What to read next
- Getting started: https://docs.uadevs.org/tenet/getting-started
- Package guide: https://docs.uadevs.org/tenet/ua-tenet
- Services and agents: https://docs.uadevs.org/tenet/services-agents-dependency-injection
- Data helpers: https://docs.uadevs.org/tenet/data-helpers
- Web layer: https://docs.uadevs.org/tenet/ua-tenet-web
| 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 is compatible. 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 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
- Microsoft.Extensions.Configuration.Abstractions (>= 10.0.5)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.5)
-
net8.0
- Microsoft.Extensions.Configuration.Abstractions (>= 10.0.5)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.5)
-
net9.0
- Microsoft.Extensions.Configuration.Abstractions (>= 10.0.5)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.5)
NuGet packages (2)
Showing the top 2 NuGet packages that depend on UA.Tenet:
| Package | Downloads |
|---|---|
|
UA.Azure.Storage
UA.Azure.Storage provides a lightweight, efficient implementation for accessing Azure Storage Services (Blob, Queue, and Table) in .NET applications. Built on the Tenet Framework principles, it offers a simplified agent-based approach to interact with Azure Storage without heavy SDK dependencies. |
|
|
UA.Tenet.Web
UA.Tenet.Web extends the Tenet Framework for ASP.NET Core applications. It provides a unified convention-based configuration combining the structure of Controller-based APIs with the performance of Minimal APIs, along with TagHelpers, view components, and web extensions. |
GitHub repositories
This package is not used by any popular GitHub repositories.
See https://docs.uadevs.org/tenet/release-notes for release notes and documentation.