{"id":21393226,"url":"https://github.com/camunda-community-hub/zeebe-client-csharp-accelerator","last_synced_at":"2025-09-05T10:34:53.060Z","repository":{"id":63939999,"uuid":"545383044","full_name":"camunda-community-hub/zeebe-client-csharp-accelerator","owner":"camunda-community-hub","description":"C# Zeebe Job Workers made easy - boostrapped via a .NET HostedService and added to DI","archived":false,"fork":false,"pushed_at":"2025-08-16T06:45:05.000Z","size":552,"stargazers_count":12,"open_issues_count":8,"forks_count":10,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-08-16T08:36:33.531Z","etag":null,"topics":["camunda-platform-8","csharp","dotnet","zb-client","zb-client-accelerator","zb-grcp","zeebe","zeebe-client"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"camunda-community-hub/zeebe-client-csharp-bootstrap","license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/camunda-community-hub.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2022-10-04T09:12:33.000Z","updated_at":"2025-08-14T10:36:58.000Z","dependencies_parsed_at":"2024-03-11T15:28:00.190Z","dependency_job_id":"7159f4a7-1961-4314-a638-21615e8e0d66","html_url":"https://github.com/camunda-community-hub/zeebe-client-csharp-accelerator","commit_stats":{"total_commits":143,"total_committers":8,"mean_commits":17.875,"dds":0.4755244755244755,"last_synced_commit":"ac9bfcfcc36f494482f6fe60fd0893591c28212d"},"previous_names":["vonderbeck/zeebe-client-csharp-accelerator"],"tags_count":27,"template":false,"template_full_name":null,"purl":"pkg:github/camunda-community-hub/zeebe-client-csharp-accelerator","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/camunda-community-hub%2Fzeebe-client-csharp-accelerator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/camunda-community-hub%2Fzeebe-client-csharp-accelerator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/camunda-community-hub%2Fzeebe-client-csharp-accelerator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/camunda-community-hub%2Fzeebe-client-csharp-accelerator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/camunda-community-hub","download_url":"https://codeload.github.com/camunda-community-hub/zeebe-client-csharp-accelerator/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/camunda-community-hub%2Fzeebe-client-csharp-accelerator/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":273746892,"owners_count":25160647,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-05T02:00:09.113Z","response_time":402,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["camunda-platform-8","csharp","dotnet","zb-client","zb-client-accelerator","zb-grcp","zeebe","zeebe-client"],"created_at":"2024-11-22T14:10:40.446Z","updated_at":"2025-09-05T10:34:53.045Z","avatar_url":"https://github.com/camunda-community-hub.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![BUILD](https://github.com/VonDerBeck/zeebe-client-csharp-accelerator/actions/workflows/build.yml/badge.svg)](https://github.com/VonDerBeck/zeebe-client-csharp-accelerator/actions/workflows/build.yml)\n[![ANALYZE](https://github.com/VonDerBeck/zeebe-client-csharp-accelerator/actions/workflows/analyze.yml/badge.svg)](https://github.com/VonDerBeck/zeebe-client-csharp-accelerator/actions/workflows/analyze.yml)\n[![](https://img.shields.io/nuget/v/zb-client-accelerator.svg)](https://www.nuget.org/packages/zb-client-accelerator/) \n[![](https://img.shields.io/nuget/dt/zb-client-accelerator)](https://www.nuget.org/stats/packages/zb-client-accelerator?groupby=Version) \n[![](https://img.shields.io/github/license/VonDerBeck/zeebe-client-csharp-accelerator.svg)](https://www.apache.org/licenses/LICENSE-2.0) \n[![](https://img.shields.io/badge/Community%20Extension-An%20open%20source%20community%20maintained%20project-FF4700)](https://github.com/camunda-community-hub/community)\n![Compatible with: Camunda Platform 8](https://img.shields.io/badge/Compatible%20with-Camunda%20Platform%208-0072Ce)\n[![](https://img.shields.io/badge/Lifecycle-Incubating-blue)](https://github.com/Camunda-Community-Hub/community/blob/main/extension-lifecycle.md#incubating-)\n\n# Bootstrap Accelerator for the C# Zeebe client\n\nThis project is an extension of the [C# Zeebe client project](https://github.com/camunda-community-hub/zeebe-client-csharp). Zeebe Workers are automatically recognized and bootstrapped via a [.Net HostedService](https://docs.microsoft.com/en-us/dotnet/architecture/microservices/multi-container-microservice-net-applications/background-tasks-with-ihostedservice).\n\nRead the [Zeebe documentation](https://docs.camunda.io/docs/components/zeebe/zeebe-overview/) for more information about the Zeebe project.\n\nThe basic idea and implementation for this came from https://github.com/camunda-community-hub/zeebe-client-csharp-bootstrap.\nWe loved the idea, but had in some parts our own preferences for defaults, behaviour and separation of concerns. So this is our version of a good Bootstrap\nExtension for the C# Zeebe Client. Credits for the base work still belong to https://github.com/arjangeertsema.\n\n## Requirements\n\nSince version 2.2.0:\n\n* [.NET 7](https://dotnet.microsoft.com/en-us/download/dotnet/7.0) / [.NET 8](https://dotnet.microsoft.com/en-us/download/dotnet/8.0) / [.NET 9](https://dotnet.microsoft.com/en-us/download/dotnet/9.0)\n* [Zeebe C# client 2.9.0 release](https://www.nuget.org/packages/zb-client/)\n* [Zeebe 8.x release](https://github.com/zeebe-io/zeebe/releases/)\n\nFor older .NET versions please use the 1.x.x release of this extension based on Zeebe C# client 1.3.0 release.\n\n## How to use\n\nThe Zeebe C# client bootstrap extension is available via nuget (https://www.nuget.org/packages/zb-client-accelerator/).\n\n**Recommendation:** a complete sample project using this extension can be found in [examples].\n\n## Quick start\n\nAll classes which implement `IZeebeWorker`, `IAsyncZeebeWorker`, `IZeebeWorkerWithResult` or `IAsyncZeebeWorkerWithResult` are automatically added to the service collection and autowired to Zeebe when you register this bootstrap project with the `IServiceCollection.BootstrapZeebe()` extension method.\n\nMore power is provided by `using global::Zeebe.Client.Accelerator.Extensions;` which provides you with further extensions for `IHost`, `IZeebeClient` etc. in\norder to deploy processes or create one time message receivers.\n\n### Bootstrap Zeebe\n\nThe `BootstrapZeebe` method has two parameters:\n\n1. `ZeebeBootstrapOptions` via [configuration, action delegate or both](https://docs.microsoft.com/en-us/dotnet/core/extensions/options-library-authors).\n1. An array with assemblies which will be scanned for job handlers.\n\n```csharp\nConfigureServices((hostContext, services) =\u003e {\n    services.BootstrapZeebe(\n        hostContext.Configuration.GetSection(\"ZeebeConfiguration\"),\n        this.GetType().Assembly\n    );\n})\n```\n\nExample Web Application:\n\n```csharp\n// Start building my WebApplication\nvar builder = WebApplication.CreateBuilder(args);\n\n// Bootstrap Zeebe Integration\nbuilder.Services.BootstrapZeebe(\n    builder.Configuration.GetSection(\"ZeebeConfiguration\"),\n    typeof(Program).Assembly);\n```\n\nThe configuration will e.g. look as follows: \n\n```json\n{\n  \"ZeebeConfiguration\": {\n    \"Client\": {\n      \"GatewayAddress\": \"127.0.0.1:26500\"\n    },\n    \"Worker\": {\n      \"MaxJobsActive\": 5,\n      \"HandlerThreads\": 3,\n      \"TimeoutInMilliseconds\": 500,\n      \"PollIntervalInMilliseconds\": 50,\n      \"PollingTimeoutInMilliseconds\": 1000,\n      \"RetryTimeoutInMilliseconds\": 1000\n    }\n  },\n}\n```\nThe `GatewayAddress` attribute can be set as well via standard environment variable `ZEEBE_ADDRESS` (since 1.0.2).\n\n### Configuring Camunda Platform 8 SaaS Connection\n*Since 1.0.2*\n\nConnections to the Camunda SaaS can be easily configured. Upon creating a new Zeebe API Client in the Cloud Console select the \"Env Vars\" section for your credentials and memorize all `ZEEBE_*` environment variables. You will get something like the following:\n\n```\nexport ZEEBE_ADDRESS='a1b2c3dd-12ab-3c4d-ab1b-ab1c23abcc12.bru-2.zeebe.camunda.io:443'\nexport ZEEBE_CLIENT_ID='ABcDE~a0bCD1eFGH1aEF5G.6HI_abCd0'\nexport ZEEBE_CLIENT_SECRET='ABCDeFgHi1J0KLMnO0PQrOstUVWXyZAbCdeFGh2IjkLmnO-pqrstUVw0xyzab.cd'\nexport ZEEBE_AUTHORIZATION_SERVER_URL='https://login.cloud.camunda.io/oauth/token'\nexport ZEEBE_TOKEN_AUDIENCE='zeebe.camunda.io'\n```\nYou now have 2 options. You can either set exactly these `ZEEBE_*` environment variables and you are done. \nOf course you can alternatively manage these settings in the `appsettings.json` file:\n\n```json\n{\n  \"ZeebeConfiguration\": {\n    \"Client\": {\n      \"GatewayAddress\": \"a1b2c3dd-12ab-3c4d-ab1b-ab1c23abcc12.bru-2.zeebe.camunda.io:443\",\n      \"Cloud\": {\n        \"ClientId\": \"ABcDE~a0bCD1eFGH1aEF5G.6HI_abCd0\",\n        \"ClientSecret\": \"ABCDeFgHi1J0KLMnO0PQrOstUVWXyZAbCdeFGh2IjkLmnO-pqrstUVw0xyzab.cd\",\n        \"AuthorizationServerUrl\": \"https://login.cloud.camunda.io/oauth/token\",\n        \"TokenAudience\": \"zeebe.camunda.io\"\n      }\n    }\n```\nFurther rules:\n- Environment variables have precedence over `appsettings.json`. \n- `AutorizationServerUrl` and `TokenAudience` have the shown values as default values. Thus they are optional settings.\n\n#### Troubleshouting\n\nIf you get DNS errors from the gRPC layer (e.g. \"DNS resolution failed for service\"), you might need to set the following environment variable:\n\n```\nexport GRPC_DNS_RESOLVER=native\n```\n\nFurther documentation is available under [gRPC environment variables](https://chromium.googlesource.com/external/github.com/grpc/grpc/+/HEAD/doc/environment_variables.md).\n\n### Other Transport layer options\n\nThe implementation is based on the [Zeebe C# Client](https://github.com/camunda-community-hub/zeebe-client-csharp) and therefore has some more options available:\n\n```\n{\n  \"ZeebeConfiguration\": {\n    \"Client\": {\n      \"GatewayAddress\": \"my-zeebe-gateway:26500\",\n      \"KeepAliveInMilliSeconds\": ...\n      \"TransportEncryption\": {\n        \"RootCertificatePath\": \"...\",\n        \"AccessToken\": \"...\"\n      }\n```\nTransport encryption settings can as well be provided using environment variables `ZEEBE_ROOT_CERTIFICATE_PATH`, `ZEEBE_ACCESS_TOKEN`.\n\n### Providing your own AccessTokenSupplier\n\n*Since 2.1.8*\n\nYou are able to provide your own `IAccessTokenSupplier` implementation - e.g. using [Duende.AccessTokenManagement](https://github.com/DuendeSoftware/Duende.AccessTokenManagement) - simply by registering your implementation in DI before bootstrapping this extension:\n\n```csharp\n// Register custom AccessTokenSupplier\nbuilder.Services.AddSingleton\u003cIAccessTokenSupplier, MyCustomTokenSupplier\u003e();\n\n// Bootstrap Zeebe Integration\nbuilder.Services.BootstrapZeebe(\n    builder.Configuration.GetSection(\"ZeebeConfiguration\"),\n    typeof(Program).Assembly);\n```\n\nFor more detailed info on this topic see the following [zeebe-client-csharp/discussions](https://github.com/camunda-community-hub/zeebe-client-csharp/discussions/666)\n\n### Deploy Processes\n\nIf we want to deploy some processes right before the final startup of our application we create a deployment using the extension for `IHost` or `IServiceProvider` as follows:\n\n```csharp\nvar app = builder.Build();\n...\n// Deploy all process resources\napp.CreateZeebeDeployment()\n    .UsingDirectory(\"Resources\")\n    .AddResource(\"insurance_application.bpmn\")\n    .AddResource(\"document_request.bpmn\")\n    .AddResource(\"risk_check.dmn\")\n    .Deploy();\n\n// Now run the application\napp.Run();\n```\n\nThe alternative `DeployAndContinueWith(...)` method offers the ability to register callbacks that are executed after successful deployment.\n\n### Zeebe Workers\n\nA Zeebe Worker is an implementation of `IZeebeWorker`, `IAsyncZeebeWorker`, `IZeebeWorkerWithResult` or `IAsyncZeebeWorkerWithResult`. Zeebe Workers are automatically added to the DI container, therefore you can use dependency injection inside.  The default worker configuration can be overwritten with `AbstractWorkerAttribute` implementations, see [attributes] for more information.\n\n```csharp\n[JobType(\"doSomeWork\")]\npublic class SomeWorker : IAsyncZeebeWorker\n{\n    private readonly MyApiService _myApiService;\n\n    public SimpleJobHandler(MyApiService myApiService)\n    {\n        _myApiService = myApiService;\n    }\n\n    /// \u003csummary\u003e\n    /// Handles the job \"doSomeWork\".\n    /// \u003c/summary\u003e\n    /// \u003cparam name=\"job\"\u003ethe Zeebe job\u003c/param\u003e\n    /// \u003cparam name=\"cancellationToken\"\u003ecancellation token\u003c/param\u003e\n    public async Task HandleJob(ZeebeJob job, CancellationToken cancellationToken)\n    {  \n        // execute business service etc.\n        await _myApiService.DoSomethingAsync(cancellationToken);\n    }\n}\n```\n\nOf course you are able to access process variables and return a result. E.g.:\n\n```csharp\n[JobType(\"doAwesomeWork\")]\npublic class AwesomeWorker : IAsyncZeebeWorker\u003cSimpleJobPayload, SimpleResponse\u003e\n{\n    ...\n\n    public async Task\u003cSimpleResponse\u003e HandleJob(ZeebeJob\u003cSimpleJobPayload\u003e job, CancellationToken cancellationToken)\n    {  \n        // get variables as declared (SimpleJobPayload)\n        var variables = job.getVariables();\n\n        // execute business service etc.\n        var result = await _myApiService.DoSomethingAsync(variables.CustomerNo, cancellationToken);\n        return new SimpleResponse(result);\n    }\n\n    class SimpleJobPayload\n    {\n        public string CustomerNo { get; set; }\n    }\n}\n```\nThe above code will fetch exactly the variables defined as attributes in `SimpleJobPaylad` from the process.\n\nAnd there are more options, including the option to access custom headers configured in the process model:\n\n```csharp\n[JobType(\"doComplexWork\")]\npublic class ComplexWorker : IAsyncZeebeWorker\n{\n    ...\n\n    public async Task HandleJob(ZeebeJob job, CancellationToken cancellationToken)\n    {  \n        // get all variables (and deserialize to a given type)\n        ProcessVariables variables = job.getVariables\u003cProcessVariables\u003e();\n        // get custom headers (and deserialize to a given type)\n        MyCustomHeaders headers = job.getCustomHeaders\u003cMyCustomHeaders\u003e();\n\n        // execute business service etc.\n        await _myApiService.DoSomethingComplex(variables.Customer, headers.SomeConfiguration, cancellationToken);\n        ...\n    }\n\n    class ProcessVariables\n    {\n        public string? BusinessKey { get; set; }\n\n        public CustomerData Customer { get; set; }\n\n        public string? AccountName { get; set; }\n\n        ...\n    }\n\n    class MyCustomHeaders\n    {\n        public string SomeConfiguration { get; set; }\n    }\n}\n```\n\nThe following table gives you an overview of the available options:\n\n| **Interface**                            | **Description**                                                    | **Fetched Variables**                                                                       |\n|------------------------------------------|--------------------------------------------------------------------|---------------------------------------------------------------------------------------------|\n| `IAsyncZeebeWorker`                      | Asynchronous worker without specific input and no response         | Default is to fetch all process variables.  Use `FetchVariables` attribute for restictions. |\n| `IAsyncZeebeWorker\u003cTInput\u003e`              | Asynchronous worker with specific input and no response            | Fetches exactly the variables defined as attributes in `TInput`.                            |\n| `IAsyncZeebeWorker\u003cTInput, TResponse\u003e`   | Asynchronous worker with specific input and specific response      | Fetches exactly the variables defined as attributes in `TInput`.                            |\n| `IAsyncZeebeWorkerWithResult\u003cTResponse\u003e` | Asynchronous worker without specific input but a specific response | Default is to fetch all process variables. Use `FetchVariables` attribute for restrictions. |\n| `IZeebeWorker`                           | Synchronous worker without specific input and no response          | Default is to fetch all process variables.  Use `FetchVariables` attribute for restictions. |\n| `IZeebeWorker\u003cTInput\u003e`                   | Synchronous worker with specific input and no response             | Fetches exactly the variables defined as attributes in `TInput`.                            |\n| `IZeebeWorker\u003cTInput, TResponse\u003e`        | Synchronous worker with specific input and specific response       | Fetches exactly the variables defined as attributes in `TInput`.                            |\n| `IZeebeWorkerWithResult\u003cTResponse\u003e`      | Synchronous worker without specific input but a specific response  | Default is to fetch all process variables. Use `FetchVariables` attribute for restrictions. |\n\nIf you like to explicitely restrict the variables fetched from Zeebe, you have the following additional option:\n\n```csharp\n[JobType(\"doComplexWork\")]\n[FetchVariables(\"businessKey\", \"applicantName\")]\npublic class SimpleWorker : IAsyncZeebeWorker\n{\n   ...\n}\n```\n\nIn case you do not want to fetch any variables at all from Zeebe, use `[FetchVariables(none: true)]`:\n\n```csharp\n[JobType(\"doSimpleWork\")]\n[FetchVariables(none: true)]\nclass SimpleWorker : IZeebeWorker\n{\n   ...\n}\n```\n\nA handled job has three outcomes:\n\n1. The job has been handled without exceptions: this will automaticly result in a `JobCompletedCommand` beeing send to the broker. The optional `TResponse` is automaticly serialized and added to the `JobCompletedCommand`.\n1. A `BpmnErrorException` has been thrown while handling the job: this will automaticly result in a `ThrowErrorCommand` beeing send to the broker triggering Error Boundary Events in the process.\n1. Any other unexpected exception will automatically result in a `FailCommand` beeing send to the broker including message details and reducing the number of retries;\n\n### Custom attribute naming\n*Since 1.1.0*\n\nThis extension uses CamelCase as default naming policy. In order to customize serialization and deserialization the standard `JsonPropertyName`and `JsonIgnore` attributes are fully supported:\n\n```csharp\npublic class MyJobVariables\n{\n    [JsonPropertyName(\"MY_AmountName\")]\n    public long Amount { get; set; }\n\n    [JsonIgnore]\n    public string ToBeIgnored { get; set; }\n}\n```\n\n### Manual job completion\n*Since 2.1.0*\n\nFor use cases where autocompletion is not to be used, the `[AutoComplete(false)]` attribute is at your disposal:\n\n```csharp\n[AutoComplete(false)]\npublic class ManualJobHandler : IAsyncZeebeWorker\n{\n    public async Task HandleJob(ZeebeJob job, CancellationToken cancellationToken)\n    {\n        // do something ...\n\n        // complete job manually\n        await job.GetClient().NewCompleteJobCommand(job.Key).Send(token: cancellationToken);\n    }\n}\n```\n\nPlease be aware, that uncatched exceptions still lead to sending fail commands (or error commands in case of `BpmnErrorException`).\nIt's the responsibility of the worker implementation to catch and handle all exceptions if a different behaviour is intended.\n\n### Multi-tenancy\n*Since 2.1.12*\n\nMulti-tenancy in the context of Camunda 8 refers to the ability of Camunda 8 to serve multiple distinct tenants or clients within a single installation.\nHence you can configure a job worker to pick up jobs belonging to one or more tenants:\n\n```csharp\n[TenantIds(\"myTenant\", \"myOtherTenant\")]\npublic class TenantSpecificJobHandler : IAsyncZeebeWorker\n{\n   ...\n}\n```\n\nAlternatively you can set default tenants using the `TenantIds` attribute in the `Worker` section of your *ZeebeConfiguration*.\n\n### Dynamic message receiver\n\nSee [Example for synchronous responses from processes](https://github.com/camunda-community-hub/camunda-8-examples/tree/main/synchronous-response-springboot) for a description of the scenario.\n\nYou can create a one time job handler for receiving a message for a dynamic job type `\"received_\" + number` as follows:\n\n```csharp\ntry\n{\n    string jsonContent = _zeebeClient.ReceiveMessage(\"received_\" + number, TimeSpan.FromSeconds(5), \"someVariable1\", \"someVariable2\");\n    ...\n} catch (MessageTimeoutException)\n{\n    // nothing received\n    ...\n}\n```\nOf course it is possible to use a typed response, which will automatically fetch and deserialize all variables defined as attributes in the given type:\n\n```csharp\nMyVariables typedContent = _zeebeClient.ReceiveMessage\u003cMyVariables\u003e(\"received_\" + number, TimeSpan.FromSeconds(3));\n```\n\n\nSimply waiting without receiving any variables:\n\n```csharp\nbool messageReceived = _zeebeClient.ReceiveMessage(\"received_\" + number, TimeSpan.FromSeconds(3));\n```\n\nThe one time job handler will be destroyed after `ReceiveMessage` returns.\n\n## Connector Secrets\n\n*Since 2.2.0*\n\nThe Connector Secrets functionality provides a secure way to handle sensitive information in your Zeebe workers by replacing secret placeholders with actual values from various secret providers.\nMore info in the official documentation of the feature : https://docs.camunda.io/docs/components/connectors/use-connectors/#using-secrets.\nThe out-of-the-box included providers are Environment Variables and Azure Key Vault, with possibility to add additional custom providers.\n\n### Overview\n\nConnector Secrets allows you to use placeholder patterns in your process variables, configuration strings, or any text that will be processed by your workers. These placeholders are automatically replaced with actual secret values at runtime.\n\n**Supported Secret Patterns:**\n\n- `{{ secrets.mySecretKey }}` - Bracketed pattern\n\n### Quick Start\n\nTo enable Connector Secrets, register the functionality during service configuration:\n\n```csharp\nvar builder = WebApplication.CreateBuilder(args);\n\n// Bootstrap Zeebe Integration with Connector Secrets\nbuilder.Services.BootstrapZeebe(\n    builder.Configuration.GetSection(\"ZeebeConfiguration\"),\n    typeof(Program).Assembly);\n\n// Register secret providers\nbuilder.Services.AddEnvironmentSecretProvider(\n    builder.Configuration.GetSection(\"ZeebeConfiguration\"));\n\nservices.AddAzureKeyVaultSecretProvider(\n    builder.Configuration.GetSection(\"ZeebeConfiguration\"));\n\n```\n\n### Configuration\n\nAdd the Connector Secrets configuration to your `appsettings.json`.\nYou can register multiple secret providers. The system will try each provider in order until a secret is found (in this case using both Environment Variables and Azure Key Vault):\n\n```json\n{\n  \"ZeebeConfiguration\": {\n    \"Client\": {\n      \"GatewayAddress\": \"127.0.0.1:26500\"\n    },\n    \"ConnectorSecrets\": {\n      \"Providers\": [\"EnvironmentVariablesSecretProvider\", \"AzureKeyVaultSecretProvider\"], //Evaluation order of providers\n      \"EnvironmentVariables\": {\n        \"Prefix\": \"MY_APP_\"\n      },\n      \"AzureKeyVault\": {\n        \"VaultUri\": \"https://your-keyvault.vault.azure.net/\"\n      }\n    }\n  }\n}\n```\n\n### Secret Providers\n\n#### Environment Variables Provider\n\nThe Environment Variables provider retrieves secrets from environment variables.\n\n**Registration:**\n```csharp\nbuilder.Services.AddEnvironmentSecretProvider(\n    builder.Configuration.GetSection(\"ZeebeConfiguration\"));\n```\n\n**Configuration:**\n```json\n{\n  \"ZeebeConfiguration\": {\n    \"ConnectorSecrets\": {\n      \"Providers\": [\"EnvironmentVariablesSecretProvider\"],\n      \"EnvironmentVariables\": {\n        \"Prefix\": \"MY_APP_\"\n      }\n    }\n  }\n}\n```\n\n**Example:**\n- Secret placeholder: `{{secrets.DATABASE_PASSWORD}}`\n- Environment variable: `MY_APP_DATABASE_PASSWORD`\n- The provider will look for `{Prefix}DATABASE_PASSWORD`\n\n#### Azure Key Vault Provider\n\nThe Azure Key Vault provider retrieves secrets from Azure Key Vault.\n\n**Registration:**\n```csharp\nbuilder.Services.AddAzureKeyVaultSecretProvider(\n    builder.Configuration.GetSection(\"ZeebeConfiguration\"));\n```\n\n**Configuration:**\n```json\n{\n  \"ZeebeConfiguration\": {\n    \"ConnectorSecrets\": {\n      \"Providers\": [\"AzureKeyVaultSecretProvider\"],\n      \"AzureKeyVault\": {\n        \"VaultUri\": \"https://your-keyvault.vault.azure.net/\"\n      }\n    }\n  }\n}\n```\n\n**Prerequisites:**\n- Ensure your application has proper authentication configured for Azure Key Vault\n- Use Azure.Identity for authentication (DefaultAzureCredential, ManagedIdentity, etc.)\n\n#### Custom Secret Provider\n\nYou can implement your own secret provider by implementing the `ISecretProvider` interface:\n\n```csharp\npublic class CustomSecretProvider : ISecretProvider\n{\n    public async Task\u003cstring\u003e GetSecretAsync(string key)\n    {\n        // Your custom logic to retrieve secrets\n        // Return null if the secret is not found\n        return await MyCustomSecretStore.GetSecretAsync(key);\n    }\n}\n\n// Register your custom provider\nbuilder.Services.AddSecretProvider\u003cCustomSecretProvider\u003e(\n    builder.Configuration.GetSection(\"ZeebeConfiguration\"),\n    (secretsSection, services) =\u003e {\n        // Configure any dependencies for your provider\n        services.Configure\u003cMyCustomProviderOptions\u003e(\n            secretsSection.GetSection(\"MyCustomProvider\"));\n        return services;\n    });\n```\n\n### Error Handling\n\nWhen a secret placeholder cannot be resolved:\n\n1. **Missing Secret**: If a secret is not found in any provider, a `ConnectorInputException` is thrown\n2. **Invalid Pattern**: Invalid secret patterns are left unchanged\n3. **Provider Errors**: Provider-specific errors are logged and the next provider is tried\n\n## Hints\n\n1. By default the workers are added to de DI container with a `Transient` service lifetime. This can be overriden by adding the `ServiceLifetimeAttribute` to the worker, see [attributes] for more information.\n1. By default the `ZeebeVariablesSerializer` is registered as the implementation for `IZeebeVariablesSerializer` which uses `System.Text.Json.JsonSerializer`. Serialization / Deserialization always uses CamelCase as naming policy! `JsonPropertyName` and `JsonIgnore` attributes are supported, so that you still have the option to customize your attribute naming.\n1. The default job type of a worker is the class name of the worker. This can be overriden by adding the `JobTypeAttribute` to the worker, e.g. `[JobType(\"myJobName\")]`.\n\n## How to build\n\nRun `dotnet build Zeebe.Client.Accelerator.sln`\n\n## How to test\n\nRun `dotnet test Zeebe.Client.Accelerator.sln`\n\n[examples]:  https://github.com/VonDerBeck/zeebe-client-csharp-accelerator/tree/main/examples\n[attributes]: https://github.com/VonDerBeck/zeebe-client-csharp-accelerator/tree/main/src/Zeebe.Client.Accelerator/Attributes\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcamunda-community-hub%2Fzeebe-client-csharp-accelerator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcamunda-community-hub%2Fzeebe-client-csharp-accelerator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcamunda-community-hub%2Fzeebe-client-csharp-accelerator/lists"}