Features
Summary
A Feature groups business logic by namespace. Features tell the source generator what order to register [Logic] classes in.
You write a Feature class. The generator does the rest.
One folder = one feature
Sales/
├── Feature.cs ← IFeature, LogicNameSpace = "...Sales"
├── SalesEntity.cs
└── SalesBL.cs ← belongs to Sales
Sales/Doc/
├── Feature.cs ← IFeature, LogicNameSpace = "...Sales.Doc"
├── DocEntity.cs
└── DocBL.cs ← belongs to Sales.Doc
The folder = the namespace. The namespace = the feature.
The Feature class
public class Feature : IFeature
{
public string Name => "Sales Doc";
public string Description => "Sales document management.";
public string LogicNameSpace => "Benevia.ERP.Sales.Doc";
}
No singleton needed — the runtime constructs features on demand via the registry.
Two ways to declare dependencies
1. Implicit (by namespace)
Sales.Doc is automatically after Sales — its namespace is a child.
graph LR
Sales["Sales<br/>(namespace: ...Sales)"]
SalesDoc["Sales.Doc<br/>(namespace: ...Sales.Doc)"]
Sales -->|"automatic<br/>(namespace prefix)"| SalesDoc
No code needed.
2. Explicit (across namespaces)
For features in different namespace branches, use [FeatureDependsOn].
[FeatureDependsOn(typeof(Products.Feature), typeof(Customers.Feature))]
public class Feature : IFeature
{
public string Name => "Sales Doc";
public string LogicNameSpace => "Benevia.ERP.Sales.Doc";
public string Description => "...";
}
graph LR
Products["Products"]
Customers["Customers"]
SalesDoc["Sales.Doc"]
Products -->|"FeatureDependsOn"| SalesDoc
Customers -->|"FeatureDependsOn"| SalesDoc
Resulting order
graph TB
A["services.AddBeneviaERPSalesDocBL()"]
A --> B["Products BL registers"]
B --> C["Customers BL registers"]
C --> D["Sales.Doc BL registers"]
D --> E["LogicProvider invokes<br/>methods in registered order"]
The order in BusinessLogicConfig._items is now:
- Products
- Customers
- Sales.Doc
That order propagates straight into compute subscriber order — see Multiple subscribers on one property.
Rules
| Rule | What happens |
|---|---|
Sales.Doc namespace child of Sales |
Sales runs first (automatic). |
[FeatureDependsOn(typeof(X))] |
X runs first. |
| Manual dep contradicts namespace rule | Throws FeatureDependencyException at build/startup. |
Cycle (A → B → A) |
Throws FeatureDependencyException. |