Cephalon.Behaviors.SourceGen
เนื้อหานี้ยังไม่ได้แปลเป็นภาษาไทย แสดงเป็นภาษาอังกฤษแทน
Maturity:
M1· Ownership: cephalon-managed · Family:behaviors· See audit, matrix.
Cephalon.Behaviors.SourceGen is the M5 compile-time tooling layer of the Adaptive Behavior Topology (ABT).
It provides a Roslyn incremental source generator and diagnostic analyzer that validate behavior authoring
conventions at build time and produce a compile-time-known registration hint file.
What it owns
Section titled “What it owns”- BehaviorSourceGenerator — combined Roslyn
IIncrementalGenerator+ diagnostic analyzer- Uses
ForAttributeWithMetadataNamefor efficient incremental processing - Emits
BehaviorRegistrationHints.g.cslisting all discovered[AppBehavior]IDs - Emits
BehaviorAutoRegistration.g.csfor zero-reflection DI/type registration plus pre-built topology descriptors when compile-time extraction succeeds - Emits source-generated metadata-only REST profile hints through
GetRestProfiles()when behaviors declare validBehaviorRestProfileAttributemetadata - Extracts compile-time topology from
ConfigureTopology(...)for pattern, transports, feature flags, and literalWithApiSurface(...)overrides
- Uses
- Reports ABT0010–ABT0027 diagnostics on invalid behavior declarations, metadata-only REST profile hints, malformed REST profile placeholder syntax, explicit REST binding metadata, and invalid preserved implicit query-fallback authoring before
GetRestProfiles()is generated
Diagnostic rules
Section titled “Diagnostic rules”| Code | Severity | Description |
|---|---|---|
| ABT0010 | Error | [AppBehavior] class does not implement IAppBehavior<TIn, TOut> |
| ABT0011 | Error | [AppBehavior] ID is null or empty |
| ABT0012 | Error | [AppBehavior] class is abstract |
| ABT0013 | Error | [AppBehavior] class is static |
| ABT0014 | Error | REST is declared in behavior topology instead of a module-owned REST surface |
| ABT0015 | Error | [BehaviorRestProfile] does not select a supported REST method |
| ABT0016 | Error | [BehaviorRestProfile] uses an empty relative pattern |
| ABT0017 | Error | [BehaviorRestProfile] uses a non-positive ApiVersionMajor |
| ABT0018 | Error | [BehaviorRestProfile] uses a relative pattern that does not start with / |
| ABT0019 | Error | [BehaviorRestBinding] does not name a target input property |
| ABT0020 | Error | [BehaviorRestBinding] does not select a supported binding source |
| ABT0021 | Error | [BehaviorRestBinding] metadata is declared for a scalar input or an input without public readable properties |
| ABT0022 | Error | [BehaviorRestBinding] targets an input property that does not exist |
| ABT0023 | Error | [BehaviorRestBinding] declares the same input property more than once |
| ABT0024 | Error | [BehaviorRestBinding] uses Body on a REST method that does not accept a request body |
| ABT0025 | Error | [BehaviorRestBinding] uses a route placeholder that is not declared in [BehaviorRestProfile(...)] |
| ABT0026 | Error | [BehaviorRestProfile] uses malformed route placeholder syntax such as unbalanced or empty {...} segments |
| ABT0027 | Error | [BehaviorRestProfile(PreserveImplicitQueryFallback = true)] is declared without any explicit [BehaviorRestBinding] metadata |
Generated output
Section titled “Generated output”BehaviorRegistrationHints.g.cs and BehaviorAutoRegistration.g.cs are emitted into the consuming project at build time:
// <auto-generated/>// Generated by Cephalon.Behaviors.SourceGen — do not edit.
namespace Cephalon.Behaviors.Generated;
internal static class BehaviorRegistrationHints{ internal static readonly IReadOnlyList<string> BehaviorIds = [ "order.place", "order.get", ];}When the generator can statically understand ConfigureTopology(...), it also emits zero-reflection
registration and topology data, including literal WithApiSurface(...) overrides:
internal static class BehaviorAutoRegistration{ internal static IReadOnlyList<BehaviorTopologyDescriptor> GetTopologyDescriptors() { return [ new BehaviorTopologyDescriptor( "catalog.lookup", "cqrs", new[] { "http.jsonrpc", "http.sse" }, apiSurface: new BehaviorApiSurfaceDescriptor("catalog/items", "lookup")) ]; }}When a behavior also declares a valid metadata-only REST profile, the generated registration type now emits future-facing REST profile hints without publishing any public REST routes:
internal static class BehaviorAutoRegistration{ internal static IReadOnlyList<BehaviorRestProfileDescriptor> GetRestProfiles() { return [ new BehaviorRestProfileDescriptor( "catalog.lookup", BehaviorRestMethod.Get, "/{itemId}", 2, [ new BehaviorRestBindingDescriptor( "ItemId", BehaviorRestBindingSource.Route, "itemId") ]) ]; }}For REST profile methods and binding sources, the generator now validates against the stable
wire-name vocabularies instead of hardcoding enum member names: BehaviorRestMethod uses get,
post, put, patch, and delete, while BehaviorRestBindingSource uses route, query,
header, and body. Generated GetRestProfiles() hints still emit the resolved enum member
names, so future package versions can rename those members without breaking valid metadata as long
as the stable wire-name contracts stay intact.
Integration
Section titled “Integration”The generator is automatically applied when Cephalon.Behaviors is referenced. No additional setup required.
The Cephalon.Behaviors package references Cephalon.Behaviors.SourceGen as an analyzer, so the generator
and diagnostics activate for any project that references Cephalon.Behaviors.
Compile-time topology extraction intentionally stays conservative. Literal WithApiSurface(...)
arguments are supported, while more complex expressions fall back to runtime topology resolution so
the generated surface stays truthful. Public REST is module-owned and therefore sits outside the
behavior source-generator topology model; ABT0014 now rejects http.rest and ViaHttpRest(...)
so authors map REST in a module with RestBehaviorModuleBase.ConfigureRestBehaviors(...), or with
manual MapBehaviorRestGroup(...) wiring when they intentionally stay on the low-level REST module
path.
BehaviorRestProfileAttribute plus optional repeated BehaviorRestBindingAttribute declarations
are now the shipped metadata-only bridge for future low-ceremony REST: the generator validates the
core profile shape plus explicit binding metadata, preserved implicit query-fallback authoring, and
emits GetRestProfiles() hints, including explicit binding descriptors and
preserveImplicitQueryFallback: true when present, plus GetRestProfileBehaviorTypes() hints for
the generated module-owned shorthand path, but that metadata still does not publish public REST
routes by itself and does not override host OpenAPI document publication policy.
Cephalon.Behaviors.Http now consumes those hints through the explicit module-owned
MapProfile<TBehavior>(), MapGeneratedProfiles(...), and
IRestBehaviorModuleBuilder.MapGeneratedProfileGroups(...) shorthands, preferring the generated
hints and falling back only to the explicitly targeted behavior type’s attribute or to a bounded
scan of the explicit owning module assembly when the current assembly lacks generated type hints.
Generated REST profile and binding hints now resolve their enum member names from the actual
attribute arguments instead of assuming fixed numeric ordinals.
The build now rejects unsupported binding sources, malformed route placeholder syntax, missing or
duplicate input-property targets, scalar-input misuse, body-binding verb restrictions,
route-placeholder mismatches, and preserved implicit-query fallback without any explicit bindings
earlier, while Cephalon.Behaviors.Http still re-checks the same contract when the runtime falls
back to direct attribute resolution for MapProfile<TBehavior>() or to the bounded owner-assembly
scan used by MapGeneratedProfiles(...) and MapGeneratedProfileGroups(...). Runtime
normalization still lets ASP.NET Core route parsing stay authoritative for the final route-shape
truth even after the generator moves the most common placeholder-shape mistakes and preserved-
fallback authoring errors to compile time.
Likewise, explicit module ownership through IBehaviorOwnerModule, BehaviorModuleBase, or
RestBehaviorModuleBase remains a runtime-composition concern rather than a source-generated
topology concern: the generator still focuses on behavior shape and topology, while the engine owns
which module claims each behavior.
When a behavior has no compile-time topology but does declare exactly one allowed pattern plus one
or more allowed transports, the runtime synthesizes the attribute-only baseline descriptor from
those attributes. If multiple allowed patterns are declared, runtime resolution still fails fast
until another topology source selects one explicitly.
Status
Section titled “Status”Status: ✅ Shipped — targeted source-generator tests 29/29
Related components
Section titled “Related components”Cephalon.Behaviors— dispatcher, catalog, resolver (M1)Cephalon.Behaviors.Http— HTTP transport bindings (M2)Cephalon.Behaviors.Messaging— messaging transport bindings (M3)Cephalon.Behaviors.Patterns— pattern execution strategies (M4)