* Add ingress rate limiting hooks * Fix ingress rate limiting middleware setup * Harden rate limiter policy validation * Preserve routed endpoints during rate limiting * Address rate limiting review feedback * Address rate limiting Copilot feedback * Register rate limiter services for external policies * Address rate limiting review comments * Keep rate limiter service detection best effort * Address rate limiting review comments * Remove brittle rate limiter validation * Address rate limiting review feedback * Address rate limiting nullable review * Address rate limiting review feedback * Assign ingress rate limit policies when enabled * Refine ingress rate limiting middleware cleanup * Address rate limiting review feedback * Align rate limiting review feedback * Clarify rate limiting policy semantics * Stabilize rate limiting exception tests * Fix rate limiting endpoint matching default
6.1 KiB
Extension Guide
Elsa is designed to be extended by adding modules, features, activities, stores, expression providers, API endpoints, and runtime integration points. This page collects the common patterns.
Add A Code-First Feature
- Create
Features/MyFeature.cs. - Derive from
FeatureBase. - Add
[DependsOn]attributes for required features. - Use
Configure()for feature graph changes and activity scanning. - Use
ConfigureHostedServices()for hosted services. - Use
Apply()for service registration. - Add
Extensions/ModuleExtensions.cswithUseMyFeature. - Add unit tests that prove core services register.
Use HttpFeature, SchedulingFeature, and StructuredLogsFeature as examples.
Add A Shell Feature
Shell features live in ShellFeatures and implement CShells interfaces such as IShellFeature, IFastEndpointsShellFeature, or IMiddlewareShellFeature.
Use shell features when modular server/package configuration needs to activate the feature without code-first AddElsa calls.
Examples:
- Elsa.Shells.Api/ShellFeatures/ShellsApiFeature.cs
- Elsa.Diagnostics.StructuredLogs/ShellFeatures/StructuredLogsFeature.cs
- EF Core provider shell features
Add An Activity
- Put the activity in the owning module's
Activitiesfolder. - Derive from
Activity,Activity<T>,CodeActivity, or a module-specific base. - Use
Input<T>andOutput<T>for designer/runtime compatibility. - Register the activity with workflow management.
- Add descriptor/UI hint handlers if the designer needs dynamic options.
- Test activity-only behavior with
ActivityTestFixture. - Add integration/component tests for bookmarks, triggers, persistence, or transport behavior.
Good examples:
Add An Expression Provider
Expression providers need:
- evaluator contract and implementation
- expression descriptor provider
- optional activity for running scripts
- optional UI hint handler
- option type
- feature registration
- tests for evaluator behavior and workflow integration
Compare existing language modules:
Add An API Endpoint
- Create a folder under the relevant
Endpointscategory. - Add
Endpoint.csand localModels.cswhen needed. - Derive from the Elsa endpoint base used by nearby endpoints.
- Configure verb, route, permissions, and summary.
- Inject service contracts, not concrete internals when possible.
- Add endpoint tests or component coverage if behavior is important.
- Update client models if the endpoint is part of the public client surface.
Use route prefixing from MapWorkflowsApi; endpoint routes should usually be written without /elsa/api.
Add A Store Or Persistence Provider
For an EF Core-backed store:
- Add the entity/configuration/store to the shared EF Core module slice if it is a common Elsa domain.
- Add provider-specific migrations if persisted shape changes.
- Replace the owning feature's store factory in the persistence feature.
- Add tests for query/filter/order behavior.
- Add provider integration tests for migrations or SQL differences.
For diagnostics structured log relational providers:
- Reference the relational structured-log package.
- Implement
IRelationalStructuredLogConnectionFactory. - Implement
IRelationalStructuredLogDialect. - Implement
IStructuredLogSchemaMigrator. - Register those services and call
AddRelationalStructuredLogPersistence.
See SqliteStructuredLogsModuleExtensions.
Add A Runtime Ingress Source
External event sources should participate in graceful shutdown. Add an ingress source when a module feeds work into the runtime from outside the engine.
Steps:
- Implement the runtime
IIngressSourcecontract in the owning module. - Register it as a singleton service.
- Make dispatch loops or middleware honor paused state.
- Add tests for pause/resume/drain behavior.
Existing first-party examples are HTTP and Scheduling ingress source registrations.
Add A Workflow Provider
Workflow providers bring definitions from external storage. Existing examples:
Keep provider modules focused on discovery/materialization and leave execution to runtime.
Add Documentation
Update docs when changing:
- public APIs
- options/configuration
- endpoint routes
- persistence schema or provider setup
- runtime behavior
- security/authorization behavior
- developer workflows
Good locations:
- module README
- relevant spec quickstart
- this wiki
- ADR for architectural decisions
Design Rules Of Thumb
- Keep core provider-neutral.
- Use feature configuration instead of direct cross-module service replacement.
- Add dependencies explicitly with
[DependsOn]. - Prefer contracts at module boundaries.
- Put tests near the module whose behavior changed.
- Avoid adding shared abstractions until at least two real modules need them.