Skip to content

ZibStack.NET.Aop — Alternatives

.NET AOP has three historical waves:

  1. MSIL rewriters — PostSharp (2008, commercial)
  2. Runtime proxies — Castle.DynamicProxy (free, but requires virtual/interface)
  3. Roslyn-native source gen — Metalama (2023, commercial) and now this package

Resilience patterns (retry / timeout / circuit-breaker / cache) have their own fluent libraries — Polly and Microsoft.Extensions.Caching.Hybrid — that ZibStack.NET.Aop wraps with a declarative attribute instead of fluent plumbing at every call site.

FeatureZibStack.NET.AopPostSharpMetalamaCastle.DynamicProxyPolly / HybridCache
DispatchRoslyn source gen + C# 12 interceptorsMSIL post-processingRoslyn + T# templateRuntime proxy genDirect API calls
Price✅ MIT freeCommercial (paid)Commercial (free tier)MIT freeMIT free
Needs virtual/interface?❌ works on any method✅ yes — can’t wrap sealed/non-virtualn/a (wrapping)
Runtime reflection✅ proxy generation
Overhead per callzero dispatch (direct inline via interceptor)near zeronear zeroproxy + dispatchsingle delegate
Declarative attributes[Retry], [Timeout], [Trace], [Cache], …❌ (wire via DI container)❌ (fluent API)
Retry / timeout / circuit-breaker✅ built-in + Polly bridge ([PollyRetry], [PollyCircuitBreaker], [PollyRateLimiter], [HttpRetry])custom aspectcustom aspectcustom interceptor✅ built-in
HybridCache (.NET 9+)[HybridCache] attributen/an/an/a✅ library API
Entry/exit/exception logging[Log] (via ZibStack.NET.Log inline emitter — zero alloc)custom aspectcustom aspectn/an/a
OpenTelemetry Activities[Trace]custom aspectcustom aspectn/an/a
System.Diagnostics.Metrics[Metrics]custom aspectcustom aspectn/an/a
Project-wide defaults✅ fluent IAopConfiguratorvia conventionvia fabric classn/afluent per-client
Source-visible generated codeEmitCompilerGeneratedFiles=true writes .g.cs❌ (IL only)✅ T# previewsn/an/a
Analyzer feedback at write time✅ AOP0xxx diagnosticsvia build step✅ real-timen/an/a

Metalama’s T# is more powerful for custom aspects that rewrite method bodies in complex ways — our extension model is simpler (IAsyncAroundAspectHandler, IAspectHandler) and doesn’t expose a template language. For exotic compile-time transformations (changing control flow, injecting new members, editing existing syntax trees) you’d still pick Metalama.

You want declarative cross-cutting concerns (retry, timeout, cache, trace, metrics, logging) on any method, with zero runtime cost and without paying for PostSharp/Metalama or the virtual + container dance of Castle.DynamicProxy. The [PollyRetry] / [HybridCache] bridges give you the best-in-class resilience/cache libs with an attribute instead of fluent plumbing at every call site.

  • Polly / HybridCache directly — you build retry/cache strategies at runtime based on non-compile-time data (dynamic configs, per-request policies), or you want one handler wrapping multiple method calls at a single DI seam.
  • Metalama — you’re writing custom aspects that heavily rewrite method bodies, want the T# template language, and commercial licensing is fine.
  • Castle.DynamicProxy — you need runtime-decided aspects (interceptors chosen based on runtime config), have interfaces everywhere, and don’t care about the proxy allocation.