Skip to content

Getting Started

ZibStack.NET is a collection of source generators for .NET. Each package is independent — install only what you need. Start at Tier 1 (drop-in, zero architectural buy-in) and move deeper only if it fits your project — see the Three tiers overview for orientation.

Terminal window
dotnet add package ZibStack.NET.Log

Add one attribute to get structured logging, OpenTelemetry tracing, or both — no architectural changes.

Program.cs
using ZibStack.NET.Aop;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAop(); // registers built-in [Trace] handler
var app = builder.Build();
app.Services.UseAop(); // bridges DI into the aspect runtime
app.Run();
Services/OrderService.cs
using ZibStack.NET.Aop;
public class OrderService
{
[Log] // structured entry/exit/exception logging
[Trace] // OpenTelemetry span with parameter tags
public async Task<Order> GetOrderAsync(int id)
{
// ... your code unchanged
}
// Or, for the whole class:
// [Log] [Trace] public class OrderService { ... }
}

You now have compile-time structured logging and OpenTelemetry spans with zero boilerplate. Wire an exporter (AddOpenTelemetry().WithTracing().AddOtlpExporter()) and you’re done.

If you want the full-stack scaffold: define a model, add one attribute, and get a full REST API with database persistence. Note this moves a lot of code out of your hands — best for solo or small-team projects.

Models/Player.cs
using ZibStack.NET.Dto;
using ZibStack.NET.Validation;
[CrudApi]
[ZValidate]
public partial class Player
{
[DtoIgnore] public int Id { get; set; }
[ZRequired] [ZMinLength(2)]
public required string Name { get; set; }
[ZRange(1, 100)]
public int Level { get; set; }
[ZEmail]
public string? Email { get; set; }
}
AppDbContext.cs
using ZibStack.NET.EntityFramework;
[GenerateCrudStores]
public class AppDbContext : DbContext
{
public DbSet<Player> Players => Set<Player>();
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }
}
Program.cs
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<AppDbContext>(o => o.UseSqlite("Data Source=app.db"));
builder.Services.AddAppDbContextCrudStores(); // auto-generated
builder.Services.ConfigureHttpJsonOptions(o =>
o.SerializerOptions.Converters.Add(new PatchFieldJsonConverterFactory()));
var app = builder.Build();
using (var scope = app.Services.CreateScope())
scope.ServiceProvider.GetRequiredService<AppDbContext>().Database.EnsureCreated();
app.MapPlayerEndpoints(); // auto-generated: GET, POST, PATCH, DELETE
app.Run();

That’s it. You now have:

EndpointMethodDescription
/api/playersGETList with pagination
/api/players/{id}GETGet by ID
/api/playersPOSTCreate with validation
/api/players/{id}PATCHPartial update
/api/players/{id}DELETEDelete

All responses use ProblemDetails (RFC 9110) for errors, and PatchField for true partial updates.

Source generators run at compile time and emit C# code into your project. No reflection, no runtime overhead, full IntelliSense support. The generated code is visible in obj/ — you can inspect exactly what’s produced.