Franz.Common.Aras
2.3.0
dotnet add package Franz.Common.Aras --version 2.3.0
NuGet\Install-Package Franz.Common.Aras -Version 2.3.0
<PackageReference Include="Franz.Common.Aras" Version="2.3.0" />
<PackageVersion Include="Franz.Common.Aras" Version="2.3.0" />
<PackageReference Include="Franz.Common.Aras" />
paket add Franz.Common.Aras --version 2.3.0
#r "nuget: Franz.Common.Aras, 2.3.0"
#:package Franz.Common.Aras@2.3.0
#addin nuget:?package=Franz.Common.Aras&version=2.3.0
#tool nuget:?package=Franz.Common.Aras&version=2.3.0
# Franz.Common.Aras � v1.5.0 ??
**Franz.Common.Aras** integrates **ARAS Innovator** into the **Franz Framework** with clean, DDD-driven abstractions.
It lets you treat ARAS as just another persistence provider � with **Entities**, **Aggregates**, **Unit of Work**, **Snapshots**, **Diagnostics**, and an **InMemory provider for testing**.
---
## ?? What�s New in v1.5.0
- ? **Concrete ARAS Innovator provider** (REST API)
- ? **Fluent mapping layer** (field ? property, ignores, conversions)
- ? **Unit of Work** (commit entities + aggregates atomically)
- ? **Snapshotting** (optimize large aggregates, replay only post-snapshot events)
- ? **Diagnostics decorators** (logging + OpenTelemetry tracing)
- ? **InMemory provider** (unit testing without ARAS)
- ? **AddArasInnovator bootstrapper** (EF-style DI registration)
- ? **Full samples** for Entities, Aggregates, UoW, Testing, and Snapshots
Current Version: v2.3.0
?? Installation
dotnet add package Franz.Common.Aras
If you�re in a class library (not ASP.NET Core), also add:
dotnet add package Microsoft.Extensions.Http
?? Setup
Register ARAS Innovator with dependency injection:
using Franz.Common.Aras.Innovator;
using Microsoft.Extensions.DependencyInjection;
var services = new ServiceCollection();
services.AddArasInnovator(options =>
{
options.BaseUrl = "https://aras.server/InnovatorServer";
options.Database = "InnovatorSolutions";
options.UserName = "admin";
options.Password = "innovator";
// Optional:
options.UseDiagnostics = true;
options.SnapshotFrequency = 50; // every 50 events
});
?? Entities (CRUD)
Entities are simple Entity<Guid> models.
public class PartEntity : Entity<Guid>
{
public string PartNumber { get; set; } = default!;
public string Description { get; set; } = default!;
}
Define a repository:
public class PartRepository : ArasEntityRepository<PartEntity>
{
public PartRepository(IArasEntityContext context) : base(context) { }
}
Usage sample:
var repo = provider.GetRequiredService<PartRepository>();
// Create
var part = new PartEntity { PartNumber = "PN-1000", Description = "Widget" };
await repo.AddAsync(part);
// Read
var fetched = await repo.GetByIdAsync(part.Id);
Console.WriteLine($"Fetched {fetched.PartNumber} - {fetched.Description}");
// Update
fetched.Description = "Updated Widget";
await repo.UpdateAsync(fetched);
// Delete
await repo.DeleteAsync(fetched.Id);
?? Aggregates (DDD + Events)
Aggregates inherit from AggregateRoot<TEvent> and model behavior with domain events.
public record PartCreated(Guid PartId, string PartNumber) : BaseDomainEvent;
public class PartAggregate : AggregateRoot<PartCreated>
{
public string PartNumber { get; private set; } = default!;
public void Create(string number)
{
ApplyChange(new PartCreated(Id, number));
}
protected override void When(PartCreated e)
{
Id = e.PartId;
PartNumber = e.PartNumber;
}
}
Usage sample:
var aggregates = provider.GetRequiredService<IArasAggregateContext>();
var partAgg = new PartAggregate();
partAgg.Create("PN-2000");
await aggregates.SaveAggregateAsync(partAgg);
// Load again (replay events or snapshot)
var loaded = await aggregates.GetAggregateAsync<PartAggregate, PartCreated>(partAgg.Id);
Console.WriteLine($"Loaded aggregate with PartNumber = {loaded.PartNumber}");
?? Unit of Work
Commit entities + aggregates in one go:
using var uow = provider.GetRequiredService<IArasUnitOfWork>();
// Entities
uow.Entities.Add(new PartEntity { PartNumber = "PN-3000", Description = "Bolt" });
// Aggregates
var partAgg = new PartAggregate();
partAgg.Create("PN-4000");
uow.Aggregates.TrackAggregate(partAgg);
// Commit atomically
await uow.CommitAsync();
Console.WriteLine("UoW committed successfully");
Rollback clears tracked changes:
await uow.RollbackAsync();
Console.WriteLine("UoW rolled back");
?? InMemory Provider (Testing)
Use the in-memory contexts without ARAS server:
services.AddInMemoryAras();
var context = provider.GetRequiredService<IArasEntityContext>();
await context.SaveEntityAsync(new PartEntity { PartNumber = "TEST-1" });
var parts = await context.QueryEntitiesAsync<PartEntity>("all");
foreach (var part in parts)
Console.WriteLine($"InMemory part: {part.PartNumber}");
Aggregate testing:
var aggregates = provider.GetRequiredService<IArasAggregateContext>();
var agg = new PartAggregate();
agg.Create("TEST-AGG");
await aggregates.SaveAggregateAsync(agg);
var reloaded = await aggregates.GetAggregateAsync<PartAggregate, PartCreated>(agg.Id);
Console.WriteLine($"Reloaded aggregate: {reloaded.PartNumber}");
?? Snapshots (Performance)
Aggregates are snapshotted automatically every N events (default 50):
var agg = await aggregates.GetAggregateAsync<PartAggregate, PartCreated>(id);
// Replays only events after last snapshot
You can configure snapshot frequency in ArasInnovatorOptions:
options.SnapshotFrequency = 25;
?? Diagnostics
Enable structured logging + tracing with decorators:
services.AddLogging(b => b.AddConsole());
services.AddOpenTelemetryTracing();
services.Decorate<IArasEntityContext, DiagnosticEntityContextDecorator>();
services.Decorate<IArasAggregateContext, DiagnosticAggregateContextDecorator>();
You�ll get logs for:
- Entity queries, saves, deletes
- Aggregate tracking, saving, committing
- Event publishing
- Snapshot operations
Sample log:
[INF] Querying entities of type PartEntity
[INF] Saving aggregate PartAggregate/PN-2000 with 1 new events
[INF] Published event PartCreated { PartId = ..., PartNumber = "PN-2000" }
? Summary
- Entities ? simple CRUD
- Aggregates ? DDD + event sourcing
- Unit of Work ? atomic batch commit
- InMemory ? testing without ARAS
- Snapshots ? scalable performance
- Diagnostics ? enterprise observability
- Bootstrapper ? one-liner service registration
?? Samples
This repo includes a samples/ folder with ready-to-run console apps:
Sample.Entities? CRUD with PartEntitySample.Aggregates? Domain events with PartAggregateSample.UoW? Entities + aggregates in one transactionSample.InMemory? Tests without ARASSample.Diagnostics? Logs + tracing
Franz.Common.Aras v1.5.0 � bringing ARAS into the DDD world.
Version 1.6.20
- Updated to .NET 10.0
v2.0.1 � Internal Modernization
- Messaging and infrastructure refactored for async, thread-safety, and modern .NET 10 patterns.
- All APIs remain fully backward compatible.
- Tests, listeners, and pipeline components modernized.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | 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
- Franz.Common.Business (>= 2.3.0)
- Franz.Common.EntityFramework (>= 2.3.0)
- Franz.Common.Errors (>= 2.3.0)
- Franz.Common.Mediator (>= 2.3.0)
- Microsoft.Extensions.Http (>= 10.0.10)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 2.3.0 | 117 | 7/21/2026 |
| 2.2.19 | 110 | 7/19/2026 |
| 2.2.18 | 97 | 7/19/2026 |
| 2.2.17 | 102 | 7/12/2026 |
| 2.2.16 | 112 | 7/2/2026 |
| 2.2.15 | 121 | 6/29/2026 |
| 2.2.14 | 112 | 6/29/2026 |
| 2.2.13 | 113 | 6/29/2026 |
| 2.2.12 | 109 | 6/28/2026 |
| 2.2.11 | 108 | 6/28/2026 |
| 2.2.10 | 119 | 6/28/2026 |
| 2.2.9 | 111 | 6/28/2026 |
| 2.2.8 | 108 | 6/28/2026 |
| 2.2.7 | 117 | 6/7/2026 |
| 2.2.6 | 126 | 6/6/2026 |
| 2.2.5 | 120 | 6/4/2026 |
| 2.2.4 | 113 | 6/3/2026 |
| 2.2.3 | 115 | 6/2/2026 |
| 2.2.2 | 117 | 6/2/2026 |
| 2.2.1 | 111 | 5/24/2026 |