├── .codespellrc
├── .devcontainer
└── devcontainer.json
├── .editorconfig
├── .gitattributes
├── .github
├── FUNDING.yml
├── dependabot.yml
└── workflows
│ ├── build.yml
│ └── codespell.yml
├── .gitignore
├── .vscode
├── extensions.json
├── ltex.dictionary.en-US.txt
└── settings.json
├── Directory.Build.props
├── Directory.Build.targets
├── GitVersion.yml
├── LICENSE
├── README.md
├── Tingle.EventBus.slnx
├── global.json
├── logo.png
├── samples
├── AmazonSqsAndSns
│ ├── AmazonSqsAndSns.csproj
│ ├── DoorOpened.cs
│ ├── DoorOpenedConsumer.cs
│ ├── Program.cs
│ ├── Properties
│ │ └── launchSettings.json
│ ├── PublisherService.cs
│ ├── appsettings.Development.json
│ └── appsettings.json
├── AotSupport
│ ├── AotSupport.csproj
│ ├── Program.cs
│ ├── Properties
│ │ └── launchSettings.json
│ ├── appsettings.Development.json
│ └── appsettings.json
├── AzureIotHub
│ ├── AzureIotEventsConsumer.cs
│ ├── AzureIotHub.csproj
│ ├── MyIotHubEvent.cs
│ ├── Program.cs
│ ├── Properties
│ │ └── launchSettings.json
│ ├── appsettings.Development.json
│ └── appsettings.json
├── AzureManagedIdentity
│ ├── AzureManagedIdentity.csproj
│ ├── Program.cs
│ ├── Properties
│ │ └── launchSettings.json
│ ├── VehicleDoorOpenedEvent.cs
│ ├── VehicleTelemetryEvent.cs
│ ├── VehicleTelemetryEventsConsumer.cs
│ ├── appsettings.Development.json
│ └── appsettings.json
├── ConfigSample
│ ├── ConfigSample.csproj
│ ├── ImageUploaded.cs
│ ├── Program.cs
│ ├── Properties
│ │ └── launchSettings.json
│ ├── VehicleDoorOpenedEvent.cs
│ ├── VehicleTelemetryEventsConsumer.cs
│ ├── VisualsProducerService.cs
│ ├── VisualsUploadedConsumer.cs
│ ├── appsettings.Development.json
│ └── appsettings.json
├── CustomEventConfigurator
│ ├── CustomEventConfigurator.csproj
│ ├── MyConfigurator.cs
│ ├── Program.cs
│ ├── Properties
│ │ └── launchSettings.json
│ ├── SampleConsumer1.cs
│ ├── SampleConsumer2.cs
│ ├── SampleEvent1.cs
│ ├── SampleEvent2.cs
│ ├── appsettings.Development.json
│ └── appsettings.json
├── CustomEventSerializer
│ ├── AzureDevOpsCodePushed.cs
│ ├── AzureDevOpsEventSerializer.cs
│ ├── AzureDevOpsEventsConsumer.cs
│ ├── CustomEventSerializer.csproj
│ ├── Models
│ │ ├── AzureDevOpsEventResource.cs
│ │ ├── AzureDevOpsEventResourceRefUpdate.cs
│ │ ├── AzureDevOpsEventResourceRepository.cs
│ │ └── AzureDevOpsEventResourceRepositoryProject.cs
│ ├── Program.cs
│ ├── Properties
│ │ └── launchSettings.json
│ ├── appsettings.Development.json
│ ├── appsettings.json
│ └── git.push-sample.json
├── Directory.Build.props
├── HealthCheck
│ ├── AzureServiceBusHealthCheck.cs
│ ├── HealthCheck.csproj
│ ├── Program.cs
│ ├── Properties
│ │ └── launchSettings.json
│ ├── VehicleDoorOpenedEvent.cs
│ ├── VehicleTelemetryEvent.cs
│ ├── VehicleTelemetryEventsConsumer.cs
│ ├── appsettings.Development.json
│ └── appsettings.json
├── InMemoryBackgroundProcessing
│ ├── InMemoryBackgroundProcessing.csproj
│ ├── Program.cs
│ ├── Properties
│ │ └── launchSettings.json
│ ├── appsettings.Development.json
│ └── appsettings.json
├── MultiEventsConsumer
│ ├── DoorClosed.cs
│ ├── DoorKind.cs
│ ├── DoorOpened.cs
│ ├── DoorState.cs
│ ├── DummyProducerService.cs
│ ├── MultiEventsConsumer.cs
│ ├── MultiEventsConsumer.csproj
│ ├── Program.cs
│ ├── Properties
│ │ └── launchSettings.json
│ ├── appsettings.Development.json
│ └── appsettings.json
├── MultipleConsumers
│ ├── DoorOpened.cs
│ ├── FirstEventConsumer.cs
│ ├── MultipleConsumers.csproj
│ ├── Program.cs
│ ├── Properties
│ │ └── launchSettings.json
│ ├── PublisherService.cs
│ ├── SecondEventConsumer.cs
│ ├── appsettings.Development.json
│ └── appsettings.json
├── MultipleDifferentTransports
│ ├── MultipleDifferentTransports.csproj
│ ├── Program.cs
│ ├── Properties
│ │ └── launchSettings.json
│ ├── VehicleDoorOpenedEvent.cs
│ ├── VehicleTelemetryEvent.cs
│ ├── VehicleTelemetryEventsConsumer.cs
│ ├── appsettings.Development.json
│ └── appsettings.json
├── MultipleSimilarTransports
│ ├── MultipleSimilarTransports.csproj
│ ├── Program.cs
│ ├── Properties
│ │ └── launchSettings.json
│ ├── appsettings.Development.json
│ └── appsettings.json
├── SimpleConsumer
│ ├── EventCounter.cs
│ ├── Program.cs
│ ├── Properties
│ │ └── launchSettings.json
│ ├── SampleEvent.cs
│ ├── SampleEventConsumer.cs
│ ├── SimpleConsumer.csproj
│ ├── appsettings.Development.json
│ └── appsettings.json
└── SimplePublisher
│ ├── DoorOpened.cs
│ ├── Program.cs
│ ├── Properties
│ └── launchSettings.json
│ ├── PublisherService.cs
│ ├── SimplePublisher.csproj
│ ├── appsettings.Development.json
│ └── appsettings.json
├── shared
└── TrimmingHelper.cs
├── src
├── Directory.Build.props
├── Tingle.EventBus.Serializers.NewtonsoftJson
│ ├── MessageStrings.cs
│ ├── NewtonsoftJsonEventBusBuilderExtensions.cs
│ ├── NewtonsoftJsonSerializer.cs
│ ├── NewtonsoftJsonSerializerConfigureOptions.cs
│ ├── NewtonsoftJsonSerializerOptions.cs
│ └── Tingle.EventBus.Serializers.NewtonsoftJson.csproj
├── Tingle.EventBus.Transports.Amazon.Abstractions
│ ├── AmazonSqsTransportException.cs
│ ├── AmazonTransportConfigureOptions.cs
│ ├── AmazonTransportOptions.cs
│ ├── AmazonWebServiceResponseExtensions.cs
│ └── Tingle.EventBus.Transports.Amazon.Abstractions.csproj
├── Tingle.EventBus.Transports.Amazon.Kinesis
│ ├── AmazonKinesisConfigureOptions.cs
│ ├── AmazonKinesisDefaults.cs
│ ├── AmazonKinesisEventBusBuilderExtensions.cs
│ ├── AmazonKinesisTransport.cs
│ ├── AmazonKinesisTransportOptions.cs
│ ├── BinaryDataExtensions.cs
│ ├── ILoggerExtensions.cs
│ └── Tingle.EventBus.Transports.Amazon.Kinesis.csproj
├── Tingle.EventBus.Transports.Amazon.Sqs
│ ├── AmazonSqsConfigureOptions.cs
│ ├── AmazonSqsDefaults.cs
│ ├── AmazonSqsEventBusBuilderExtensions.cs
│ ├── AmazonSqsTransport.cs
│ ├── AmazonSqsTransportOptions.cs
│ ├── ILoggerExtensions.cs
│ ├── MessageAttributeExtensions.cs
│ └── Tingle.EventBus.Transports.Amazon.Sqs.csproj
├── Tingle.EventBus.Transports.Azure.Abstractions
│ ├── AzureTransportConfigureOptions.cs
│ ├── AzureTransportCredentials.cs
│ ├── AzureTransportOptions.cs
│ └── Tingle.EventBus.Transports.Azure.Abstractions.csproj
├── Tingle.EventBus.Transports.Azure.EventHubs
│ ├── AzureBlobStorageCredentials.cs
│ ├── AzureEventHubsConfigureOptions.cs
│ ├── AzureEventHubsDefaults.cs
│ ├── AzureEventHubsEventBusBuilderExtensions.cs
│ ├── AzureEventHubsEventContextExtensions.cs
│ ├── AzureEventHubsEventRegistrationExtensions.cs
│ ├── AzureEventHubsTransport.cs
│ ├── AzureEventHubsTransportCredentials.cs
│ ├── AzureEventHubsTransportOptions.cs
│ ├── EventDataExtensions.cs
│ ├── ILoggerExtensions.cs
│ ├── IotHub
│ │ ├── IotHubConnectionAuthMethod.cs
│ │ ├── IotHubEvent.cs
│ │ ├── IotHubEventContextExtensions.cs
│ │ ├── IotHubEventDataExtensions.cs
│ │ ├── IotHubEventSerializer.cs
│ │ └── IotHubJsonSerializerContext.cs
│ ├── MessageStrings.cs
│ └── Tingle.EventBus.Transports.Azure.EventHubs.csproj
├── Tingle.EventBus.Transports.Azure.QueueStorage
│ ├── AzureQueueStorageConfigureOptions.cs
│ ├── AzureQueueStorageDefaults.cs
│ ├── AzureQueueStorageEventBusBuilderExtensions.cs
│ ├── AzureQueueStorageSchedulingId.cs
│ ├── AzureQueueStorageTransport.cs
│ ├── AzureQueueStorageTransportCredentials.cs
│ ├── AzureQueueStorageTransportOptions.cs
│ ├── ILoggerExtensions.cs
│ └── Tingle.EventBus.Transports.Azure.QueueStorage.csproj
├── Tingle.EventBus.Transports.Azure.ServiceBus
│ ├── AzureServiceBusConfigureOptions.cs
│ ├── AzureServiceBusDefaults.cs
│ ├── AzureServiceBusEventBusBuilderExtensions.cs
│ ├── AzureServiceBusEventContextExtensions.cs
│ ├── AzureServiceBusTransport.cs
│ ├── AzureServiceBusTransportCredentials.cs
│ ├── AzureServiceBusTransportOptions.cs
│ ├── ILoggerExtensions.cs
│ └── Tingle.EventBus.Transports.Azure.ServiceBus.csproj
├── Tingle.EventBus.Transports.InMemory
│ ├── Client
│ │ ├── BroadcastChannel.cs
│ │ ├── BroadcastChannelWriter.cs
│ │ ├── InMemoryClient.cs
│ │ ├── InMemoryErrorSource.cs
│ │ ├── InMemoryMessage.cs
│ │ ├── InMemoryProcessor.cs
│ │ ├── InMemoryProcessorOptions.cs
│ │ ├── InMemoryReceivedMessage.cs
│ │ ├── InMemorySender.cs
│ │ ├── ProcessErrorEventArgs.cs
│ │ ├── ProcessMessageEventArgs.cs
│ │ └── SequenceNumberGenerator.cs
│ ├── ILoggerExtensions.cs
│ ├── InMemoryDefaults.cs
│ ├── InMemoryEventBusBuilderExtensions.cs
│ ├── InMemoryEventContextExtensions.cs
│ ├── InMemoryTestHarness.cs
│ ├── InMemoryTestHarnessConfigureOptions.cs
│ ├── InMemoryTestHarnessOptions.cs
│ ├── InMemoryTransport.cs
│ ├── InMemoryTransportConfigureOptions.cs
│ ├── InMemoryTransportOptions.cs
│ └── Tingle.EventBus.Transports.InMemory.csproj
├── Tingle.EventBus.Transports.Kafka
│ ├── ILoggerExtensions.cs
│ ├── KafkaConfigureOptions.cs
│ ├── KafkaDefaults.cs
│ ├── KafkaEventBusBuilderExtensions.cs
│ ├── KafkaExtensions.cs
│ ├── KafkaTransport.cs
│ ├── KafkaTransportOptions.cs
│ └── Tingle.EventBus.Transports.Kafka.csproj
├── Tingle.EventBus.Transports.RabbitMQ
│ ├── RabbitMqConfigureOptions.cs
│ ├── RabbitMqDefaults.cs
│ ├── RabbitMqEventBusBuilderExtensions.cs
│ ├── RabbitMqTransport.cs
│ ├── RabbitMqTransportOptions.cs
│ └── Tingle.EventBus.Transports.RabbitMQ.csproj
└── Tingle.EventBus
│ ├── Configuration
│ ├── Attributes
│ │ ├── ConsumerNameAttribute.cs
│ │ ├── EntityKindAttribute.cs
│ │ ├── EventNameAttribute.cs
│ │ ├── EventSerializerAttribute.cs
│ │ └── EventTransportNameAttribute.cs
│ ├── ConsumerNameSource.cs
│ ├── DefaultEventBusConfigurationProvider.cs
│ ├── DefaultEventBusConfigurator.cs
│ ├── EntityKind.cs
│ ├── EventConsumerRegistration.cs
│ ├── EventIdFormat.cs
│ ├── EventRegistration.cs
│ ├── IEventBusConfigurationProvider.cs
│ ├── IEventBusConfigurator.cs
│ ├── MandatoryEventBusConfigurator.cs
│ ├── NamingConvention.cs
│ └── UnhandledConsumerErrorBehaviour.cs
│ ├── DependencyInjection
│ ├── EventBusBuilder.cs
│ ├── EventBusConfigureOptions.cs
│ ├── EventBusNamingOptions.cs
│ ├── EventBusOptions.cs
│ ├── EventBusSerializationOptions.cs
│ ├── EventBusServiceCollectionExtensions.cs
│ └── EventBusTransportRegistrationBuilder.cs
│ ├── Diagnostics
│ ├── ActivityExtensions.cs
│ ├── ActivityNames.cs
│ ├── ActivityTagNames.cs
│ ├── EventBusActivitySource.cs
│ ├── HeaderNames.cs
│ └── LogCategoryNames.cs
│ ├── EventBus.cs
│ ├── EventContext.cs
│ ├── Extensions
│ └── ILoggerExtensions.cs
│ ├── IEventConsumer.cs
│ ├── Ids
│ ├── DefaultEventIdGenerator.cs
│ └── IEventIdGenerator.cs
│ ├── Internal
│ ├── DictionaryExtensions.cs
│ ├── EventBusConcurrentDictionary.cs
│ ├── EventBusDictionaryWrapper.cs
│ ├── EventBusHost.cs
│ ├── ExecutionHelper.cs
│ └── ResiliencePipelineHelper.cs
│ ├── MessageStrings.cs
│ ├── MetadataNames.cs
│ ├── Publisher
│ ├── EventPublisher.cs
│ ├── IEventPublisher.cs
│ ├── IEventPublisherExtensions.cs
│ └── WrappedEventPublisher.cs
│ ├── Retries
│ ├── AbstractRetryableEvent.cs
│ ├── IRetryableEvent.cs
│ └── IRetryableEventExtensions.cs
│ ├── ScheduledResult.cs
│ ├── Serialization
│ ├── AbstractEventSerializer.cs
│ ├── DefaultJsonEventSerializer.cs
│ ├── DeserializationContext.cs
│ ├── EventEnvelope.cs
│ ├── HostInfo.cs
│ ├── IEventEnvelope.cs
│ ├── IEventSerializer.cs
│ ├── SerializationContext.cs
│ └── Xml
│ │ ├── EventBusBuilderExtensions.cs
│ │ ├── XmlEventEnvelope.cs
│ │ ├── XmlEventSerializer.cs
│ │ ├── XmlEventSerializerConfigureOptions.cs
│ │ ├── XmlEventSerializerOptions.cs
│ │ └── XmlHeader.cs
│ ├── Tingle.EventBus.csproj
│ └── Transports
│ ├── EventBusTransport.cs
│ ├── EventBusTransportConfigureOptions.cs
│ ├── EventBusTransportOptions.cs
│ ├── EventBusTransportProvider.cs
│ ├── EventBusTransportRegistration.cs
│ ├── EventConsumeResult.cs
│ └── IEventBusTransport.cs
└── tests
├── Directory.Build.props
├── Tingle.EventBus.Tests
├── Configurator
│ ├── FakeEventSerializer1.cs
│ ├── FakeEventSerializer2.cs
│ ├── MandatoryEventBusConfiguratorTests.cs
│ ├── TestConsumer1.cs
│ ├── TestConsumer2.cs
│ ├── TestEvent1.cs
│ ├── TestEvent2.cs
│ └── TestEvent3.cs
├── DefaultEventIdGeneratorTests.cs
├── EventBusBuilderTests.cs
├── EventBusNamingOptionsTests.cs
├── FakeHostEnvironment.cs
└── Tingle.EventBus.Tests.csproj
├── Tingle.EventBus.Transports.Azure.EventHubs.Tests
├── AzureEventHubsTransportTests.cs
├── IotHubEventSerializerTests.cs
├── Samples
│ ├── iot-hub-Telemetry.json
│ ├── iot-hub-deviceConnectionStateEvents.json
│ ├── iot-hub-deviceLifecycleEvents.json
│ └── iot-hub-twinChangeEvents.json
├── TestSamples.cs
└── Tingle.EventBus.Transports.Azure.EventHubs.Tests.csproj
├── Tingle.EventBus.Transports.Azure.ServiceBus.Tests
├── AzureServiceBusTransportTests.cs
└── Tingle.EventBus.Transports.Azure.ServiceBus.Tests.csproj
├── Tingle.EventBus.Transports.InMemory.Tests
├── SampleEventConsumerTests.cs
├── SequenceNumberGeneratorTests.cs
├── SimpleCancellationTests.cs
├── SimplePublisherTests.cs
└── Tingle.EventBus.Transports.InMemory.Tests.csproj
└── Tingle.EventBus.Transports.Kafka.Tests
├── KafkaTransportTests.cs
└── Tingle.EventBus.Transports.Kafka.Tests.csproj
/.codespellrc:
--------------------------------------------------------------------------------
1 | [codespell]
2 | skip = .git
3 |
--------------------------------------------------------------------------------
/.devcontainer/devcontainer.json:
--------------------------------------------------------------------------------
1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the
2 | // README at: https://github.com/devcontainers/templates/tree/main/src/dotnet
3 | {
4 | "name": "C# (.NET)",
5 | // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
6 | "image": "mcr.microsoft.com/devcontainers/dotnet:8.0"
7 |
8 | // Features to add to the dev container. More info: https://containers.dev/features.
9 | // "features": {},
10 |
11 | // Use 'forwardPorts' to make a list of ports inside the container available locally.
12 | // "forwardPorts": [5000, 5001],
13 | // "portsAttributes": {
14 | // "5001": {
15 | // "protocol": "https"
16 | // }
17 | // }
18 |
19 | // Use 'postCreateCommand' to run commands after the container is created.
20 | // "postCreateCommand": "dotnet restore",
21 |
22 | // Configure tool-specific properties.
23 | // "customizations": {},
24 |
25 | // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
26 | // "remoteUser": "root"
27 | }
28 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # editorconfig.org
2 |
3 | # top-most EditorConfig file
4 | root = true
5 |
6 | # CSharp formatting rules:
7 | [*.cs]
8 | csharp_style_namespace_declarations =file_scoped:warning
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: [mburumaxwell]
4 | patreon: maxwellweru # Replace with a single Patreon username
5 | open_collective: maxwellweru # Replace with a single Open Collective username
6 | ko_fi: # Replace with a single Ko-fi username
7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9 | liberapay: # Replace with a single Liberapay username
10 | issuehunt: # Replace with a single IssueHunt username
11 | otechie: # Replace with a single Otechie username
12 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
13 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
14 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # To get started with Dependabot version updates, you'll need to specify which
2 | # package ecosystems to update and where the package manifests are located.
3 | # Please see the documentation for all configuration options:
4 | # https://docs.github.com/en/code-security/dependabot/working-with-dependabot/dependabot-options-reference
5 |
6 | version: 2
7 | updates:
8 | - package-ecosystem: 'nuget'
9 | directory: '/'
10 | schedule:
11 | interval: 'weekly'
12 | time: '02:00'
13 | open-pull-requests-limit: 10
14 | groups:
15 | aws-sdk:
16 | patterns: ['AWSSDK.*']
17 | azure-sdk:
18 | patterns: ['Azure.*']
19 | microsoft:
20 | patterns: ['Microsoft.*']
21 | system:
22 | patterns: ['System.*']
23 | xunit:
24 | patterns: ['Xunit*']
25 |
26 | - package-ecosystem: 'dotnet-sdk'
27 | directory: '/'
28 | schedule:
29 | interval: 'weekly'
30 | time: '02:00'
31 |
32 | - package-ecosystem: 'github-actions'
33 | directory: '/'
34 | schedule:
35 | interval: 'weekly'
36 | time: '02:00'
37 |
38 | - package-ecosystem: 'devcontainers'
39 | directory: '/'
40 | schedule:
41 | interval: 'weekly'
42 | time: '02:00'
43 |
--------------------------------------------------------------------------------
/.github/workflows/codespell.yml:
--------------------------------------------------------------------------------
1 | name: Codespell
2 |
3 | on:
4 | push:
5 | branches: [main]
6 | pull_request:
7 | branches: [main]
8 |
9 | permissions:
10 | contents: read
11 |
12 | jobs:
13 | codespell:
14 | name: Check for spelling errors
15 | runs-on: ubuntu-latest
16 |
17 | steps:
18 | - name: Checkout
19 | uses: actions/checkout@v4
20 | - name: Codespell
21 | uses: codespell-project/actions-codespell@v2
22 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | // See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations.
3 | // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp
4 |
5 | // List of extensions which should be recommended for users of this workspace.
6 | "recommendations": [
7 | "ms-dotnettools.vscodeintellicode-csharp",
8 | "streetsidesoftware.code-spell-checker",
9 | "ms-azuretools.vscode-docker",
10 | "shardulm94.trailing-spaces",
11 | "redhat.vscode-yaml",
12 | "github.vscode-github-actions"
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/.vscode/ltex.dictionary.en-US.txt:
--------------------------------------------------------------------------------
1 | serializer
2 | EventBus
3 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "cSpell.words": [
3 | "AWSSDK",
4 | "Behaviour",
5 | "checkpointing",
6 | "Configurator",
7 | "configurators",
8 | "Deadletter",
9 | "Deduplication",
10 | "devcontainers",
11 | "Newtonsoft",
12 | "Serializers",
13 | "Xunit"
14 | ]
15 | }
--------------------------------------------------------------------------------
/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | net8.0;net9.0
6 | latest
7 | enable
8 | enable
9 | false
10 |
11 |
12 |
13 | $(WarningsAsErrors),SYSLIB1045
14 | $(WarningsAsErrors),IL2026,IL2060,IL2091,IL2095,IL3050
15 | $(WarningsAsErrors),xUnit1051
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/Directory.Build.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | True
8 | True
9 | Resources.resx
10 |
11 |
12 |
13 | True
14 | ResXFileCodeGenerator
15 | Resources.Designer.cs
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/GitVersion.yml:
--------------------------------------------------------------------------------
1 | # To get the effective configuration run 'gitversion /showconfig'
2 | branches:
3 | pull-request:
4 | label: pr
5 | main:
6 | label: ci
7 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 TINGLE SOFTWARE
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/global.json:
--------------------------------------------------------------------------------
1 | {
2 | "sdk": {
3 | "version": "9.0.300",
4 | "allowPrerelease": false,
5 | "rollForward": "latestMinor"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tinglesoftware/eventbus/cab00baad57a640c807d348d40c4463f3ecff005/logo.png
--------------------------------------------------------------------------------
/samples/AmazonSqsAndSns/AmazonSqsAndSns.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | aedb10fe-1539-4990-8f43-981e8ed03904
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/samples/AmazonSqsAndSns/DoorOpened.cs:
--------------------------------------------------------------------------------
1 | namespace AmazonSqsAndSns;
2 |
3 | public class DoorOpened
4 | {
5 | ///
6 | /// The vehicle who's door was opened.
7 | ///
8 | public string? VehicleId { get; set; }
9 |
10 | ///
11 | /// The kind of door that was opened.
12 | ///
13 | public OpenDoorKind Kind { get; set; }
14 |
15 | ///
16 | /// When the door was opened.
17 | ///
18 | public DateTimeOffset Opened { get; set; }
19 | }
20 |
21 | public enum OpenDoorKind
22 | {
23 | FrontLeft,
24 | FrontRight,
25 | RearLeft,
26 | ReadRight,
27 | Hood,
28 | Trunk,
29 | }
30 |
--------------------------------------------------------------------------------
/samples/AmazonSqsAndSns/DoorOpenedConsumer.cs:
--------------------------------------------------------------------------------
1 | namespace AmazonSqsAndSns;
2 |
3 | public class DoorOpenedConsumer(ILogger logger) : IEventConsumer
4 | {
5 | public Task ConsumeAsync(EventContext context, CancellationToken cancellationToken = default)
6 | {
7 | logger.LogInformation("Received event Id: {Id}", context.Id);
8 | logger.LogInformation("Event body: {EventBody}", System.Text.Json.JsonSerializer.Serialize(context.Event));
9 | return Task.CompletedTask;
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/samples/AmazonSqsAndSns/Program.cs:
--------------------------------------------------------------------------------
1 | using AmazonSqsAndSns;
2 |
3 | var host = Host.CreateDefaultBuilder(args)
4 | .ConfigureServices((hostContext, services) =>
5 | {
6 | services.AddEventBus(builder =>
7 | {
8 | builder.AddConsumer();
9 |
10 | // Transport specific configuration
11 | builder.AddAmazonSqsTransport(options =>
12 | {
13 | options.RegionName = "eu-west-1";
14 | options.AccessKey = "my-access-key";
15 | options.SecretKey = "my-secret-key";
16 | });
17 | });
18 |
19 | services.AddHostedService();
20 | })
21 | .Build();
22 |
23 | await host.RunAsync();
24 |
--------------------------------------------------------------------------------
/samples/AmazonSqsAndSns/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "AmazonSqsAndSns": {
4 | "commandName": "Project",
5 | "dotnetRunMessages": true,
6 | "environmentVariables": {
7 | "DOTNET_ENVIRONMENT": "Development"
8 | }
9 | }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/samples/AmazonSqsAndSns/PublisherService.cs:
--------------------------------------------------------------------------------
1 | namespace AmazonSqsAndSns;
2 |
3 | public class PublisherService(IEventPublisher publisher) : BackgroundService
4 | {
5 | protected override async Task ExecuteAsync(CancellationToken stoppingToken)
6 | {
7 | var delay = TimeSpan.FromSeconds(30);
8 | var times = 5;
9 |
10 | var rnd = new Random(DateTimeOffset.UtcNow.Millisecond);
11 |
12 | for (var i = 0; i < times; i++)
13 | {
14 | var evt = new DoorOpened
15 | {
16 | Kind = (OpenDoorKind)rnd.Next(0, 5),
17 | Opened = DateTimeOffset.UtcNow.AddMinutes(rnd.Next(-10, 10)),
18 | VehicleId = "123456",
19 | };
20 |
21 | await publisher.PublishAsync(evt, cancellationToken: stoppingToken);
22 |
23 | await Task.Delay(delay, stoppingToken);
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/samples/AmazonSqsAndSns/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Debug",
5 | "Microsoft": "Information",
6 | "System": "Information"
7 | },
8 | "Console": {
9 | "FormatterName": "simple",
10 | "FormatterOptions": {
11 | "SingleLine": true,
12 | "TimestampFormat": "HH:mm:ss "
13 | }
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/samples/AmazonSqsAndSns/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/samples/AotSupport/AotSupport.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | true
5 | true
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/samples/AotSupport/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "AotSupport": {
4 | "commandName": "Project",
5 | "environmentVariables": {
6 | "DOTNET_ENVIRONMENT": "Development"
7 | }
8 | }
9 | }
10 | }
--------------------------------------------------------------------------------
/samples/AotSupport/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Debug",
5 | "Microsoft": "Information",
6 | "System": "Information"
7 | },
8 | "Console": {
9 | "FormatterName": "simple",
10 | "FormatterOptions": {
11 | "SingleLine": true,
12 | "TimestampFormat": "HH:mm:ss "
13 | }
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/samples/AotSupport/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/samples/AzureIotHub/AzureIotHub.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 710bcdca-052b-456d-be46-4efede662bb2
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/samples/AzureIotHub/MyIotHubEvent.cs:
--------------------------------------------------------------------------------
1 | using System.Text.Json.Serialization;
2 | using Tingle.EventBus.Transports.Azure.EventHubs.IotHub;
3 |
4 | namespace AzureIotHub;
5 |
6 | public record MyIotHubEvent : IotHubEvent { }
7 |
8 | public class MyIotHubTelemetry
9 | {
10 | public DateTimeOffset Timestamp { get; set; }
11 |
12 | [JsonExtensionData]
13 | public Dictionary? Extras { get; set; }
14 | }
15 |
--------------------------------------------------------------------------------
/samples/AzureIotHub/Program.cs:
--------------------------------------------------------------------------------
1 | using AzureIotHub;
2 | using Tingle.EventBus.Configuration;
3 |
4 | var host = Host.CreateDefaultBuilder(args)
5 | .ConfigureServices((hostContext, services) =>
6 | {
7 | var configuration = hostContext.Configuration;
8 |
9 | services.AddEventBus(builder =>
10 | {
11 | builder.Configure(o => o.ConfigureEvent(reg =>
12 | {
13 | reg.ConfigureAsIotHubEvent(configuration["IotHubEventHubName"]!)
14 | .UseIotHubEventSerializer();
15 | }));
16 |
17 | builder.AddConsumer();
18 |
19 | // Transport specific configuration
20 | builder.AddAzureEventHubsTransport(options =>
21 | {
22 | options.Credentials = configuration.GetConnectionString("EventHub")!;
23 | options.BlobStorageCredentials = configuration.GetConnectionString("AzureStorage")!;
24 | });
25 | });
26 | })
27 | .Build();
28 |
29 | await host.RunAsync();
30 |
--------------------------------------------------------------------------------
/samples/AzureIotHub/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "AzureIotHub": {
4 | "commandName": "Project",
5 | "environmentVariables": {
6 | "DOTNET_ENVIRONMENT": "Development"
7 | }
8 | }
9 | }
10 | }
--------------------------------------------------------------------------------
/samples/AzureIotHub/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Debug",
5 | "Microsoft": "Information",
6 | "System": "Information"
7 | },
8 | "Console": {
9 | "FormatterName": "simple",
10 | "FormatterOptions": {
11 | "SingleLine": true,
12 | "TimestampFormat": "HH:mm:ss "
13 | }
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/samples/AzureIotHub/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | },
9 |
10 | "ConnectionStrings:AzureStorage": "UseDevelopmentStorage=true;",
11 | "ConnectionStrings:EventHub": "Endpoint=sb://abcd.servicebus.windows.net/;SharedAccessKeyName=xyz;SharedAccessKey=AAAAAAAAAAAAAAAAAAAAAA==",
12 | "IotHubEventHubName": "iothub-ehub-test-dev-0000000-0aaaa000aa"
13 | }
14 |
--------------------------------------------------------------------------------
/samples/AzureManagedIdentity/AzureManagedIdentity.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/samples/AzureManagedIdentity/Program.cs:
--------------------------------------------------------------------------------
1 | using Azure.Identity;
2 | using AzureManagedIdentity;
3 | using Tingle.EventBus.Configuration;
4 |
5 | var host = Host.CreateDefaultBuilder(args)
6 | .ConfigureServices((hostContext, services) =>
7 | {
8 | var configuration = hostContext.Configuration;
9 |
10 | services.AddEventBus(builder =>
11 | {
12 | builder.AddConsumer();
13 |
14 | var credential = new DefaultAzureCredential();
15 |
16 | // Transport specific configuration
17 | builder.AddAzureServiceBusTransport(options =>
18 | {
19 | options.Credentials = new AzureServiceBusTransportCredentials
20 | {
21 | TokenCredential = credential,
22 | FullyQualifiedNamespace = "{your_namespace}.servicebus.windows.net"
23 | };
24 | options.DefaultEntityKind = EntityKind.Queue; // required if using the basic SKU (does not support topics)
25 | });
26 | });
27 | })
28 | .Build();
29 |
30 | await host.RunAsync();
31 |
--------------------------------------------------------------------------------
/samples/AzureManagedIdentity/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "AzureManagedIdentity": {
4 | "commandName": "Project",
5 | "dotnetRunMessages": true,
6 | "environmentVariables": {
7 | "DOTNET_ENVIRONMENT": "Development"
8 | }
9 | }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/samples/AzureManagedIdentity/VehicleDoorOpenedEvent.cs:
--------------------------------------------------------------------------------
1 | namespace AzureManagedIdentity;
2 |
3 | public class VehicleDoorOpenedEvent
4 | {
5 | public string? VehicleId { get; set; }
6 | public VehicleDoorKind Kind { get; set; }
7 | public DateTimeOffset? Opened { get; set; }
8 | public DateTimeOffset? Closed { get; set; }
9 | }
10 |
--------------------------------------------------------------------------------
/samples/AzureManagedIdentity/VehicleTelemetryEvent.cs:
--------------------------------------------------------------------------------
1 | using System.Text.Json.Serialization;
2 |
3 | namespace AzureManagedIdentity;
4 |
5 | internal class VehicleTelemetryEvent
6 | {
7 | public string? DeviceId { get; set; }
8 |
9 | public DateTimeOffset Timestamp { get; set; }
10 |
11 | public string? Action { get; set; }
12 |
13 | public VehicleDoorKind? VehicleDoorKind { get; set; }
14 | public VehicleDoorStatus? VehicleDoorStatus { get; set; }
15 |
16 | [JsonExtensionData]
17 | public Dictionary? Extras { get; set; }
18 | }
19 |
20 | public enum VehicleDoorStatus
21 | {
22 | Unknown,
23 | Open,
24 | Closed,
25 | }
26 |
27 | public enum VehicleDoorKind
28 | {
29 | FrontLeft,
30 | FrontRight,
31 | RearLeft,
32 | ReadRight,
33 | Hood,
34 | Trunk,
35 | }
36 |
--------------------------------------------------------------------------------
/samples/AzureManagedIdentity/VehicleTelemetryEventsConsumer.cs:
--------------------------------------------------------------------------------
1 | namespace AzureManagedIdentity;
2 |
3 | internal class VehicleTelemetryEventsConsumer(ILogger logger) : IEventConsumer
4 | {
5 | public async Task ConsumeAsync(EventContext context, CancellationToken cancellationToken)
6 | {
7 | var telemetry = context.Event;
8 |
9 | var status = telemetry.VehicleDoorStatus;
10 | if (status is not VehicleDoorStatus.Open and not VehicleDoorStatus.Closed)
11 | {
12 | logger.LogWarning("Vehicle Door status '{VehicleDoorStatus}' is not yet supported", status);
13 | return;
14 | }
15 |
16 | var kind = telemetry.VehicleDoorKind;
17 | if (kind is null)
18 | {
19 | logger.LogWarning("Vehicle Door kind '{VehicleDoorKind}' cannot be null", kind);
20 | return;
21 | }
22 |
23 | var timestamp = telemetry.Timestamp;
24 | var updateEvt = new VehicleDoorOpenedEvent
25 | {
26 | VehicleId = telemetry.DeviceId,
27 | Kind = kind.Value,
28 | Closed = status is VehicleDoorStatus.Closed ? timestamp : null,
29 | Opened = status is VehicleDoorStatus.Open ? timestamp : null,
30 | };
31 |
32 | // the VehicleDoorOpenedEvent on a broadcast bus would notify all subscribers
33 | await context.PublishAsync(updateEvt, cancellationToken: cancellationToken);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/samples/AzureManagedIdentity/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Debug",
5 | "Microsoft": "Information",
6 | "System": "Information"
7 | },
8 | "Console": {
9 | "FormatterName": "simple",
10 | "FormatterOptions": {
11 | "SingleLine": true,
12 | "TimestampFormat": "HH:mm:ss "
13 | }
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/samples/AzureManagedIdentity/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/samples/ConfigSample/ConfigSample.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | fdb14b87-4a29-455c-9912-67a1e0c64081
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/samples/ConfigSample/ImageUploaded.cs:
--------------------------------------------------------------------------------
1 | namespace ConfigSample;
2 |
3 | internal class ImageUploaded
4 | {
5 | public string? ImageId { get; set; }
6 | public string? Url { get; set; }
7 | public long SizeBytes { get; set; }
8 | }
9 |
10 | internal class VideoUploaded
11 | {
12 | public string? VideoId { get; set; }
13 | public string? Url { get; set; }
14 | public long SizeBytes { get; set; }
15 | }
16 |
--------------------------------------------------------------------------------
/samples/ConfigSample/Program.cs:
--------------------------------------------------------------------------------
1 | using Azure.Identity;
2 | using ConfigSample;
3 | using Tingle.EventBus.Transports.Azure.ServiceBus;
4 |
5 | var host = Host.CreateDefaultBuilder(args)
6 | .ConfigureServices((hostContext, services) =>
7 | {
8 | var configuration = hostContext.Configuration;
9 |
10 | services.AddEventBus(builder =>
11 | {
12 | builder.AddConsumer();
13 | builder.AddConsumer();
14 |
15 | // Add transports
16 | builder.AddAzureServiceBusTransport();
17 | builder.AddInMemoryTransport("in-memory-images");
18 | builder.AddInMemoryTransport("in-memory-videos");
19 |
20 | // Transport specific configuration
21 | var credential = new DefaultAzureCredential();
22 | builder.Services.PostConfigure(
23 | name: AzureServiceBusDefaults.Name,
24 | configureOptions: o => ((AzureServiceBusTransportCredentials)o.Credentials).TokenCredential = credential);
25 | });
26 |
27 | services.AddHostedService();
28 | })
29 | .Build();
30 |
31 | await host.RunAsync();
32 |
--------------------------------------------------------------------------------
/samples/ConfigSample/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "ConfigSample": {
4 | "commandName": "Project",
5 | "dotnetRunMessages": true,
6 | "environmentVariables": {
7 | "DOTNET_ENVIRONMENT": "Development"
8 | }
9 | }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/samples/ConfigSample/VehicleDoorOpenedEvent.cs:
--------------------------------------------------------------------------------
1 | using System.Text.Json.Serialization;
2 |
3 | namespace ConfigSample;
4 |
5 | internal class VehicleDoorOpenedEvent
6 | {
7 | public string? VehicleId { get; set; }
8 | public VehicleDoorKind Kind { get; set; }
9 | public DateTimeOffset? Opened { get; set; }
10 | public DateTimeOffset? Closed { get; set; }
11 | }
12 |
13 | internal class VehicleTelemetryEvent
14 | {
15 | public string? DeviceId { get; set; }
16 | public DateTimeOffset Timestamp { get; set; }
17 | public string? Action { get; set; }
18 | public VehicleDoorKind? VehicleDoorKind { get; set; }
19 | public VehicleDoorStatus? VehicleDoorStatus { get; set; }
20 | [JsonExtensionData]
21 | public Dictionary? Extras { get; set; }
22 | }
23 |
24 | internal enum VehicleDoorStatus { Unknown, Open, Closed, }
25 | internal enum VehicleDoorKind { FrontLeft, FrontRight, RearLeft, ReadRight, Hood, Trunk, }
26 |
--------------------------------------------------------------------------------
/samples/ConfigSample/VehicleTelemetryEventsConsumer.cs:
--------------------------------------------------------------------------------
1 | namespace ConfigSample;
2 |
3 | internal class VehicleTelemetryEventsConsumer(ILogger logger) : IEventConsumer
4 | {
5 | public async Task ConsumeAsync(EventContext context, CancellationToken cancellationToken)
6 | {
7 | var telemetry = context.Event;
8 |
9 | var status = telemetry.VehicleDoorStatus;
10 | if (status is not VehicleDoorStatus.Open and not VehicleDoorStatus.Closed)
11 | {
12 | logger.LogWarning("Vehicle Door status '{VehicleDoorStatus}' is not yet supported", status);
13 | return;
14 | }
15 |
16 | var kind = telemetry.VehicleDoorKind;
17 | if (kind is null)
18 | {
19 | logger.LogWarning("Vehicle Door kind '{VehicleDoorKind}' cannot be null", kind);
20 | return;
21 | }
22 |
23 | var timestamp = telemetry.Timestamp;
24 | var updateEvt = new VehicleDoorOpenedEvent
25 | {
26 | VehicleId = telemetry.DeviceId,
27 | Kind = kind.Value,
28 | Closed = status is VehicleDoorStatus.Closed ? timestamp : null,
29 | Opened = status is VehicleDoorStatus.Open ? timestamp : null,
30 | };
31 |
32 | // the VehicleDoorOpenedEvent on a broadcast bus would notify all subscribers
33 | await context.PublishAsync(updateEvt, cancellationToken: cancellationToken);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/samples/ConfigSample/VisualsProducerService.cs:
--------------------------------------------------------------------------------
1 | namespace ConfigSample;
2 |
3 | internal class VisualsProducerService(IEventPublisher publisher, ILogger logger) : BackgroundService
4 | {
5 | protected override async Task ExecuteAsync(CancellationToken stoppingToken)
6 | {
7 | await Task.Delay(TimeSpan.FromSeconds(2), stoppingToken); // delays a little so that the logs are better visible in a better order (only ended for sample)
8 |
9 | logger.LogInformation("Starting production ...");
10 |
11 | var delay = TimeSpan.FromSeconds(20);
12 | var times = 10;
13 |
14 | var rnd = new Random(DateTimeOffset.UtcNow.Millisecond);
15 |
16 | for (var i = 0; i < times; i++)
17 | {
18 | var id = Convert.ToUInt32(rnd.Next()).ToString();
19 | var size = Convert.ToUInt32(rnd.Next());
20 | var image = (i % 2) == 0;
21 | var url = $"https://localhost:8080/{(image ? "images" : "videos")}/{id}.{(image ? "png" : "flv")}";
22 |
23 | _ = image
24 | ? await DoPublishAsync(new VideoUploaded { VideoId = id, SizeBytes = size, Url = url, }, stoppingToken)
25 | : await DoPublishAsync(new ImageUploaded { ImageId = id, SizeBytes = size, Url = url, }, stoppingToken);
26 |
27 | await Task.Delay(delay, stoppingToken);
28 | }
29 | }
30 |
31 | private async Task DoPublishAsync(T @event, CancellationToken cancellationToken) where T : class
32 | => await publisher.PublishAsync(@event, cancellationToken: cancellationToken);
33 | }
34 |
--------------------------------------------------------------------------------
/samples/ConfigSample/VisualsUploadedConsumer.cs:
--------------------------------------------------------------------------------
1 | namespace ConfigSample;
2 |
3 | internal class VisualsUploadedConsumer(ILogger logger) : IEventConsumer, IEventConsumer
4 | {
5 | private static readonly TimeSpan SimulationDuration = TimeSpan.FromSeconds(1.3f);
6 |
7 | public async Task ConsumeAsync(EventContext context, CancellationToken cancellationToken)
8 | {
9 | var id = context.Event.ImageId;
10 | var thumbnailUrl = $"https://localhost:8080/thumbnails/{id}.jpg";
11 |
12 | await Task.Delay(SimulationDuration, cancellationToken);
13 | logger.LogInformation("Generated thumbnail from image '{ImageId}' at '{ThumbnailUrl}'.", id, thumbnailUrl);
14 | }
15 |
16 | public async Task ConsumeAsync(EventContext context, CancellationToken cancellationToken = default)
17 | {
18 | var id = context.Event.VideoId;
19 | var thumbnailUrl = $"https://localhost:8080/thumbnails/{id}.jpg";
20 |
21 | await Task.Delay(SimulationDuration, cancellationToken);
22 | logger.LogInformation("Generated thumbnail from video '{VideoId}' at '{ThumbnailUrl}'.", id, thumbnailUrl);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/samples/ConfigSample/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Debug",
5 | "Microsoft": "Information",
6 | "System": "Information"
7 | },
8 | "Console": {
9 | "FormatterName": "simple",
10 | "FormatterOptions": {
11 | "SingleLine": true,
12 | "TimestampFormat": "HH:mm:ss "
13 | }
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/samples/ConfigSample/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | },
9 |
10 | "EventBus": {
11 | "DefaultTransportWaitStarted": false,
12 | "Naming": {
13 | "Convention": "DotCase",
14 | "UseFullTypeNames": false
15 | },
16 | "DefaultTransportName": "azure-service-bus",
17 | "Transports": { // keyed by name of the transport
18 | "azure-service-bus": {
19 | "DefaultEntityKind": "Queue", // required if using the basic SKU (does not support topics)
20 | "FullyQualifiedNamespace": "{your_namespace}.servicebus.windows.net"
21 | },
22 | "in-memory-images": {
23 | "DefaultEventIdFormat": "DoubleLongHex"
24 | },
25 | "in-memory-videos": {
26 | "DefaultEntityKind": "Queue"
27 | }
28 | },
29 | "Events": {
30 | "ConfigSample.ImageUploaded": { // FullName of the type
31 | "TransportName": "in-memory-images"
32 | },
33 | "ConfigSample.VideoUploaded": { // FullName of the type
34 | "TransportName": "in-memory-videos",
35 | "Consumers": {
36 | "ConfigSample.VisualsUploadedConsumer": { // FullName of the type
37 | "UnhandledErrorBehaviour": "Discard",
38 | "Metadata": {
39 | "generation": "2022"
40 | }
41 | }
42 | }
43 | }
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/samples/CustomEventConfigurator/CustomEventConfigurator.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/samples/CustomEventConfigurator/MyConfigurator.cs:
--------------------------------------------------------------------------------
1 | using Tingle.EventBus.Configuration;
2 | using Tingle.EventBus.Transports;
3 |
4 | namespace CustomEventConfigurator;
5 |
6 | class MyConfigurator : IEventBusConfigurator
7 | {
8 | public void Configure(EventBusOptions options) { }
9 |
10 | public void Configure(IConfiguration configuration, TOptions options) where TOptions : EventBusTransportOptions { }
11 |
12 | public void Configure(EventRegistration registration, EventBusOptions options)
13 | {
14 | if (registration.EventType == typeof(SampleEvent1))
15 | {
16 | registration.EntityKind = EntityKind.Queue;
17 | }
18 |
19 | if (registration.EventType == typeof(SampleEvent2))
20 | {
21 | registration.IdFormat = EventIdFormat.LongHex;
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/samples/CustomEventConfigurator/Program.cs:
--------------------------------------------------------------------------------
1 | using CustomEventConfigurator;
2 | using Tingle.EventBus.Configuration;
3 |
4 | var host = Host.CreateDefaultBuilder(args)
5 | .ConfigureServices((hostContext, services) =>
6 | {
7 | services.AddEventBus(builder =>
8 | {
9 | // Transport agnostic configuration
10 | builder.Configure(o =>
11 | {
12 | o.Naming.Scope = "dev"; // queues will be prefixed by 'dev'
13 | o.Naming.UseFullTypeNames = false;
14 | });
15 | builder.AddConsumer();
16 | builder.AddConsumer();
17 |
18 | // Setup extra configurators
19 | // You can have as many as you like, these are called after the default one.
20 | builder.Services.AddSingleton();
21 |
22 | // Transport specific configuration
23 | builder.AddAzureQueueStorageTransport(o => o.Credentials = "UseDevelopmentStorage=true;");
24 | });
25 | })
26 | .Build();
27 |
28 | await host.RunAsync();
29 |
--------------------------------------------------------------------------------
/samples/CustomEventConfigurator/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "CustomEventConfigurator": {
4 | "commandName": "Project",
5 | "environmentVariables": {
6 | "DOTNET_ENVIRONMENT": "Development"
7 | }
8 | }
9 | }
10 | }
--------------------------------------------------------------------------------
/samples/CustomEventConfigurator/SampleConsumer1.cs:
--------------------------------------------------------------------------------
1 | namespace CustomEventConfigurator;
2 |
3 | public class SampleConsumer1(ILogger logger) : IEventConsumer
4 | {
5 | public Task ConsumeAsync(EventContext context, CancellationToken cancellationToken = default)
6 | {
7 | logger.LogInformation("Received event Id: {Id}", context.Id);
8 | logger.LogInformation("Event body: {EventBody}", System.Text.Json.JsonSerializer.Serialize(context.Event));
9 | return Task.CompletedTask;
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/samples/CustomEventConfigurator/SampleConsumer2.cs:
--------------------------------------------------------------------------------
1 | namespace CustomEventConfigurator;
2 |
3 | public class SampleConsumer2(ILogger logger) : IEventConsumer
4 | {
5 | public Task ConsumeAsync(EventContext context, CancellationToken cancellationToken = default)
6 | {
7 | logger.LogInformation("Received event Id: {Id}", context.Id);
8 | logger.LogInformation("Event body: {EventBody}", System.Text.Json.JsonSerializer.Serialize(context.Event));
9 | return Task.CompletedTask;
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/samples/CustomEventConfigurator/SampleEvent1.cs:
--------------------------------------------------------------------------------
1 | namespace CustomEventConfigurator;
2 |
3 | public class SampleEvent1
4 | {
5 | public string? Make { get; set; }
6 | public string? Model { get; set; }
7 | public int Year { get; set; }
8 | }
9 |
--------------------------------------------------------------------------------
/samples/CustomEventConfigurator/SampleEvent2.cs:
--------------------------------------------------------------------------------
1 | namespace CustomEventConfigurator;
2 |
3 | public class SampleEvent2
4 | {
5 | public string? VehicleId { get; set; }
6 | public string? Kind { get; set; }
7 | public DateTimeOffset Opened { get; set; }
8 | }
9 |
--------------------------------------------------------------------------------
/samples/CustomEventConfigurator/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Debug",
5 | "Microsoft": "Information",
6 | "System": "Information"
7 | },
8 | "Console": {
9 | "FormatterName": "simple",
10 | "FormatterOptions": {
11 | "SingleLine": true,
12 | "TimestampFormat": "HH:mm:ss "
13 | }
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/samples/CustomEventConfigurator/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/samples/CustomEventSerializer/AzureDevOpsCodePushed.cs:
--------------------------------------------------------------------------------
1 | using CustomEventSerializer.Models;
2 | using Tingle.EventBus.Configuration;
3 |
4 | namespace CustomEventSerializer;
5 |
6 | [EventSerializer(typeof(AzureDevOpsEventSerializer))]
7 | public sealed class AzureDevOpsCodePushed
8 | {
9 | public AzureDevOpsEventResource? Resource { get; set; }
10 | }
11 |
--------------------------------------------------------------------------------
/samples/CustomEventSerializer/AzureDevOpsEventsConsumer.cs:
--------------------------------------------------------------------------------
1 | namespace CustomEventSerializer;
2 |
3 | internal class AzureDevOpsEventsConsumer(ILogger logger) : IEventConsumer
4 | {
5 | public Task ConsumeAsync(EventContext context, CancellationToken cancellationToken = default)
6 | {
7 | var @event = context.Event;
8 | var resource = @event.Resource;
9 | var repository = resource?.Repository;
10 | var defaultBranch = repository?.DefaultBranch;
11 |
12 | // get the updated branches (refs)
13 | var updatedReferences = resource?.RefUpdates?.Select(ru => ru.Name).ToList() ?? [];
14 | logger.LogInformation("Default branch: ({DefaultBranch})", defaultBranch);
15 | logger.LogInformation("Updated branches (references):\r\n- {ChangedReferences}",
16 | string.Join("\r\n- ", updatedReferences));
17 | return Task.CompletedTask;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/samples/CustomEventSerializer/CustomEventSerializer.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/samples/CustomEventSerializer/Models/AzureDevOpsEventResource.cs:
--------------------------------------------------------------------------------
1 | namespace CustomEventSerializer.Models;
2 |
3 | public class AzureDevOpsEventResource
4 | {
5 | ///
6 | /// List of updated references.
7 | ///
8 | public List? RefUpdates { get; set; }
9 |
10 | ///
11 | /// Details about the repository.
12 | ///
13 | public AzureDevOpsEventResourceRepository? Repository { get; set; }
14 | }
15 |
--------------------------------------------------------------------------------
/samples/CustomEventSerializer/Models/AzureDevOpsEventResourceRefUpdate.cs:
--------------------------------------------------------------------------------
1 | namespace CustomEventSerializer.Models;
2 |
3 | public class AzureDevOpsEventResourceRefUpdate
4 | {
5 | public string? Name { get; set; }
6 | public string? OldObjectId { get; set; }
7 | public string? NewObjectId { get; set; }
8 | }
9 |
--------------------------------------------------------------------------------
/samples/CustomEventSerializer/Models/AzureDevOpsEventResourceRepository.cs:
--------------------------------------------------------------------------------
1 | namespace CustomEventSerializer.Models;
2 |
3 | public class AzureDevOpsEventResourceRepository
4 | {
5 | ///
6 | /// The unique identifier of the repository.
7 | ///
8 | public Guid Id { get; set; }
9 |
10 | ///
11 | /// The name of the repository.
12 | ///
13 | public string? Name { get; set; }
14 |
15 | ///
16 | /// The details about the project which owns the repository.
17 | ///
18 | public AzureDevOpsEventResourceRepositoryProject? Project { get; set; }
19 |
20 | ///
21 | /// The default branch of the repository.
22 | ///
23 | public string? DefaultBranch { get; set; }
24 | }
25 |
--------------------------------------------------------------------------------
/samples/CustomEventSerializer/Models/AzureDevOpsEventResourceRepositoryProject.cs:
--------------------------------------------------------------------------------
1 | namespace CustomEventSerializer.Models;
2 |
3 | public class AzureDevOpsEventResourceRepositoryProject
4 | {
5 | ///
6 | /// The unique identifier of the project.
7 | ///
8 | public Guid Id { get; set; }
9 |
10 | ///
11 | /// The name of the project.
12 | ///
13 | public string? Name { get; set; }
14 |
15 | ///
16 | /// The URL for the project.
17 | ///
18 | /// https://dev.azure.com/tingle/_apis/projects/cea8cb01-dd13-4588-b27a-55fa170e4e94
19 | /// Useful for extraction of the name and URL of the organization.
20 | public string? Url { get; set; }
21 | }
22 |
--------------------------------------------------------------------------------
/samples/CustomEventSerializer/Program.cs:
--------------------------------------------------------------------------------
1 | using CustomEventSerializer;
2 |
3 | var host = Host.CreateDefaultBuilder(args)
4 | .ConfigureServices((hostContext, services) =>
5 | {
6 | services.AddEventBus(builder =>
7 | {
8 | // Transport agnostic configuration
9 | builder.Configure(o =>
10 | {
11 | o.Naming.Scope = "dev"; // queues will be prefixed by 'dev'
12 | o.Naming.UseFullTypeNames = false;
13 | });
14 | builder.AddConsumer();
15 |
16 | // Transport specific configuration
17 | builder.AddAzureQueueStorageTransport(o => o.Credentials = "UseDevelopmentStorage=true;");
18 | });
19 | })
20 | .Build();
21 |
22 | await host.RunAsync();
23 |
--------------------------------------------------------------------------------
/samples/CustomEventSerializer/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "CustomEventSerializer": {
4 | "commandName": "Project",
5 | "environmentVariables": {
6 | "DOTNET_ENVIRONMENT": "Development"
7 | }
8 | }
9 | }
10 | }
--------------------------------------------------------------------------------
/samples/CustomEventSerializer/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Debug",
5 | "Microsoft": "Information",
6 | "System": "Information"
7 | },
8 | "Console": {
9 | "FormatterName": "simple",
10 | "FormatterOptions": {
11 | "SingleLine": true,
12 | "TimestampFormat": "HH:mm:ss "
13 | }
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/samples/CustomEventSerializer/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/samples/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Exe
7 | false
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/samples/HealthCheck/AzureServiceBusHealthCheck.cs:
--------------------------------------------------------------------------------
1 | using Azure.Messaging.ServiceBus.Administration;
2 | using Microsoft.Extensions.Diagnostics.HealthChecks;
3 | using Microsoft.Extensions.Options;
4 | using Tingle.EventBus.Transports.Azure.ServiceBus;
5 |
6 | namespace HealthCheck;
7 |
8 | internal class AzureServiceBusHealthCheck(IOptionsMonitor optionsMonitor) : IHealthCheck
9 | {
10 | private const string QueueName = "health-check";
11 |
12 | private readonly AzureServiceBusTransportOptions options = optionsMonitor?.Get(AzureServiceBusDefaults.Name) ?? throw new ArgumentNullException(nameof(optionsMonitor));
13 |
14 | public async Task CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default)
15 | {
16 | try
17 | {
18 | var cred = (AzureServiceBusTransportCredentials)options.Credentials.CurrentValue;
19 | var managementClient = new ServiceBusAdministrationClient(
20 | fullyQualifiedNamespace: cred.FullyQualifiedNamespace,
21 | credential: cred.TokenCredential);
22 |
23 | _ = await managementClient.GetQueueRuntimePropertiesAsync(QueueName, cancellationToken);
24 |
25 | return HealthCheckResult.Healthy();
26 | }
27 | catch (TaskCanceledException) when (cancellationToken.IsCancellationRequested)
28 | {
29 | // ignore long running calls
30 | return HealthCheckResult.Healthy();
31 | }
32 | catch (Exception ex)
33 | {
34 | return new HealthCheckResult(context.Registration.FailureStatus, exception: ex);
35 | }
36 | }
37 | }
38 |
39 |
--------------------------------------------------------------------------------
/samples/HealthCheck/HealthCheck.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/samples/HealthCheck/Program.cs:
--------------------------------------------------------------------------------
1 | using Azure.Identity;
2 | using HealthCheck;
3 | using Tingle.EventBus.Configuration;
4 |
5 | var host = Host.CreateDefaultBuilder(args)
6 | .ConfigureServices((hostContext, services) =>
7 | {
8 | var configuration = hostContext.Configuration;
9 |
10 | services.AddEventBus(builder =>
11 | {
12 | builder.AddConsumer();
13 |
14 | var credential = new DefaultAzureCredential();
15 |
16 | // Transport specific configuration
17 | builder.AddAzureServiceBusTransport(options =>
18 | {
19 | options.Credentials = new AzureServiceBusTransportCredentials
20 | {
21 | TokenCredential = credential,
22 | FullyQualifiedNamespace = "{your_namespace}.servicebus.windows.net"
23 | };
24 | options.DefaultEntityKind = EntityKind.Queue; // required if using the basic SKU (does not support topics)
25 | });
26 |
27 | builder.Services.AddHealthChecks()
28 | .AddCheck(name: "servicebus", tags: ["eventbus"]);
29 | });
30 | })
31 | .Build();
32 |
33 | await host.RunAsync();
34 |
--------------------------------------------------------------------------------
/samples/HealthCheck/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "HealthCheck": {
4 | "commandName": "Project",
5 | "dotnetRunMessages": true,
6 | "environmentVariables": {
7 | "DOTNET_ENVIRONMENT": "Development"
8 | }
9 | }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/samples/HealthCheck/VehicleDoorOpenedEvent.cs:
--------------------------------------------------------------------------------
1 | namespace HealthCheck;
2 |
3 | public class VehicleDoorOpenedEvent
4 | {
5 | public string? VehicleId { get; set; }
6 | public VehicleDoorKind Kind { get; set; }
7 | public DateTimeOffset? Opened { get; set; }
8 | public DateTimeOffset? Closed { get; set; }
9 | }
10 |
--------------------------------------------------------------------------------
/samples/HealthCheck/VehicleTelemetryEvent.cs:
--------------------------------------------------------------------------------
1 | using System.Text.Json.Serialization;
2 |
3 | namespace HealthCheck;
4 |
5 | internal class VehicleTelemetryEvent
6 | {
7 | public string? DeviceId { get; set; }
8 |
9 | public DateTimeOffset Timestamp { get; set; }
10 |
11 | public string? Action { get; set; }
12 |
13 | public VehicleDoorKind? VehicleDoorKind { get; set; }
14 | public VehicleDoorStatus? VehicleDoorStatus { get; set; }
15 |
16 | [JsonExtensionData]
17 | public Dictionary? Extras { get; set; }
18 | }
19 |
20 | public enum VehicleDoorStatus
21 | {
22 | Unknown,
23 | Open,
24 | Closed,
25 | }
26 |
27 | public enum VehicleDoorKind
28 | {
29 | FrontLeft,
30 | FrontRight,
31 | RearLeft,
32 | ReadRight,
33 | Hood,
34 | Trunk,
35 | }
36 |
--------------------------------------------------------------------------------
/samples/HealthCheck/VehicleTelemetryEventsConsumer.cs:
--------------------------------------------------------------------------------
1 | namespace HealthCheck;
2 |
3 | internal class VehicleTelemetryEventsConsumer(ILogger logger) : IEventConsumer
4 | {
5 | public async Task ConsumeAsync(EventContext context, CancellationToken cancellationToken)
6 | {
7 | var telemetry = context.Event;
8 |
9 | var status = telemetry.VehicleDoorStatus;
10 | if (status is not VehicleDoorStatus.Open and not VehicleDoorStatus.Closed)
11 | {
12 | logger.LogWarning("Vehicle Door status '{VehicleDoorStatus}' is not yet supported", status);
13 | return;
14 | }
15 |
16 | var kind = telemetry.VehicleDoorKind;
17 | if (kind is null)
18 | {
19 | logger.LogWarning("Vehicle Door kind '{VehicleDoorKind}' cannot be null", kind);
20 | return;
21 | }
22 |
23 | var timestamp = telemetry.Timestamp;
24 | var updateEvt = new VehicleDoorOpenedEvent
25 | {
26 | VehicleId = telemetry.DeviceId,
27 | Kind = kind.Value,
28 | Closed = status is VehicleDoorStatus.Closed ? timestamp : null,
29 | Opened = status is VehicleDoorStatus.Open ? timestamp : null,
30 | };
31 |
32 | // the VehicleDoorOpenedEvent on a broadcast bus would notify all subscribers
33 | await context.PublishAsync(updateEvt, cancellationToken: cancellationToken);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/samples/HealthCheck/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Debug",
5 | "Microsoft": "Information",
6 | "System": "Information"
7 | },
8 | "Console": {
9 | "FormatterName": "simple",
10 | "FormatterOptions": {
11 | "SingleLine": true,
12 | "TimestampFormat": "HH:mm:ss "
13 | }
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/samples/HealthCheck/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/samples/InMemoryBackgroundProcessing/InMemoryBackgroundProcessing.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/samples/InMemoryBackgroundProcessing/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "InMemoryBackgroundProcessing": {
4 | "commandName": "Project",
5 | "environmentVariables": {
6 | "DOTNET_ENVIRONMENT": "Development"
7 | }
8 | }
9 | }
10 | }
--------------------------------------------------------------------------------
/samples/InMemoryBackgroundProcessing/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Debug",
5 | "Microsoft": "Information",
6 | "System": "Information"
7 | },
8 | "Console": {
9 | "FormatterName": "simple",
10 | "FormatterOptions": {
11 | "SingleLine": true,
12 | "TimestampFormat": "HH:mm:ss "
13 | }
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/samples/InMemoryBackgroundProcessing/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/samples/MultiEventsConsumer/DoorClosed.cs:
--------------------------------------------------------------------------------
1 | namespace MultiEventsConsumer;
2 |
3 | public class DoorClosed
4 | {
5 | ///
6 | /// The vehicle who's door was closed.
7 | ///
8 | public string? VehicleId { get; set; }
9 |
10 | ///
11 | /// The kind of door that was opened.
12 | ///
13 | public DoorKind Kind { get; set; }
14 |
15 | ///
16 | /// When the door was opened.
17 | ///
18 | public DateTimeOffset Closed { get; set; }
19 | }
20 |
--------------------------------------------------------------------------------
/samples/MultiEventsConsumer/DoorKind.cs:
--------------------------------------------------------------------------------
1 | namespace MultiEventsConsumer;
2 |
3 | public enum DoorKind
4 | {
5 | FrontLeft,
6 | FrontRight,
7 | RearLeft,
8 | ReadRight,
9 | Hood,
10 | Trunk,
11 | }
12 |
--------------------------------------------------------------------------------
/samples/MultiEventsConsumer/DoorOpened.cs:
--------------------------------------------------------------------------------
1 | namespace MultiEventsConsumer;
2 |
3 | public class DoorOpened
4 | {
5 | ///
6 | /// The vehicle who's door was opened.
7 | ///
8 | public string? VehicleId { get; set; }
9 |
10 | ///
11 | /// The kind of door that was opened.
12 | ///
13 | public DoorKind Kind { get; set; }
14 |
15 | ///
16 | /// When the door was opened.
17 | ///
18 | public DateTimeOffset Opened { get; set; }
19 | }
20 |
--------------------------------------------------------------------------------
/samples/MultiEventsConsumer/DoorState.cs:
--------------------------------------------------------------------------------
1 | namespace MultiEventsConsumer;
2 |
3 | public enum DoorState
4 | {
5 | Open,
6 | Closed
7 | }
8 |
--------------------------------------------------------------------------------
/samples/MultiEventsConsumer/MultiEventsConsumer.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/samples/MultiEventsConsumer/Program.cs:
--------------------------------------------------------------------------------
1 | var host = Host.CreateDefaultBuilder(args)
2 | .ConfigureServices((hostContext, services) =>
3 | {
4 | services.AddDistributedMemoryCache();
5 |
6 | services.AddEventBus(builder =>
7 | {
8 | builder.AddXmlSerializer();
9 |
10 | // Transport agnostic configuration
11 | builder.Configure(o =>
12 | {
13 | o.Naming.Scope = "dev"; // queues will be prefixed by 'dev'
14 | o.Naming.UseFullTypeNames = false;
15 | });
16 | builder.AddConsumer();
17 |
18 | // Transport specific configuration
19 | builder.AddInMemoryTransport();
20 | });
21 |
22 | services.AddHostedService();
23 | })
24 | .Build();
25 |
26 | await host.RunAsync();
27 |
--------------------------------------------------------------------------------
/samples/MultiEventsConsumer/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "MultiEventsConsumer": {
4 | "commandName": "Project",
5 | "environmentVariables": {
6 | "DOTNET_ENVIRONMENT": "Development"
7 | }
8 | }
9 | }
10 | }
--------------------------------------------------------------------------------
/samples/MultiEventsConsumer/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Debug",
5 | "Microsoft": "Information",
6 | "System": "Information"
7 | },
8 | "Console": {
9 | "FormatterName": "simple",
10 | "FormatterOptions": {
11 | "SingleLine": true,
12 | "TimestampFormat": "HH:mm:ss "
13 | }
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/samples/MultiEventsConsumer/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/samples/MultipleConsumers/DoorOpened.cs:
--------------------------------------------------------------------------------
1 | namespace MultipleConsumers;
2 |
3 | public class DoorOpened
4 | {
5 | ///
6 | /// The vehicle who's door was opened.
7 | ///
8 | public string? VehicleId { get; set; }
9 |
10 | ///
11 | /// The kind of door that was opened.
12 | ///
13 | public OpenDoorKind Kind { get; set; }
14 |
15 | ///
16 | /// When the door was opened.
17 | ///
18 | public DateTimeOffset Opened { get; set; }
19 | }
20 |
21 | public enum OpenDoorKind
22 | {
23 | FrontLeft,
24 | FrontRight,
25 | RearLeft,
26 | ReadRight,
27 | Hood,
28 | Trunk,
29 | }
30 |
--------------------------------------------------------------------------------
/samples/MultipleConsumers/FirstEventConsumer.cs:
--------------------------------------------------------------------------------
1 | namespace MultipleConsumers;
2 |
3 | public class FirstEventConsumer(ILogger logger) : IEventConsumer
4 | {
5 | public Task ConsumeAsync(EventContext context, CancellationToken cancellationToken = default)
6 | {
7 | var evt = context.Event;
8 | var vehicleId = evt.VehicleId;
9 | var kind = evt.Kind;
10 | logger.LogInformation("{DoorKind} door for {VehicleId} was opened at {Opened:r}.", kind, vehicleId, evt.Opened);
11 | return Task.CompletedTask;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/samples/MultipleConsumers/MultipleConsumers.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/samples/MultipleConsumers/Program.cs:
--------------------------------------------------------------------------------
1 | using MultipleConsumers;
2 | using Tingle.EventBus.Configuration;
3 |
4 | var host = Host.CreateDefaultBuilder(args)
5 | .ConfigureServices((hostContext, services) =>
6 | {
7 | services.AddEventBus(builder =>
8 | {
9 | builder.AddNewtonsoftJsonSerializer();
10 |
11 | // Transport agnostic configuration
12 | builder.Configure(o =>
13 | {
14 | o.Naming.Scope = "dev"; // queues will be prefixed by 'dev'
15 | o.Naming.UseFullTypeNames = false;
16 | });
17 | builder.AddConsumer();
18 | builder.AddConsumer();
19 |
20 | // Transport specific configuration
21 | builder.AddInMemoryTransport(o =>
22 | {
23 | // default to Broadcast kind so that we get pub-sub behaviour
24 | o.DefaultEntityKind = EntityKind.Broadcast;
25 | });
26 | });
27 |
28 | services.AddHostedService();
29 | })
30 | .Build();
31 |
32 | await host.RunAsync();
33 |
--------------------------------------------------------------------------------
/samples/MultipleConsumers/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "MultipleConsumers": {
4 | "commandName": "Project",
5 | "environmentVariables": {
6 | "DOTNET_ENVIRONMENT": "Development"
7 | }
8 | }
9 | }
10 | }
--------------------------------------------------------------------------------
/samples/MultipleConsumers/PublisherService.cs:
--------------------------------------------------------------------------------
1 | namespace MultipleConsumers;
2 |
3 | public class PublisherService(IEventPublisher publisher) : BackgroundService
4 | {
5 | protected override async Task ExecuteAsync(CancellationToken stoppingToken)
6 | {
7 | var delay = TimeSpan.FromSeconds(30);
8 | var times = 5;
9 |
10 | var rnd = new Random(DateTimeOffset.UtcNow.Millisecond);
11 |
12 | for (var i = 0; i < times; i++)
13 | {
14 | var evt = new DoorOpened
15 | {
16 | Kind = (OpenDoorKind)rnd.Next(0, 5),
17 | Opened = DateTimeOffset.UtcNow.AddMinutes(rnd.Next(-10, 10)),
18 | VehicleId = "123456",
19 | };
20 |
21 | await publisher.PublishAsync(evt, cancellationToken: stoppingToken);
22 |
23 | await Task.Delay(delay, stoppingToken);
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/samples/MultipleConsumers/SecondEventConsumer.cs:
--------------------------------------------------------------------------------
1 | namespace MultipleConsumers;
2 |
3 | public class SecondEventConsumer(ILogger logger) : IEventConsumer
4 | {
5 | public Task ConsumeAsync(EventContext context, CancellationToken cancellationToken = default)
6 | {
7 | var evt = context.Event;
8 | var vehicleId = evt.VehicleId;
9 | var kind = evt.Kind;
10 | logger.LogInformation("{DoorKind} door for {VehicleId} was opened at {Opened:r}.", kind, vehicleId, evt.Opened);
11 | return Task.CompletedTask;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/samples/MultipleConsumers/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Debug",
5 | "Microsoft": "Information",
6 | "System": "Information"
7 | },
8 | "Console": {
9 | "FormatterName": "simple",
10 | "FormatterOptions": {
11 | "SingleLine": true,
12 | "TimestampFormat": "HH:mm:ss "
13 | }
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/samples/MultipleConsumers/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/samples/MultipleDifferentTransports/MultipleDifferentTransports.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 50e90b43-cf86-44cc-b5f8-2c8c5ff11362
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/samples/MultipleDifferentTransports/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "MultipleDifferentTransports": {
4 | "commandName": "Project",
5 | "environmentVariables": {
6 | "DOTNET_ENVIRONMENT": "Development"
7 | }
8 | }
9 | }
10 | }
--------------------------------------------------------------------------------
/samples/MultipleDifferentTransports/VehicleDoorOpenedEvent.cs:
--------------------------------------------------------------------------------
1 | namespace MultipleDifferentTransports;
2 |
3 | public class VehicleDoorOpenedEvent
4 | {
5 | public string? VehicleId { get; set; }
6 | public VehicleDoorKind Kind { get; set; }
7 | public DateTimeOffset? Opened { get; set; }
8 | public DateTimeOffset? Closed { get; set; }
9 | }
10 |
--------------------------------------------------------------------------------
/samples/MultipleDifferentTransports/VehicleTelemetryEvent.cs:
--------------------------------------------------------------------------------
1 | using System.Text.Json.Serialization;
2 | using Tingle.EventBus.Transports.Azure.EventHubs.IotHub;
3 |
4 | namespace MultipleDifferentTransports;
5 |
6 | internal record VehicleTelemetryEvent : IotHubEvent { }
7 |
8 | internal class VehicleTelemetry
9 | {
10 | public DateTimeOffset Timestamp { get; set; }
11 |
12 | public string? Action { get; set; }
13 |
14 | public VehicleDoorKind? VehicleDoorKind { get; set; }
15 | public VehicleDoorStatus? VehicleDoorStatus { get; set; }
16 |
17 | [JsonExtensionData]
18 | public Dictionary? Extras { get; set; }
19 | }
20 |
21 | public enum VehicleDoorStatus
22 | {
23 | Unknown,
24 | Open,
25 | Closed,
26 | }
27 |
28 | public enum VehicleDoorKind
29 | {
30 | FrontLeft,
31 | FrontRight,
32 | RearLeft,
33 | ReadRight,
34 | Hood,
35 | Trunk,
36 | }
37 |
--------------------------------------------------------------------------------
/samples/MultipleDifferentTransports/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Debug",
5 | "Microsoft": "Information",
6 | "System": "Information"
7 | },
8 | "Console": {
9 | "FormatterName": "simple",
10 | "FormatterOptions": {
11 | "SingleLine": true,
12 | "TimestampFormat": "HH:mm:ss "
13 | }
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/samples/MultipleDifferentTransports/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | },
9 |
10 | "ConnectionStrings:AzureStorage": "UseDevelopmentStorage=true;",
11 | "ConnectionStrings:EventHub": "Endpoint=sb://abcd.servicebus.windows.net/;SharedAccessKeyName=xyz;SharedAccessKey=AAAAAAAAAAAAAAAAAAAAAA==",
12 | "ConnectionStrings:ServiceBus": "Endpoint=sb://abcd.servicebus.windows.net/;SharedAccessKeyName=xyz;SharedAccessKey=AAAAAAAAAAAAAAAAAAAAAA==",
13 | "IotHubEventHubName": "iothub-ehub-test-dev-0000000-0aaaa000aa"
14 | }
15 |
--------------------------------------------------------------------------------
/samples/MultipleSimilarTransports/MultipleSimilarTransports.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/samples/MultipleSimilarTransports/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "MultipleSimilarTransports": {
4 | "commandName": "Project",
5 | "environmentVariables": {
6 | "DOTNET_ENVIRONMENT": "Development"
7 | }
8 | }
9 | }
10 | }
--------------------------------------------------------------------------------
/samples/MultipleSimilarTransports/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Debug",
5 | "Microsoft": "Information",
6 | "System": "Information"
7 | },
8 | "Console": {
9 | "FormatterName": "simple",
10 | "FormatterOptions": {
11 | "SingleLine": true,
12 | "TimestampFormat": "HH:mm:ss "
13 | }
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/samples/MultipleSimilarTransports/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/samples/SimpleConsumer/EventCounter.cs:
--------------------------------------------------------------------------------
1 | namespace SimpleConsumer;
2 |
3 | public class EventCounter
4 | {
5 | private int count = 0;
6 |
7 | public int Count => count;
8 |
9 | public void Consumed()
10 | {
11 | Interlocked.Increment(ref count);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/samples/SimpleConsumer/Program.cs:
--------------------------------------------------------------------------------
1 | using SimpleConsumer;
2 |
3 | var host = Host.CreateDefaultBuilder(args)
4 | .ConfigureServices((hostContext, services) =>
5 | {
6 | services.AddSingleton();
7 | services.AddEventBus(builder =>
8 | {
9 | // Transport agnostic configuration
10 | builder.Configure(o =>
11 | {
12 | o.Naming.Scope = "dev"; // queues will be prefixed by 'dev'
13 | o.Naming.UseFullTypeNames = false;
14 | });
15 | builder.AddConsumer();
16 |
17 | // Transport specific configuration
18 | builder.AddAzureQueueStorageTransport(o => o.Credentials = "UseDevelopmentStorage=true;");
19 | });
20 | })
21 | .Build();
22 |
23 | await host.RunAsync();
24 |
--------------------------------------------------------------------------------
/samples/SimpleConsumer/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "SimpleConsumer": {
4 | "commandName": "Project",
5 | "environmentVariables": {
6 | "DOTNET_ENVIRONMENT": "Development"
7 | }
8 | }
9 | }
10 | }
--------------------------------------------------------------------------------
/samples/SimpleConsumer/SampleEvent.cs:
--------------------------------------------------------------------------------
1 | namespace SimpleConsumer;
2 |
3 | public class SampleEvent
4 | {
5 | public string? Registration { get; set; }
6 | public string? Make { get; set; }
7 | public string? Model { get; set; }
8 | public int Year { get; set; }
9 | public string? VIN { get; set; }
10 | }
11 |
--------------------------------------------------------------------------------
/samples/SimpleConsumer/SampleEventConsumer.cs:
--------------------------------------------------------------------------------
1 | namespace SimpleConsumer;
2 |
3 | public class SampleEventConsumer(EventCounter counter, ILogger logger) : IEventConsumer
4 | {
5 | public Task ConsumeAsync(EventContext context, CancellationToken cancellationToken = default)
6 | {
7 | logger.LogInformation("Received event Id: {Id}", context.Id);
8 | logger.LogInformation("Event body: {EventBody}", System.Text.Json.JsonSerializer.Serialize(context.Event));
9 | counter.Consumed();
10 | return Task.CompletedTask;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/samples/SimpleConsumer/SimpleConsumer.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/samples/SimpleConsumer/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Debug",
5 | "Microsoft": "Information",
6 | "System": "Information"
7 | },
8 | "Console": {
9 | "FormatterName": "simple",
10 | "FormatterOptions": {
11 | "SingleLine": true,
12 | "TimestampFormat": "HH:mm:ss "
13 | }
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/samples/SimpleConsumer/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/samples/SimplePublisher/DoorOpened.cs:
--------------------------------------------------------------------------------
1 | namespace SimplePublisher;
2 |
3 | public class DoorOpened
4 | {
5 | ///
6 | /// The vehicle who's door was opened.
7 | ///
8 | public string? VehicleId { get; set; }
9 |
10 | ///
11 | /// The kind of door that was opened.
12 | ///
13 | public OpenDoorKind Kind { get; set; }
14 |
15 | ///
16 | /// When the door was opened.
17 | ///
18 | public DateTimeOffset Opened { get; set; }
19 | }
20 |
21 | public enum OpenDoorKind
22 | {
23 | FrontLeft,
24 | FrontRight,
25 | RearLeft,
26 | ReadRight,
27 | Hood,
28 | Trunk,
29 | }
30 |
--------------------------------------------------------------------------------
/samples/SimplePublisher/Program.cs:
--------------------------------------------------------------------------------
1 | using SimplePublisher;
2 |
3 | var host = Host.CreateDefaultBuilder(args)
4 | .ConfigureServices((hostContext, services) =>
5 | {
6 | services.AddEventBus(builder =>
7 | {
8 | // Transport agnostic configuration
9 | builder.Configure(o =>
10 | {
11 | o.Naming.Scope = "dev"; // queues will be prefixed by 'dev'
12 | o.Naming.UseFullTypeNames = false;
13 | });
14 |
15 | // Transport specific configuration
16 | builder.AddAzureQueueStorageTransport(o => o.Credentials = "UseDevelopmentStorage=true;");
17 | });
18 |
19 | services.AddHostedService();
20 | })
21 | .Build();
22 |
23 | await host.RunAsync();
24 |
--------------------------------------------------------------------------------
/samples/SimplePublisher/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "SimplePublisher": {
4 | "commandName": "Project",
5 | "environmentVariables": {
6 | "DOTNET_ENVIRONMENT": "Development"
7 | }
8 | }
9 | }
10 | }
--------------------------------------------------------------------------------
/samples/SimplePublisher/PublisherService.cs:
--------------------------------------------------------------------------------
1 | namespace SimplePublisher;
2 |
3 | public class PublisherService(IEventPublisher publisher) : BackgroundService
4 | {
5 | protected override async Task ExecuteAsync(CancellationToken stoppingToken)
6 | {
7 | var delay = TimeSpan.FromSeconds(30);
8 | var times = 5;
9 |
10 | var rnd = new Random(DateTimeOffset.UtcNow.Millisecond);
11 |
12 | for (var i = 0; i < times; i++)
13 | {
14 | var evt = new DoorOpened
15 | {
16 | Kind = (OpenDoorKind)rnd.Next(0, 5),
17 | Opened = DateTimeOffset.UtcNow.AddMinutes(rnd.Next(-10, 10)),
18 | VehicleId = "123456",
19 | };
20 |
21 | await publisher.PublishAsync(evt, cancellationToken: stoppingToken);
22 |
23 | await Task.Delay(delay, stoppingToken);
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/samples/SimplePublisher/SimplePublisher.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/samples/SimplePublisher/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Debug",
5 | "Microsoft": "Information",
6 | "System": "Information"
7 | },
8 | "Console": {
9 | "FormatterName": "simple",
10 | "FormatterOptions": {
11 | "SingleLine": true,
12 | "TimestampFormat": "HH:mm:ss "
13 | }
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/samples/SimplePublisher/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/shared/TrimmingHelper.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics.CodeAnalysis;
2 |
3 | namespace Tingle.EventBus.Internal;
4 |
5 | internal static class TrimmingHelper
6 | {
7 | internal const DynamicallyAccessedMemberTypes Serializer = DynamicallyAccessedMemberTypes.PublicConstructors;
8 | internal const DynamicallyAccessedMemberTypes Transport = DynamicallyAccessedMemberTypes.PublicConstructors;
9 | internal const DynamicallyAccessedMemberTypes Configurator = DynamicallyAccessedMemberTypes.Interfaces | DynamicallyAccessedMemberTypes.PublicConstructors;
10 | internal const DynamicallyAccessedMemberTypes Event = DynamicallyAccessedMemberTypes.PublicConstructors;
11 | internal const DynamicallyAccessedMemberTypes Consumer = DynamicallyAccessedMemberTypes.Interfaces | DynamicallyAccessedMemberTypes.PublicConstructors;
12 | }
13 |
--------------------------------------------------------------------------------
/src/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | netstandard2.1;net8.0;net9.0
7 | true
8 | true
9 | Tingle Software
10 | Tingle Software
11 | true
12 |
13 |
14 |
15 |
16 | true
17 |
18 |
19 | true
20 |
21 |
22 | true
23 | snupkg
24 |
25 | logo.png
26 | MIT
27 | $(PackageTags);EventBus
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Serializers.NewtonsoftJson/MessageStrings.cs:
--------------------------------------------------------------------------------
1 | namespace Tingle.EventBus.Serializers;
2 |
3 | internal class MessageStrings
4 | {
5 | public const string UnreferencedCodeMessage = "JSON serialization and deserialization might require types that cannot be statically analyzed. Migrate to System.Text.Json which has support for native AOT applications.";
6 | }
7 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Serializers.NewtonsoftJson/NewtonsoftJsonEventBusBuilderExtensions.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics.CodeAnalysis;
2 | using Tingle.EventBus.Serializers;
3 |
4 | namespace Microsoft.Extensions.DependencyInjection;
5 |
6 | ///
7 | /// Extension methods on for NewtonsoftJson serializer.
8 | ///
9 | [RequiresUnreferencedCode(MessageStrings.UnreferencedCodeMessage)]
10 | public static class NewtonsoftJsonEventBusBuilderExtensions
11 | {
12 | ///
13 | /// Use the included NewtonsoftJson serializer as the default event serializer.
14 | ///
15 | ///
16 | ///
17 | ///
18 | public static EventBusBuilder AddNewtonsoftJsonSerializer(this EventBusBuilder builder,
19 | Action? configure = null)
20 | {
21 | if (builder == null) throw new ArgumentNullException(nameof(builder));
22 |
23 | // Configure the options for the serializer
24 | var services = builder.Services;
25 | if (configure != null) services.Configure(configure);
26 | services.ConfigureOptions();
27 |
28 | // Add the serializer
29 | return builder.AddSerializer();
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Serializers.NewtonsoftJson/NewtonsoftJsonSerializerConfigureOptions.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Options;
2 | using Tingle.EventBus.Serializers;
3 |
4 | namespace Microsoft.Extensions.DependencyInjection;
5 |
6 | ///
7 | /// A class to finish the configuration of instances of .
8 | ///
9 | internal class NewtonsoftJsonSerializerConfigureOptions : IValidateOptions
10 | {
11 | public ValidateOptionsResult Validate(string? name, NewtonsoftJsonSerializerOptions options)
12 | {
13 | // Ensure the settings are provided
14 | if (options.SerializerSettings == null)
15 | {
16 | return ValidateOptionsResult.Fail($"'{nameof(options.SerializerSettings)}' must be provided");
17 | }
18 |
19 | return ValidateOptionsResult.Success;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Serializers.NewtonsoftJson/NewtonsoftJsonSerializerOptions.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using Newtonsoft.Json.Serialization;
3 |
4 | namespace Tingle.EventBus.Serializers;
5 |
6 | ///
7 | /// Options for configuring NewtonsoftJson based serializer.
8 | ///
9 | public class NewtonsoftJsonSerializerOptions
10 | {
11 | ///
12 | /// The options to use for serialization.
13 | ///
14 | public JsonSerializerSettings SerializerSettings { get; set; } = new JsonSerializerSettings
15 | {
16 | Formatting = Formatting.None, // less data used
17 | NullValueHandling = NullValueHandling.Ignore,
18 |
19 | ContractResolver = new CamelCasePropertyNamesContractResolver(),
20 | };
21 | }
22 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Serializers.NewtonsoftJson/Tingle.EventBus.Serializers.NewtonsoftJson.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | A serializer implementation for Tingle.EventBus using Newtonsoft.Json
5 | $(PackageTags);Serializers;Newtonsoft
6 | Tingle.EventBus.Serializers
7 | false
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Transports.Amazon.Abstractions/AmazonSqsTransportException.cs:
--------------------------------------------------------------------------------
1 | namespace Tingle.EventBus.Transports.Amazon;
2 |
3 | ///
4 | [Serializable]
5 | public class AmazonSqsTransportException : Exception
6 | {
7 | ///
8 | public AmazonSqsTransportException() { }
9 |
10 | ///
11 | public AmazonSqsTransportException(string message) : base(message) { }
12 |
13 | ///
14 | public AmazonSqsTransportException(string message, Exception innerException) : base(message, innerException) { }
15 | }
16 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Transports.Amazon.Abstractions/AmazonTransportOptions.cs:
--------------------------------------------------------------------------------
1 | using Amazon;
2 | using Amazon.Runtime;
3 | using Tingle.EventBus.Transports;
4 |
5 | namespace Microsoft.Extensions.DependencyInjection;
6 |
7 | ///
8 | /// Abstraction for options of AWS-based transports
9 | ///
10 | public abstract class AmazonTransportOptions : EventBusTransportOptions
11 | {
12 | ///
13 | /// The system name of the region to connect to.
14 | /// For example eu-west-1.
15 | /// When not configured, must be provided.
16 | ///
17 | public string? RegionName { get; set; }
18 |
19 | ///
20 | /// The region to connect to.
21 | /// When not set, is used to set it.
22 | ///
23 | public RegionEndpoint? Region { get; set; }
24 |
25 | ///
26 | /// The name of the key granted the requisite access control rights.
27 | ///
28 | public string? AccessKey { get; set; }
29 |
30 | ///
31 | /// The secret associated with the .
32 | ///
33 | public string? SecretKey { get; set; }
34 |
35 | ///
36 | /// Credentials for accessing AWS services.
37 | /// This can be used in place of and .
38 | ///
39 | public AWSCredentials? Credentials { get; set; }
40 | }
41 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Transports.Amazon.Abstractions/AmazonWebServiceResponseExtensions.cs:
--------------------------------------------------------------------------------
1 | using System.Net;
2 | using Tingle.EventBus.Transports.Amazon;
3 |
4 | namespace Amazon.Runtime;
5 |
6 | ///
7 | /// Extension methods for .
8 | ///
9 | public static class AmazonWebServiceResponseExtensions
10 | {
11 | ///
12 | /// Checks if the request was successful.
13 | ///
14 | /// The to check.
15 | ///
16 | public static bool Successful(this AmazonWebServiceResponse response)
17 | {
18 | var statusCode = response.HttpStatusCode;
19 | return statusCode >= HttpStatusCode.OK && statusCode < HttpStatusCode.MultipleChoices;
20 | }
21 |
22 | ///
23 | /// Ensure the request was successful.
24 | ///
25 | /// The to check.
26 | /// If the request was not successful.
27 | public static void EnsureSuccess(this AmazonWebServiceResponse response)
28 | {
29 | if (response.Successful()) return;
30 | const string documentationUri = "https://aws.amazon.com/blogs/developer/logging-with-the-aws-sdk-for-net/";
31 |
32 | var statusCode = response.HttpStatusCode;
33 | var requestId = response.ResponseMetadata.RequestId;
34 |
35 | throw new AmazonSqsTransportException($"Received unsuccessful response ({statusCode}) from AWS endpoint.\n" +
36 | $"See AWS SDK logs ({requestId}) for more details: {documentationUri}");
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Transports.Amazon.Abstractions/Tingle.EventBus.Transports.Amazon.Abstractions.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Shared EventBus transport components for Amazon.
5 | $(PackageTags);Amazon;AWS
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Transports.Amazon.Kinesis/AmazonKinesisDefaults.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.DependencyInjection;
2 |
3 | namespace Tingle.EventBus.Transports.Amazon.Kinesis;
4 |
5 | /// Defaults for .
6 | public static class AmazonKinesisDefaults
7 | {
8 | /// Default name for .
9 | public const string Name = "amazon-kinesis";
10 | }
11 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Transports.Amazon.Kinesis/AmazonKinesisEventBusBuilderExtensions.cs:
--------------------------------------------------------------------------------
1 | using Tingle.EventBus.Transports.Amazon.Kinesis;
2 |
3 | namespace Microsoft.Extensions.DependencyInjection;
4 |
5 | ///
6 | /// Extension methods on for Amazon Kinesis.
7 | ///
8 | public static class AmazonKinesisEventBusBuilderExtensions
9 | {
10 | /// Add Amazon Kinesis transport.
11 | /// The to add to.
12 | /// An to configure the transport options.
13 | ///
14 | public static EventBusBuilder AddAmazonKinesisTransport(this EventBusBuilder builder, Action? configure = null)
15 | => builder.AddAmazonKinesisTransport(AmazonKinesisDefaults.Name, configure);
16 |
17 | /// Add Amazon Kinesis transport.
18 | /// The to add to.
19 | /// The name of the transport
20 | /// An to configure the transport options.
21 | ///
22 | public static EventBusBuilder AddAmazonKinesisTransport(this EventBusBuilder builder, string name, Action? configure = null)
23 | => builder.AddTransport(name, configure);
24 | }
25 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Transports.Amazon.Kinesis/AmazonKinesisTransportOptions.cs:
--------------------------------------------------------------------------------
1 | using Amazon.Kinesis;
2 | using Tingle.EventBus;
3 | using Tingle.EventBus.Configuration;
4 |
5 | namespace Microsoft.Extensions.DependencyInjection;
6 |
7 | ///
8 | /// Options for configuring Amazon Kinesis based event bus.
9 | ///
10 | public class AmazonKinesisTransportOptions : AmazonTransportOptions
11 | {
12 | ///
13 | public override EntityKind DefaultEntityKind { get; set; } = EntityKind.Broadcast;
14 |
15 | ///
16 | /// Configuration for Kinesis
17 | ///
18 | public AmazonKinesisConfig? KinesisConfig { get; set; }
19 |
20 | ///
21 | /// A function for selecting the partition key from an event context.
22 | /// This is called for event before publishing.
23 | /// Defaults function uses as the partition key.
24 | /// The value returned is hashed to determine the shard the event is sent to.
25 | ///
26 | public Func PartitionKeyResolver { get; set; } = (ctx) => ctx.Id;
27 | }
28 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Transports.Amazon.Kinesis/BinaryDataExtensions.cs:
--------------------------------------------------------------------------------
1 | namespace System;
2 |
3 | ///
4 | /// Extension methods for
5 | ///
6 | internal static class BinaryDataExtensions
7 | {
8 | ///
9 | /// Converts the to a .
10 | ///
11 | /// The to be converted.
12 | /// A representing the data.
13 | public static MemoryStream ToMemoryStream(this BinaryData data) => new(data.ToArray());
14 | }
15 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Transports.Amazon.Kinesis/ILoggerExtensions.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics.CodeAnalysis;
2 | using Tingle.EventBus;
3 | using Tingle.EventBus.Internal;
4 |
5 | namespace Microsoft.Extensions.Logging;
6 |
7 | ///
8 | /// Extensions on for the EventBus
9 | ///
10 | internal static partial class ILoggerExtensions
11 | {
12 | [LoggerMessage(100, LogLevel.Information, "Sending {EventBusId} to '{StreamName}'. Scheduled: {Scheduled}.")]
13 | public static partial void SendingToStream(this ILogger logger, string? eventBusId, string streamName, DateTimeOffset? scheduled);
14 |
15 | [LoggerMessage(101, LogLevel.Information, "Sending {EventsCount} messages to '{StreamName}'. Scheduled: {Scheduled}. Events:\r\n- {EventBusIds}")]
16 | private static partial void SendingEventsToStream(this ILogger logger, int eventsCount, string streamName, DateTimeOffset? scheduled, string eventBusIds);
17 |
18 | public static void SendingEventsToStream(this ILogger logger, IList eventBusIds, string streamName, DateTimeOffset? scheduled)
19 | {
20 | if (!logger.IsEnabled(LogLevel.Information)) return;
21 | logger.SendingEventsToStream(eventsCount: eventBusIds.Count,
22 | streamName: streamName,
23 | scheduled: scheduled,
24 | eventBusIds: string.Join("\r\n- ", eventBusIds));
25 | }
26 |
27 | public static void SendingEventsToStream<[DynamicallyAccessedMembers(TrimmingHelper.Event)] T>(this ILogger logger, IList> events, string entityPath, DateTimeOffset? scheduled = null)
28 | where T : class
29 | {
30 | if (!logger.IsEnabled(LogLevel.Information)) return;
31 | logger.SendingEventsToStream(events.Select(e => e.Id).ToList(), entityPath, scheduled);
32 | }
33 |
34 | [LoggerMessage(102, LogLevel.Warning, "Amazon Kinesis does not support delay or scheduled publish.")]
35 | public static partial void SchedulingNotSupported(this ILogger logger);
36 | }
37 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Transports.Amazon.Kinesis/Tingle.EventBus.Transports.Amazon.Kinesis.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Amazon Kinesis transport implementation for Tingle.EventBus.
5 | $(PackageTags);Amazon;AWS;Kinesis
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Transports.Amazon.Sqs/AmazonSqsDefaults.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.DependencyInjection;
2 |
3 | namespace Tingle.EventBus.Transports.Amazon.Sqs;
4 |
5 | /// Defaults for .
6 | public static class AmazonSqsDefaults
7 | {
8 | /// Default name for .
9 | public const string Name = "amazon-sqs";
10 | }
11 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Transports.Amazon.Sqs/AmazonSqsEventBusBuilderExtensions.cs:
--------------------------------------------------------------------------------
1 | using Tingle.EventBus.Transports.Amazon.Sqs;
2 |
3 | namespace Microsoft.Extensions.DependencyInjection;
4 |
5 | ///
6 | /// Extension methods on for Amazon SQS.
7 | ///
8 | public static class AmazonSqsEventBusBuilderExtensions
9 | {
10 | /// Add Amazon SQS transport.
11 | /// The to add to.
12 | /// An to configure the transport options.
13 | ///
14 | public static EventBusBuilder AddAmazonSqsTransport(this EventBusBuilder builder, Action? configure = null)
15 | => builder.AddAmazonSqsTransport(AmazonSqsDefaults.Name, configure);
16 |
17 | /// Add Amazon SQS transport.
18 | /// The to add to.
19 | /// The name of the transport
20 | /// An to configure the transport options.
21 | ///
22 | public static EventBusBuilder AddAmazonSqsTransport(this EventBusBuilder builder, string name, Action? configure = null)
23 | => builder.AddTransport(name, configure);
24 | }
25 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Transports.Amazon.Sqs/AmazonSqsTransportOptions.cs:
--------------------------------------------------------------------------------
1 | using Amazon.SimpleNotificationService;
2 | using Amazon.SimpleNotificationService.Model;
3 | using Amazon.SQS;
4 | using Amazon.SQS.Model;
5 | using Tingle.EventBus.Configuration;
6 |
7 | namespace Microsoft.Extensions.DependencyInjection;
8 |
9 | ///
10 | /// Options for configuring Amazon SQS based event bus.
11 | ///
12 | public class AmazonSqsTransportOptions : AmazonTransportOptions
13 | {
14 | ///
15 | public override EntityKind DefaultEntityKind { get; set; } = EntityKind.Queue;
16 |
17 | ///
18 | /// Configuration for SQS
19 | ///
20 | public AmazonSQSConfig? SqsConfig { get; set; }
21 |
22 | ///
23 | /// Configuration for SNS
24 | ///
25 | public AmazonSimpleNotificationServiceConfig? SnsConfig { get; set; }
26 |
27 | ///
28 | /// A setup function for setting up settings for a topic.
29 | /// This is only called before creation.
30 | ///
31 | public Action? SetupCreateTopicRequest { get; set; }
32 |
33 | ///
34 | /// A setup function for setting up settings for a queue.
35 | /// This is only called before creation.
36 | ///
37 | public Action? SetupCreateQueueRequest { get; set; }
38 | }
39 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Transports.Amazon.Sqs/Tingle.EventBus.Transports.Amazon.Sqs.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Amazon SQS transport implementation for Tingle.EventBus.
5 | $(PackageTags);Amazon;AWS;SQS;SNS
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Transports.Azure.Abstractions/AzureTransportCredentials.cs:
--------------------------------------------------------------------------------
1 | using Azure.Core;
2 |
3 | namespace Microsoft.Extensions.DependencyInjection;
4 |
5 | ///
6 | /// Abstractions for authenticating Azure-based transports without a connection strings.
7 | ///
8 | public abstract class AzureTransportCredentials
9 | {
10 | ///
11 | /// Credential used to authenticate requests.
12 | /// Depending on the transport resources, the relevant permissions must be available in the provided credential.
13 | /// For example to access Azure Blob Storage, you need Blob Storage Container Contributor permission.
14 | /// For more details on assigning tokens,
15 | /// see the official Azure SDK identity docs.
16 | ///
17 | public TokenCredential? TokenCredential { get; set; }
18 | }
19 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Transports.Azure.Abstractions/AzureTransportOptions.cs:
--------------------------------------------------------------------------------
1 | using AnyOfTypes;
2 | using Tingle.EventBus.Transports;
3 |
4 | namespace Microsoft.Extensions.DependencyInjection;
5 |
6 | ///
7 | /// Abstraction for options of Azure-based transports
8 | ///
9 | public abstract class AzureTransportOptions : EventBusTransportOptions where TCredential : AzureTransportCredentials
10 | {
11 | ///
12 | /// Authentication credentials.
13 | /// This can either be a connection string or .
14 | ///
15 | public AnyOf Credentials { get; set; }
16 | }
17 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Transports.Azure.Abstractions/Tingle.EventBus.Transports.Azure.Abstractions.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Shared EventBus transport components for Azure.
5 | $(PackageTags);Azure
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Transports.Azure.EventHubs/AzureBlobStorageCredentials.cs:
--------------------------------------------------------------------------------
1 | using Azure.Core;
2 |
3 | namespace Microsoft.Extensions.DependencyInjection;
4 |
5 | ///
6 | /// Credentials for Azure Blob Storage backed by a .
7 | ///
8 | public class AzureBlobStorageCredentials : AzureTransportCredentials
9 | {
10 | ///
11 | /// A referencing the blob service.
12 | /// This is likely to be similar to "https://{account_name}.blob.core.windows.net".
13 | ///
14 | public Uri? ServiceUrl { get; set; }
15 | }
16 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Transports.Azure.EventHubs/AzureEventHubsDefaults.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.DependencyInjection;
2 |
3 | namespace Tingle.EventBus.Transports.Azure.EventHubs;
4 |
5 | /// Defaults for .
6 | public static class AzureEventHubsDefaults
7 | {
8 | /// Default name for .
9 | public const string Name = "azure-event-hubs";
10 | }
11 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Transports.Azure.EventHubs/AzureEventHubsEventBusBuilderExtensions.cs:
--------------------------------------------------------------------------------
1 | using Tingle.EventBus.Transports.Azure.EventHubs;
2 |
3 | namespace Microsoft.Extensions.DependencyInjection;
4 |
5 | ///
6 | /// Extension methods on for Azure EventHubs
7 | ///
8 | public static class AzureEventHubsEventBusBuilderExtensions
9 | {
10 | /// Add Azure EventHubs transport.
11 | /// The to add to.
12 | /// An to configure the transport options.
13 | ///
14 | public static EventBusBuilder AddAzureEventHubsTransport(this EventBusBuilder builder, Action? configure = null)
15 | => builder.AddAzureEventHubsTransport(AzureEventHubsDefaults.Name, configure);
16 |
17 | /// Add Azure EventHubs transport.
18 | /// The to add to.
19 | /// The name of the transport
20 | /// An to configure the transport options.
21 | ///
22 | public static EventBusBuilder AddAzureEventHubsTransport(this EventBusBuilder builder, string name, Action? configure = null)
23 | => builder.AddTransport(name, configure);
24 | }
25 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Transports.Azure.EventHubs/AzureEventHubsTransportCredentials.cs:
--------------------------------------------------------------------------------
1 | using Azure.Core;
2 |
3 | namespace Microsoft.Extensions.DependencyInjection;
4 |
5 | ///
6 | /// Credentials for Azure EventHubs transport backed by a .
7 | ///
8 | public class AzureEventHubsTransportCredentials : AzureTransportCredentials
9 | {
10 | ///
11 | /// The fully qualified Event Hubs namespace to connect to.
12 | /// This is likely to be similar to {your_namespace}.servicebus.windows.net.
13 | ///
14 | public string? FullyQualifiedNamespace { get; set; }
15 | }
16 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Transports.Azure.EventHubs/IotHub/IotHubConnectionAuthMethod.cs:
--------------------------------------------------------------------------------
1 | using System.Text.Json.Serialization;
2 |
3 | namespace Tingle.EventBus.Transports.Azure.EventHubs.IotHub;
4 |
5 | ///
6 | /// Model representing the data found in iothub-connection-auth-method property.
7 | ///
8 | ///
9 | /// {
10 | /// "scope": "hub",
11 | /// "type": "sas",
12 | /// "issuer": "iothub",
13 | /// "acceptingIpFilterRule": null
14 | /// }
15 | ///
16 | public record IotHubConnectionAuthMethod
17 | {
18 | /// hub
19 | public virtual string? Scope { get; set; }
20 |
21 | /// sas
22 | public virtual string? Type { get; set; }
23 |
24 | /// iothub
25 | public virtual string? Issuer { get; set; }
26 |
27 | ///
28 | [JsonExtensionData]
29 | public Dictionary? Extras { get; set; }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Transports.Azure.EventHubs/IotHub/IotHubJsonSerializerContext.cs:
--------------------------------------------------------------------------------
1 | using System.Text.Json.Serialization;
2 |
3 | namespace Tingle.EventBus.Transports.Azure.EventHubs.IotHub;
4 |
5 | [JsonSerializable(typeof(IotHubConnectionAuthMethod))]
6 | [JsonSerializable(typeof(IotHubOperationalEventPayload))]
7 | internal partial class IotHubJsonSerializerContext : JsonSerializerContext { }
8 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Transports.Azure.EventHubs/MessageStrings.cs:
--------------------------------------------------------------------------------
1 | namespace Tingle.EventBus.Transports.Azure.EventHubs;
2 |
3 | internal class MessageStrings
4 | {
5 | public const string SerializationUnreferencedCodeMessage = "JSON serialization and deserialization might require types that cannot be statically analyzed. Use the serializers and types that takes a JsonSerializerContext, or make sure all of the required types are preserved.";
6 | public const string SerializationRequiresDynamicCodeMessage = "JSON serialization and deserialization might require types that cannot be statically analyzed and might need runtime code generation. Use System.Text.Json source generation for native AOT applications.";
7 | }
8 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Transports.Azure.EventHubs/Tingle.EventBus.Transports.Azure.EventHubs.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Azure Event Hubs transport implementation for Tingle.EventBus.
5 | $(PackageTags);Azure;EventHubs
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Transports.Azure.QueueStorage/AzureQueueStorageDefaults.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.DependencyInjection;
2 |
3 | namespace Tingle.EventBus.Transports.Azure.QueueStorage;
4 |
5 | /// Defaults for .
6 | public static class AzureQueueStorageDefaults
7 | {
8 | /// Default name for .
9 | public const string Name = "azure-queue-storage";
10 | }
11 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Transports.Azure.QueueStorage/AzureQueueStorageEventBusBuilderExtensions.cs:
--------------------------------------------------------------------------------
1 | using Tingle.EventBus.Transports.Azure.QueueStorage;
2 |
3 | namespace Microsoft.Extensions.DependencyInjection;
4 |
5 | ///
6 | /// Extension methods on for Azure Queue Storage.
7 | ///
8 | public static class AzureQueueStorageEventBusBuilderExtensions
9 | {
10 | /// Add Azure Queue Storage transport.
11 | /// The to add to.
12 | /// An to configure the transport options.
13 | ///
14 | public static EventBusBuilder AddAzureQueueStorageTransport(this EventBusBuilder builder, Action? configure = null)
15 | => builder.AddAzureQueueStorageTransport(AzureQueueStorageDefaults.Name, configure);
16 |
17 | /// Add Azure Queue Storage transport.
18 | /// The to add to.
19 | /// The name of the transport
20 | /// An to configure the transport options.
21 | ///
22 | public static EventBusBuilder AddAzureQueueStorageTransport(this EventBusBuilder builder, string name, Action? configure = null)
23 | => builder.AddTransport(name, configure);
24 | }
25 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Transports.Azure.QueueStorage/AzureQueueStorageTransportCredentials.cs:
--------------------------------------------------------------------------------
1 | using Azure.Core;
2 |
3 | namespace Microsoft.Extensions.DependencyInjection;
4 |
5 | ///
6 | /// Credentials for Azure Queue Storage transport backed by a .
7 | ///
8 | public class AzureQueueStorageTransportCredentials : AzureTransportCredentials
9 | {
10 | ///
11 | /// A referencing the queue service.
12 | /// This is likely to be similar to "https://{account_name}.queue.core.windows.net".
13 | ///
14 | public Uri? ServiceUrl { get; set; }
15 | }
16 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Transports.Azure.QueueStorage/AzureQueueStorageTransportOptions.cs:
--------------------------------------------------------------------------------
1 | using Tingle.EventBus.Configuration;
2 |
3 | namespace Microsoft.Extensions.DependencyInjection;
4 |
5 | ///
6 | /// Options for configuring Azure Queue Storage based event bus.
7 | ///
8 | public class AzureQueueStorageTransportOptions : AzureTransportOptions
9 | {
10 | ///
11 | public override EntityKind DefaultEntityKind { get; set; } = EntityKind.Queue;
12 | }
13 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Transports.Azure.QueueStorage/Tingle.EventBus.Transports.Azure.QueueStorage.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Azure Queue Storage transport implementation for Tingle.EventBus.
5 | $(PackageTags);Azure;Queues;QueueStorage
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Transports.Azure.ServiceBus/AzureServiceBusDefaults.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.DependencyInjection;
2 |
3 | namespace Tingle.EventBus.Transports.Azure.ServiceBus;
4 |
5 | /// Defaults for .
6 | public static class AzureServiceBusDefaults
7 | {
8 | /// Default name for .
9 | public const string Name = "azure-service-bus";
10 | }
11 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Transports.Azure.ServiceBus/AzureServiceBusEventBusBuilderExtensions.cs:
--------------------------------------------------------------------------------
1 | using Tingle.EventBus.Transports.Azure.ServiceBus;
2 |
3 | namespace Microsoft.Extensions.DependencyInjection;
4 |
5 | ///
6 | /// Extension methods on for Azure Service Bus.
7 | ///
8 | public static class AzureServiceBusEventBusBuilderExtensions
9 | {
10 | /// Add Azure Service Bus transport.
11 | /// The to add to.
12 | /// An to configure the transport options.
13 | ///
14 | public static EventBusBuilder AddAzureServiceBusTransport(this EventBusBuilder builder, Action? configure = null)
15 | => builder.AddAzureServiceBusTransport(AzureServiceBusDefaults.Name, configure);
16 |
17 | /// Add Azure Service Bus transport.
18 | /// The to add to.
19 | /// The name of the transport
20 | /// An to configure the transport options.
21 | ///
22 | public static EventBusBuilder AddAzureServiceBusTransport(this EventBusBuilder builder, string name, Action? configure = null)
23 | => builder.AddTransport(name, configure);
24 | }
25 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Transports.Azure.ServiceBus/AzureServiceBusTransportCredentials.cs:
--------------------------------------------------------------------------------
1 | using Azure.Core;
2 |
3 | namespace Microsoft.Extensions.DependencyInjection;
4 |
5 | ///
6 | /// Credentials for Azure Service Bus transport backed by a .
7 | ///
8 | public class AzureServiceBusTransportCredentials : AzureTransportCredentials
9 | {
10 | ///
11 | /// The fully qualified Service Bus namespace to connect to.
12 | /// This is likely to be similar to {your_namespace}.servicebus.windows.net.
13 | ///
14 | public string? FullyQualifiedNamespace { get; set; }
15 | }
16 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Transports.Azure.ServiceBus/Tingle.EventBus.Transports.Azure.ServiceBus.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Azure Service Bus transport implementation for Tingle.EventBus.
5 | $(PackageTags);Azure;ServiceBus
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Transports.InMemory/Client/BroadcastChannel.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Channels;
2 |
3 | namespace Tingle.EventBus.Transports.InMemory.Client;
4 |
5 | internal class BroadcastChannel : Channel
6 | {
7 | public BroadcastChannel()
8 | {
9 | Writer = new BroadcastChannelWriter();
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Transports.InMemory/Client/BroadcastChannelWriter.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Channels;
2 |
3 | namespace Tingle.EventBus.Transports.InMemory.Client;
4 |
5 | internal class BroadcastChannelWriter(ICollection>? children = null) : ChannelWriter
6 | {
7 | public ICollection> Children { get; } = children ?? new List>();
8 |
9 | ///
10 | public override bool TryWrite(T item) => Children.All(w => w.TryWrite(item));
11 |
12 | ///
13 | public override ValueTask WaitToWriteAsync(CancellationToken cancellationToken = default)
14 | {
15 | throw new NotSupportedException("Waiting is not supported.");
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Transports.InMemory/Client/InMemoryErrorSource.cs:
--------------------------------------------------------------------------------
1 | namespace Tingle.EventBus.Transports.InMemory.Client;
2 |
3 | ///
4 | /// The source of the error when is raised.
5 | ///
6 | public enum InMemoryErrorSource
7 | {
8 | /// Message receive operation.
9 | Receive,
10 | }
11 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Transports.InMemory/Client/InMemoryProcessorOptions.cs:
--------------------------------------------------------------------------------
1 | namespace Tingle.EventBus.Transports.InMemory;
2 |
3 | internal class InMemoryProcessorOptions
4 | {
5 | public InMemoryProcessorSubQueue SubQueue { get; set; } = InMemoryProcessorSubQueue.None;
6 | }
7 |
8 | internal enum InMemoryProcessorSubQueue
9 | {
10 | None,
11 | DeadLetter,
12 | }
13 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Transports.InMemory/Client/ProcessErrorEventArgs.cs:
--------------------------------------------------------------------------------
1 | namespace Tingle.EventBus.Transports.InMemory.Client;
2 |
3 | ///
4 | /// Contains information about the entity whose processing threw an exception, as
5 | /// well as the exception that has been thrown.
6 | ///
7 | /// The exception that triggered the call to the error event handler.
8 | /// The source associated with the error.
9 | /// The entity path used when this exception occurred.
10 | ///
11 | /// The processor's instance which will be cancelled
12 | /// in the event that is called.
13 | ///
14 | internal class ProcessErrorEventArgs(Exception exception, InMemoryErrorSource errorSource, string entityPath, CancellationToken cancellationToken) : EventArgs
15 | {
16 | ///
17 | /// Gets the exception that triggered the call to the error event handler.
18 | ///
19 | public Exception Exception { get; } = exception;
20 |
21 | ///
22 | /// Gets the source associated with the error.
23 | ///
24 | public InMemoryErrorSource ErrorSource { get; } = errorSource;
25 |
26 | ///
27 | /// Gets the entity path associated with the error event.
28 | ///
29 | public string EntityPath { get; } = entityPath;
30 |
31 | ///
32 | /// Gets the processor's instance which will be
33 | /// cancelled when
34 | /// is called.
35 | ///
36 | public CancellationToken CancellationToken { get; } = cancellationToken;
37 | }
38 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Transports.InMemory/Client/ProcessMessageEventArgs.cs:
--------------------------------------------------------------------------------
1 | namespace Tingle.EventBus.Transports.InMemory.Client;
2 |
3 | ///
4 | /// The contain event args that are specific
5 | /// to the that is being processed.
6 | ///
7 | /// The message to be processed.
8 | ///
9 | /// The processor's which will be cancelled
10 | /// in the event that is called.
11 | ///
12 | internal class ProcessMessageEventArgs(InMemoryReceivedMessage message, CancellationToken cancellationToken) : EventArgs
13 | {
14 | /// The received message to be processed.
15 | public InMemoryReceivedMessage Message { get; } = message;
16 |
17 | ///
18 | /// The processor's instance which will be cancelled
19 | /// when is called.
20 | ///
21 | public CancellationToken CancellationToken { get; } = cancellationToken;
22 | }
23 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Transports.InMemory/Client/SequenceNumberGenerator.cs:
--------------------------------------------------------------------------------
1 | namespace Tingle.EventBus.Transports.InMemory.Client;
2 |
3 | ///
4 | /// A sequence number generator for InMemory transport
5 | ///
6 | public class SequenceNumberGenerator
7 | {
8 | private long currentValue;
9 |
10 | ///
11 | public SequenceNumberGenerator()
12 | {
13 | var random = new Random(DateTimeOffset.UtcNow.Millisecond);
14 | currentValue = random.Next();
15 | }
16 |
17 | /// Generate the next sequence number.
18 | public long Generate() => Interlocked.Increment(ref currentValue);
19 | }
20 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Transports.InMemory/InMemoryDefaults.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.DependencyInjection;
2 |
3 | namespace Tingle.EventBus.Transports.InMemory;
4 |
5 | /// Defaults for .
6 | public static class InMemoryDefaults
7 | {
8 | /// Default name for .
9 | public const string Name = "inmemory";
10 | }
11 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Transports.InMemory/InMemoryTestHarnessConfigureOptions.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Options;
2 |
3 | namespace Microsoft.Extensions.DependencyInjection;
4 |
5 | ///
6 | /// A class to finish the configuration of instances of .
7 | ///
8 | internal class InMemoryTestHarnessConfigureOptions : IPostConfigureOptions
9 | {
10 | public void PostConfigure(string? name, InMemoryTestHarnessOptions options)
11 | {
12 | // intentionally left bank for future use
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Transports.InMemory/InMemoryTestHarnessOptions.cs:
--------------------------------------------------------------------------------
1 | using Tingle.EventBus.Transports.InMemory;
2 |
3 | namespace Microsoft.Extensions.DependencyInjection;
4 |
5 | ///
6 | /// Configuration options for
7 | ///
8 | public class InMemoryTestHarnessOptions
9 | {
10 | ///
11 | /// The duration of time to delay.
12 | /// Defaults to 50ms (0.05 sec).
13 | ///
14 | public TimeSpan DefaultDelay { get; set; } = TimeSpan.FromMilliseconds(50);
15 | }
16 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Transports.InMemory/InMemoryTransportConfigureOptions.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Options;
2 | using Tingle.EventBus.Configuration;
3 |
4 | namespace Microsoft.Extensions.DependencyInjection;
5 |
6 | ///
7 | /// A class to finish the configuration of instances of .
8 | ///
9 | /// An instance.\
10 | /// A list of to use when configuring options.
11 | /// An for bus configuration.\
12 | internal class InMemoryTransportConfigureOptions(IEventBusConfigurationProvider configurationProvider,
13 | IEnumerable configurators,
14 | IOptions busOptionsAccessor)
15 | : EventBusTransportConfigureOptions(configurationProvider, configurators, busOptionsAccessor)
16 | {
17 | ///
18 | public override void PostConfigure(string? name, InMemoryTransportOptions options)
19 | {
20 | base.PostConfigure(name, options);
21 | if (name is null) throw new ArgumentNullException(nameof(name));
22 |
23 | var registrations = BusOptions.GetRegistrations(name);
24 | foreach (var reg in registrations)
25 | {
26 | // Set the values using defaults
27 | options.SetValuesUsingDefaults(reg, BusOptions);
28 |
29 | // Ensure the entity type is allowed
30 | options.EnsureAllowedEntityKind(reg, EntityKind.Broadcast, EntityKind.Queue);
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Transports.InMemory/InMemoryTransportOptions.cs:
--------------------------------------------------------------------------------
1 | using Tingle.EventBus.Transports;
2 |
3 | namespace Microsoft.Extensions.DependencyInjection;
4 |
5 | ///
6 | /// Options for configuring the in-memory based event bus.
7 | ///
8 | public class InMemoryTransportOptions : EventBusTransportOptions
9 | {
10 | // intentionally left blank for future use
11 | }
12 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Transports.InMemory/Tingle.EventBus.Transports.InMemory.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | InMemory transport implementation for Tingle.EventBus (to be used primarily for testing purposes).
5 | $(PackageTags);InMemory
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Transports.Kafka/ILoggerExtensions.cs:
--------------------------------------------------------------------------------
1 | using Confluent.Kafka;
2 |
3 | namespace Microsoft.Extensions.Logging;
4 |
5 | ///
6 | /// Extensions on for the EventBus
7 | ///
8 | internal static partial class ILoggerExtensions
9 | {
10 |
11 | [LoggerMessage(200, LogLevel.Warning, "Kafka does not support delay or scheduled publish.")]
12 | public static partial void SchedulingNotSupported(this ILogger logger);
13 |
14 | [LoggerMessage(201, LogLevel.Warning, "Kafka does not support expiring events.")]
15 | public static partial void ExpiryNotSupported(this ILogger logger);
16 |
17 | [LoggerMessage(202, LogLevel.Warning, "Kafka does not support batching. The events will be looped through one by one.")]
18 | public static partial void BatchingNotSupported(this ILogger logger);
19 |
20 |
21 | [LoggerMessage(300, LogLevel.Information, "Consumer received data at {Offset}")]
22 | public static partial void ConsumerReceivedData(this ILogger logger, TopicPartitionOffset offset);
23 |
24 | [LoggerMessage(301, LogLevel.Trace, "Reached end of topic {Topic}, Partition: {Partition}, Offset: {Offset}.")]
25 | public static partial void EndOfTopic(this ILogger logger, string topic, Partition partition, Offset offset);
26 |
27 | [LoggerMessage(302, LogLevel.Debug, "Processing '{MessageKey}' from '{Topic}', Partition: '{Partition}'. Offset: '{Offset}'")]
28 | public static partial void ProcessingMessage(this ILogger logger, string messageKey, string topic, int partition, long offset);
29 |
30 | [LoggerMessage(303, LogLevel.Information, "Received event: '{EventBusId}' from '{Topic}', Partition: '{Partition}'. Offset: '{Offset}'")]
31 | public static partial void ReceivedEvent(this ILogger logger, string? eventBusId, string topic, int partition, long offset);
32 |
33 | [LoggerMessage(304, LogLevel.Debug, "Checkpointing '{Topic}', Partition: '{Partition}'. Offset: '{Offset}'")]
34 | public static partial void Checkpointing(this ILogger logger, string topic, int partition, long offset);
35 | }
36 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Transports.Kafka/KafkaDefaults.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.DependencyInjection;
2 |
3 | namespace Tingle.EventBus.Transports.Kafka;
4 |
5 | /// Defaults for .
6 | public static class KafkaDefaults
7 | {
8 | /// Default name for .
9 | public const string Name = "kafka";
10 | }
11 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Transports.Kafka/KafkaEventBusBuilderExtensions.cs:
--------------------------------------------------------------------------------
1 | using Tingle.EventBus.Transports.Kafka;
2 |
3 | namespace Microsoft.Extensions.DependencyInjection;
4 |
5 | ///
6 | /// Extension methods on for Kafka.
7 | ///
8 | public static class KafkaEventBusBuilderExtensions
9 | {
10 | /// Add Kafka transport.
11 | /// The to add to.
12 | /// An to configure the transport options.
13 | ///
14 | public static EventBusBuilder AddKafkaTransport(this EventBusBuilder builder, Action? configure = null)
15 | => builder.AddKafkaTransport(KafkaDefaults.Name, configure);
16 |
17 | /// Add Kafka transport.
18 | /// The to add to.
19 | /// The name of the transport
20 | /// An to configure the transport options.
21 | ///
22 | public static EventBusBuilder AddKafkaTransport(this EventBusBuilder builder, string name, Action? configure = null)
23 | => builder.AddTransport(name, configure);
24 | }
25 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Transports.Kafka/KafkaExtensions.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics.CodeAnalysis;
2 | using System.Text;
3 |
4 | namespace Confluent.Kafka;
5 |
6 | internal static class KafkaExtensions
7 | {
8 | public static Headers AddIfNotNull(this Headers headers, string key, string? value)
9 | {
10 | if (!string.IsNullOrWhiteSpace(value))
11 | {
12 | headers.Add(key, Encoding.UTF8.GetBytes(value));
13 | }
14 | return headers;
15 | }
16 |
17 | public static bool TryGetValue(this Headers headers, string key, [NotNullWhen(true)] out string? value)
18 | {
19 | if (headers.TryGetLastBytes(key, out var bytes))
20 | {
21 | value = Encoding.UTF8.GetString(bytes);
22 | return true;
23 | }
24 | value = null;
25 | return false;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Transports.Kafka/Tingle.EventBus.Transports.Kafka.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Kafka transport implementation for Tingle.EventBus.
5 | $(PackageTags);Kafka
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Transports.RabbitMQ/RabbitMqDefaults.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.DependencyInjection;
2 |
3 | namespace Tingle.EventBus.Transports.RabbitMQ;
4 |
5 | /// Defaults for .
6 | public static class RabbitMqDefaults
7 | {
8 | /// Default name for .
9 | public const string Name = "rabbitmq";
10 | }
11 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Transports.RabbitMQ/RabbitMqEventBusBuilderExtensions.cs:
--------------------------------------------------------------------------------
1 | using Tingle.EventBus.Transports.RabbitMQ;
2 |
3 | namespace Microsoft.Extensions.DependencyInjection;
4 |
5 | ///
6 | /// Extension methods on for RabbitMQ.
7 | ///
8 | public static class RabbitMqEventBusBuilderExtensions
9 | {
10 | /// Add RabbitMQ transport.
11 | /// The to add to.
12 | /// An to configure the transport options.
13 | ///
14 | public static EventBusBuilder AddRabbitMqTransport(this EventBusBuilder builder, Action? configure = null)
15 | => builder.AddRabbitMqTransport(RabbitMqDefaults.Name, configure);
16 |
17 | /// Add RabbitMQ transport.
18 | /// The to add to.
19 | /// The name of the transport
20 | /// An to configure the transport options.
21 | ///
22 | public static EventBusBuilder AddRabbitMqTransport(this EventBusBuilder builder, string name, Action? configure = null)
23 | => builder.AddTransport(name, configure);
24 | }
25 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Transports.RabbitMQ/RabbitMqTransportOptions.cs:
--------------------------------------------------------------------------------
1 | using RabbitMQ.Client;
2 | using Tingle.EventBus.Configuration;
3 | using Tingle.EventBus.Transports;
4 |
5 | namespace Microsoft.Extensions.DependencyInjection;
6 |
7 | ///
8 | /// Options for configuring RabbitMQ based event bus.
9 | ///
10 | public class RabbitMqTransportOptions : EventBusTransportOptions
11 | {
12 | ///
13 | public override EntityKind DefaultEntityKind { get; set; } = EntityKind.Broadcast;
14 |
15 | ///
16 | /// The number of retries to make.
17 | ///
18 | public int RetryCount { get; set; }
19 |
20 | ///
21 | /// The host name of the broker.
22 | /// Defaults to localhost
23 | ///
24 | public string Hostname { get; set; } = "localhost";
25 |
26 | ///
27 | /// The username for authenticating on the broker.
28 | /// Defaults to quest.
29 | ///
30 | public string Username { get; set; } = "guest";
31 |
32 | ///
33 | /// The password for authenticating on the broker.
34 | /// Defaults to guest.
35 | ///
36 | public string Password { get; set; } = "guest";
37 |
38 | ///
39 | /// The factory for creating instances when needed.
40 | /// When not provided, a factory is created from the settings available in this class.
41 | ///
42 | public ConnectionFactory? ConnectionFactory { get; set; }
43 | }
44 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus.Transports.RabbitMQ/Tingle.EventBus.Transports.RabbitMQ.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | RabbitMQ transport implementation for Tingle.EventBus.
5 | $(PackageTags);RabbitMQ
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus/Configuration/Attributes/ConsumerNameAttribute.cs:
--------------------------------------------------------------------------------
1 | namespace Tingle.EventBus.Configuration;
2 |
3 | ///
4 | /// Specify the ConsumerName used for this consumer type, overriding the generated one.
5 | ///
6 | [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
7 | public sealed class ConsumerNameAttribute : Attribute
8 | {
9 | ///
10 | ///
11 | ///
12 | /// The consumer name to use for the consumer type
13 | public ConsumerNameAttribute(string consumerName)
14 | {
15 | if (string.IsNullOrWhiteSpace(consumerName))
16 | {
17 | throw new ArgumentException($"'{nameof(consumerName)}' cannot be null or whitespace", nameof(consumerName));
18 | }
19 |
20 | ConsumerName = consumerName;
21 | }
22 |
23 | ///
24 | /// The name of the consumer
25 | ///
26 | public string ConsumerName { get; }
27 | }
28 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus/Configuration/Attributes/EntityKindAttribute.cs:
--------------------------------------------------------------------------------
1 | namespace Tingle.EventBus.Configuration;
2 |
3 | ///
4 | /// Specify the EntityKind used for this event contract/type, overriding the generated one.
5 | ///
6 | /// The event kind to use for the event.
7 | [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)]
8 | public sealed class EntityKindAttribute(EntityKind kind) : Attribute
9 | {
10 | ///
11 | /// The name of the event mapped
12 | ///
13 | public EntityKind Kind { get; } = kind;
14 | }
15 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus/Configuration/Attributes/EventNameAttribute.cs:
--------------------------------------------------------------------------------
1 | namespace Tingle.EventBus.Configuration;
2 |
3 | ///
4 | /// Specify the EventName used for this event contract/type, overriding the generated one.
5 | ///
6 | [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)]
7 | public sealed class EventNameAttribute : Attribute
8 | {
9 | ///
10 | ///
11 | ///
12 | /// The event name to use for the event.
13 | public EventNameAttribute(string eventName)
14 | {
15 | if (string.IsNullOrWhiteSpace(eventName))
16 | {
17 | throw new ArgumentException($"'{nameof(eventName)}' cannot be null or whitespace", nameof(eventName));
18 | }
19 |
20 | EventName = eventName;
21 | }
22 |
23 | ///
24 | /// The name of the event mapped
25 | ///
26 | public string EventName { get; }
27 | }
28 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus/Configuration/Attributes/EventSerializerAttribute.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics.CodeAnalysis;
2 | using Tingle.EventBus.Internal;
3 |
4 | namespace Tingle.EventBus.Configuration;
5 |
6 | ///
7 | /// Specify the serializer type used for an event contract/type, overriding the default one.
8 | ///
9 | ///
10 | /// The type of serializer to use for the event type.
11 | /// It must implement .
12 | ///
13 | [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)]
14 | public sealed class EventSerializerAttribute([DynamicallyAccessedMembers(TrimmingHelper.Serializer)] Type serializerType) : Attribute
15 | {
16 | ///
17 | /// The type of serializer to be used.
18 | ///
19 | [DynamicallyAccessedMembers(TrimmingHelper.Serializer)]
20 | public Type SerializerType { get; } = serializerType ?? throw new ArgumentNullException(nameof(serializerType));
21 | }
22 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus/Configuration/Attributes/EventTransportNameAttribute.cs:
--------------------------------------------------------------------------------
1 | namespace Tingle.EventBus.Configuration;
2 |
3 | ///
4 | /// Specify the name of the transport used for this event contract/type, overriding the default one.
5 | ///
6 | [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)]
7 | public sealed class EventTransportNameAttribute : Attribute
8 | {
9 | ///
10 | ///
11 | ///
12 | /// The name of the transport to use for the event contract/type
13 | public EventTransportNameAttribute(string name)
14 | {
15 | if (string.IsNullOrWhiteSpace(name))
16 | {
17 | throw new ArgumentException($"'{nameof(name)}' cannot be null or whitespace", nameof(name));
18 | }
19 |
20 | Name = name;
21 | }
22 |
23 | ///
24 | /// The name of the transport to use for the event contract/type
25 | ///
26 | public string Name { get; }
27 | }
28 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus/Configuration/ConsumerNameSource.cs:
--------------------------------------------------------------------------------
1 | namespace Tingle.EventBus.Configuration;
2 |
3 | ///
4 | /// The source used when generating names for consumers.
5 | ///
6 | public enum ConsumerNameSource
7 | {
8 | ///
9 | /// The type name of the consumer is used.
10 | ///
11 | TypeName,
12 |
13 | ///
14 | /// The prefix provided in the bus options.
15 | ///
16 | Prefix,
17 |
18 | ///
19 | /// The prefix provided in the bus options
20 | /// and the type name of the consumer are combined.
21 | ///
22 | PrefixAndTypeName,
23 | }
24 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus/Configuration/DefaultEventBusConfigurationProvider.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Configuration;
2 |
3 | namespace Tingle.EventBus.Configuration;
4 |
5 | ///
6 | /// Default implementation of .
7 | ///
8 | internal class DefaultEventBusConfigurationProvider(IConfiguration configuration) : IEventBusConfigurationProvider
9 | {
10 | private const string EventBusKey = "EventBus";
11 |
12 | ///
13 | public IConfiguration Configuration => configuration.GetSection(EventBusKey);
14 | }
--------------------------------------------------------------------------------
/src/Tingle.EventBus/Configuration/DefaultEventBusConfigurator.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Configuration;
2 | using Microsoft.Extensions.DependencyInjection;
3 | using System.Diagnostics.CodeAnalysis;
4 | using Tingle.EventBus.Transports;
5 |
6 | namespace Tingle.EventBus.Configuration;
7 |
8 | ///
9 | /// Default implementation of .
10 | ///
11 | /// The instance.
12 | [RequiresDynamicCode(MessageStrings.BindingDynamicCodeMessage)]
13 | [RequiresUnreferencedCode(MessageStrings.BindingUnreferencedCodeMessage)]
14 | internal class DefaultEventBusConfigurator(IEventBusConfigurationProvider configurationProvider) : IEventBusConfigurator
15 | {
16 | ///
17 | public void Configure(EventBusOptions options)
18 | {
19 | configurationProvider.Configuration.Bind(options);
20 | }
21 |
22 | ///
23 | public void Configure(IConfiguration configuration, TOptions options) where TOptions : EventBusTransportOptions
24 | {
25 | configuration.Bind(options);
26 | }
27 |
28 | ///
29 | public void Configure(EventRegistration registration, EventBusOptions options)
30 | {
31 | if (registration is null) throw new ArgumentNullException(nameof(registration));
32 | if (options is null) throw new ArgumentNullException(nameof(options));
33 |
34 | // bind from IConfiguration
35 | var configuration = configurationProvider.Configuration.GetSection($"Events:{registration.EventType.FullName}");
36 | configuration.Bind(registration);
37 | foreach (var ecr in registration.Consumers)
38 | {
39 | configuration.GetSection($"Consumers:{ecr.ConsumerType.FullName}").Bind(ecr);
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus/Configuration/EntityKind.cs:
--------------------------------------------------------------------------------
1 | namespace Tingle.EventBus.Configuration;
2 |
3 | ///
4 | /// The preferred entity type for events.
5 | ///
6 | public enum EntityKind
7 | {
8 | ///
9 | /// Represents an entity that broadcasts to multiple destinations.
10 | /// Depending on the transport, this may be referred to as a topic, exchange, stream or hub
11 | ///
12 | Broadcast,
13 |
14 | ///
15 | /// Represents an entity that only maps the event to only one destination (itself).
16 | /// Depending on the transport, it may have a different name.
17 | ///
18 | Queue,
19 | }
20 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus/Configuration/EventIdFormat.cs:
--------------------------------------------------------------------------------
1 | namespace Tingle.EventBus.Configuration;
2 |
3 | ///
4 | /// The preferred format to use for values generated for .
5 | ///
6 | public enum EventIdFormat
7 | {
8 | ///
9 | /// Value is generated via .
10 | /// For example 17a2a99b-9b40-4f93-9333-7036154d20a8
11 | ///
12 | Guid,
13 |
14 | ///
15 | /// Value is generated via but the dashes are removed.
16 | /// For example 17a2a99b9b404f9393337036154d20a8
17 | ///
18 | GuidNoDashes,
19 |
20 | ///
21 | /// Value is generated via but only the first 8 bytes are changed to .
22 | /// For example 5734097450149521819
23 | ///
24 | Long,
25 |
26 | ///
27 | /// Value is generated via but only the first 8 bytes are changed to .
28 | /// For example 4f939b4017a2a99b
29 | ///
30 | LongHex,
31 |
32 | ///
33 | /// Value is generated via and converted to two concatenated.
34 | /// For example 573409745014952181912114767751129609107
35 | ///
36 | DoubleLong,
37 |
38 | ///
39 | /// Value is generated via and converted to two concatenated.
40 | /// For example 4f939b4017a2a99ba8204d1536703393
41 | ///
42 | DoubleLongHex,
43 |
44 | ///
45 | /// Value is generated via and the bytes converted to base 64.
46 | /// For example m6miF0Cbk0+TM3A2FU0gqA==
47 | ///
48 | Random,
49 | }
50 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus/Configuration/IEventBusConfigurationProvider.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Configuration;
2 |
3 | namespace Tingle.EventBus.Configuration;
4 |
5 | ///
6 | /// Provides an interface for implementing a construct that provides
7 | /// access to EventBus-related configuration sections.
8 | ///
9 | public interface IEventBusConfigurationProvider
10 | {
11 | ///
12 | /// Gets the where EventBus options are stored.
13 | ///
14 | IConfiguration Configuration { get; }
15 | }
16 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus/Configuration/IEventBusConfigurator.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Configuration;
2 | using Microsoft.Extensions.DependencyInjection;
3 | using Tingle.EventBus.Transports;
4 |
5 | namespace Tingle.EventBus.Configuration;
6 |
7 | ///
8 | /// Abstraction for configuring instances of , , and .
9 | ///
10 | public interface IEventBusConfigurator
11 | {
12 | ///
13 | /// Configure an instance of .
14 | /// This is called once during startup.
15 | ///
16 | /// The instance.
17 | void Configure(EventBusOptions options);
18 |
19 | ///
20 | /// Configure options for a specific transport.
21 | ///
22 | /// The type of options.
23 | ///
24 | /// The instance to be configured.
25 | void Configure(IConfiguration configuration, TOptions options) where TOptions : EventBusTransportOptions;
26 |
27 | ///
28 | /// Configure an instance of .
29 | /// This is called once for each event either during startup
30 | /// (when there is a consumer) or on first publish.
31 | ///
32 | /// The to be configured.
33 | /// The instance.
34 | void Configure(EventRegistration registration, EventBusOptions options);
35 | }
36 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus/Configuration/NamingConvention.cs:
--------------------------------------------------------------------------------
1 | namespace Tingle.EventBus.Configuration;
2 |
3 | ///
4 | /// The naming convention used when generating names from types.
5 | ///
6 | public enum NamingConvention
7 | {
8 | ///
9 | /// The type name is unchanged.
10 | ///
11 | Unchanged,
12 |
13 | ///
14 | /// The type name is converted to Kebab case
15 | ///
16 | KebabCase,
17 |
18 | ///
19 | /// The type name is converted to Snake case.
20 | ///
21 | SnakeCase,
22 |
23 | ///
24 | /// The type name is transformed into a lower case string with a period between words.
25 | ///
26 | DotCase,
27 | }
28 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus/Configuration/UnhandledConsumerErrorBehaviour.cs:
--------------------------------------------------------------------------------
1 | namespace Tingle.EventBus.Configuration;
2 |
3 | ///
4 | /// The behaviour to follow when an unhandled error in a consumer's
5 | ///
6 | /// invocation results in an exception that is not handled.
7 | ///
8 | public enum UnhandledConsumerErrorBehaviour
9 | {
10 | ///
11 | /// Move the event to dead-letter entity.
12 | /// Handling of dead-letter is transport specific.
13 | ///
14 | Deadletter,
15 |
16 | ///
17 | /// Discard the event.
18 | /// Depending on the transport, the event can be ignored, abandoned or skipped.
19 | ///
20 | Discard,
21 | }
22 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus/DependencyInjection/EventBusSerializationOptions.cs:
--------------------------------------------------------------------------------
1 | using System.Text.Json;
2 | using Tingle.EventBus.Serialization;
3 |
4 | namespace Microsoft.Extensions.DependencyInjection;
5 |
6 | ///
7 | /// Specified options for serialization.
8 | ///
9 | public class EventBusSerializationOptions
10 | {
11 | ///
12 | /// The options to use for serialization.
13 | ///
14 | public JsonSerializerOptions SerializerOptions { get; set; } = new JsonSerializerOptions
15 | {
16 | NumberHandling = System.Text.Json.Serialization.JsonNumberHandling.AllowNamedFloatingPointLiterals
17 | | System.Text.Json.Serialization.JsonNumberHandling.AllowReadingFromString,
18 | WriteIndented = false, // less data used
19 | DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingDefault
20 | | System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull,
21 |
22 | PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
23 | PropertyNameCaseInsensitive = true,
24 | AllowTrailingCommas = true,
25 | ReadCommentHandling = JsonCommentHandling.Skip,
26 | };
27 |
28 | ///
29 | /// The information about the host where the EventBus is running.
30 | ///
31 | public HostInfo? HostInfo { get; set; }
32 | }
33 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus/DependencyInjection/EventBusTransportRegistrationBuilder.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics.CodeAnalysis;
2 | using Tingle.EventBus.Internal;
3 | using Tingle.EventBus.Transports;
4 |
5 | namespace Microsoft.Extensions.DependencyInjection;
6 |
7 | /// Used to build s.
8 | /// The name of the transport being built.
9 | public class EventBusTransportRegistrationBuilder(string name)
10 | {
11 | /// Gets the name of the transport being built.
12 | public string Name { get; } = name;
13 |
14 | /// Gets or sets the display name for the transport being built.
15 | public string? DisplayName { get; set; }
16 |
17 | /// Gets or sets the type responsible for this transport.
18 | [DynamicallyAccessedMembers(TrimmingHelper.Transport)]
19 | public Type? TransportType { get; set; }
20 |
21 | /// Builds the instance.
22 | /// The .
23 | public EventBusTransportRegistration Build()
24 | {
25 | if (TransportType is null)
26 | {
27 | throw new InvalidOperationException($"{nameof(TransportType)} must be configured to build an {nameof(EventBusTransportRegistration)}.");
28 | }
29 |
30 | return new EventBusTransportRegistration(Name, DisplayName, TransportType);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus/Diagnostics/ActivityNames.cs:
--------------------------------------------------------------------------------
1 | namespace Tingle.EventBus.Diagnostics;
2 |
3 | ///
4 | /// Names for activities generated by EventBus
5 | ///
6 | public static class ActivityNames
7 | {
8 | #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
9 | public const string Consume = "EventBus.Consume";
10 | public const string Publish = "EventBus.Publish";
11 | public const string Cancel = "EventBus.Cancel";
12 | #pragma warning restore CS1591 // Missing XML comment for publicly visible type or member
13 | }
14 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus/Diagnostics/ActivityTagNames.cs:
--------------------------------------------------------------------------------
1 | namespace Tingle.EventBus.Diagnostics;
2 |
3 | ///
4 | /// Names for tags added to activities generated by EventBus
5 | ///
6 | public static class ActivityTagNames
7 | {
8 | #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
9 | public const string MessagingSystem = "messaging.system";
10 | public const string MessagingMessageId = "messaging.message_id";
11 | public const string MessagingConversationId = "messaging.conversation_id";
12 | public const string MessagingDestination = "messaging.destination";
13 | public const string MessagingDestinationKind = "messaging.destination_kind";
14 | public const string MessagingTempDestination = "messaging.temp_destination";
15 | public const string MessagingProtocol = "messaging.protocol";
16 | public const string MessagingProtocolVersion = "messaging.protocol_version";
17 | public const string MessagingUrl = "messaging.url";
18 |
19 | public const string NetPeerIp = "net.peer.ip";
20 | public const string NetPeerName = "net.peer.name";
21 |
22 | public const string EventBusEventType = "eventbus.event_type";
23 | public const string EventBusSerializerType = "eventbus.serializer_type";
24 | public const string EventBusConsumerType = "eventbus.consumer_type";
25 | public const string EventBusEventsCount = "eventbus.events_count";
26 | #pragma warning restore CS1591 // Missing XML comment for publicly visible type or member
27 | }
28 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus/Diagnostics/EventBusActivitySource.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics;
2 | using System.Reflection;
3 |
4 | namespace Tingle.EventBus.Diagnostics;
5 |
6 | ///
7 | public static class EventBusActivitySource
8 | {
9 | private static readonly AssemblyName AssemblyName = typeof(EventBusActivitySource).Assembly.GetName();
10 | private static readonly string ActivitySourceName = AssemblyName.Name!;
11 | private static readonly Version Version = AssemblyName.Version!;
12 | private static readonly ActivitySource ActivitySource = new(ActivitySourceName, Version.ToString());
13 |
14 | ///
15 | /// Creates a new activity if there are active listeners for it, using the specified
16 | /// name, activity kind, and parent Id.
17 | ///
18 | ///
19 | ///
20 | ///
21 | ///
22 | public static Activity? StartActivity(string name, ActivityKind kind = ActivityKind.Internal, string? parentId = null)
23 | {
24 | return parentId is not null
25 | ? ActivitySource.StartActivity(name: name, kind: kind, parentId: parentId)
26 | : ActivitySource.StartActivity(name: name, kind: kind);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus/Diagnostics/HeaderNames.cs:
--------------------------------------------------------------------------------
1 | namespace Tingle.EventBus.Diagnostics;
2 |
3 | ///
4 | /// Names of known headers added to events
5 | ///
6 | public static class HeaderNames
7 | {
8 | #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
9 | public const string EventType = "X-Event-Type";
10 | public const string ActivityId = "X-Activity-Id";
11 | #pragma warning restore CS1591 // Missing XML comment for publicly visible type or member
12 | }
13 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus/Diagnostics/LogCategoryNames.cs:
--------------------------------------------------------------------------------
1 | namespace Tingle.EventBus.Diagnostics;
2 |
3 | ///
4 | /// The category names to use for logging.
5 | ///
6 | internal static class LogCategoryNames
7 | {
8 | public const string EventBus = "Tingle.EventBus";
9 | public const string Transports = EventBus + ".Transports";
10 | public const string Serializers = EventBus + ".Serializers";
11 | }
12 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus/IEventConsumer.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics.CodeAnalysis;
2 | using Tingle.EventBus.Internal;
3 |
4 | namespace Tingle.EventBus;
5 |
6 | ///
7 | /// Contract describing a consumer of one or more events.
8 | ///
9 | public interface IEventConsumer
10 | {
11 | // Intentionally left blank
12 | }
13 |
14 | ///
15 | /// Contract describing a consumer of an event.
16 | ///
17 | public interface IEventConsumer<[DynamicallyAccessedMembers(TrimmingHelper.Event)] T> : IEventConsumer where T : class
18 | {
19 | ///
20 | /// Consume an event of the provided type.
21 | ///
22 | /// The context of the event
23 | ///
24 | ///
25 | Task ConsumeAsync(EventContext context, CancellationToken cancellationToken);
26 | }
27 |
28 | ///
29 | /// Contract describing a consumer of a dead-lettered event.
30 | ///
31 | public interface IDeadLetteredEventConsumer<[DynamicallyAccessedMembers(TrimmingHelper.Event)] T> : IEventConsumer where T : class
32 | {
33 | ///
34 | /// Consume a dead-lettered event of the provided type.
35 | ///
36 | /// The context of the event
37 | ///
38 | ///
39 | Task ConsumeAsync(DeadLetteredEventContext context, CancellationToken cancellationToken);
40 | }
41 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus/Ids/DefaultEventIdGenerator.cs:
--------------------------------------------------------------------------------
1 | using Tingle.EventBus.Configuration;
2 |
3 | namespace Tingle.EventBus.Ids;
4 |
5 | ///
6 | /// Default implementation of .
7 | ///
8 | public class DefaultEventIdGenerator : IEventIdGenerator
9 | {
10 | ///
11 | public string Generate(EventRegistration reg)
12 | {
13 | if (reg is null) throw new ArgumentNullException(nameof(reg));
14 |
15 | var id = Guid.NewGuid();
16 | var bytes = id.ToByteArray();
17 |
18 | return reg.IdFormat switch
19 | {
20 | EventIdFormat.Guid => id.ToString(),
21 | EventIdFormat.GuidNoDashes => id.ToString("n"),
22 | EventIdFormat.Long => BitConverter.ToUInt64(bytes, 0).ToString(),
23 | EventIdFormat.LongHex => BitConverter.ToUInt64(bytes, 0).ToString("x"),
24 | EventIdFormat.DoubleLong => $"{BitConverter.ToUInt64(bytes, 0)}{BitConverter.ToUInt64(bytes, 8)}",
25 | EventIdFormat.DoubleLongHex => $"{BitConverter.ToUInt64(bytes, 0):x}{BitConverter.ToUInt64(bytes, 8):x}",
26 | EventIdFormat.Random => Convert.ToBase64String(bytes),
27 | _ => throw new NotSupportedException($"'{nameof(EventIdFormat)}.{reg.IdFormat}' set on event '{reg.EventType.FullName}' is not supported."),
28 | };
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus/Ids/IEventIdGenerator.cs:
--------------------------------------------------------------------------------
1 | using Tingle.EventBus.Configuration;
2 |
3 | namespace Tingle.EventBus.Ids;
4 |
5 | ///
6 | /// Generator for event identifiers
7 | ///
8 | public interface IEventIdGenerator
9 | {
10 | ///
11 | /// Generate value for .
12 | ///
13 | /// The for which to generate for.
14 | ///
15 | string Generate(EventRegistration reg);
16 | }
17 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus/Internal/DictionaryExtensions.cs:
--------------------------------------------------------------------------------
1 | namespace Tingle.EventBus.Internal;
2 |
3 | /// Extension methods on .
4 | public static class DictionaryExtensions
5 | {
6 | ///
7 | /// Creates an
8 | /// wrapping around the provided .
9 | ///
10 | /// The type of keys in the dictionary.
11 | /// The type of values in the dictionary.
12 | /// The dictionary to use
13 | ///
14 | public static EventBusDictionaryWrapper ToEventBusWrapper(this IDictionary dictionary)
15 | where TKey : notnull => new(dictionary);
16 | }
17 |
--------------------------------------------------------------------------------
/src/Tingle.EventBus/Internal/EventBusHost.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Hosting;
2 | using Microsoft.Extensions.Logging;
3 |
4 | namespace Tingle.EventBus.Internal;
5 |
6 | /// Host for .
7 | ///
8 | ///
9 | ///
10 | internal class EventBusHost(IHostApplicationLifetime lifetime, EventBus bus, ILogger logger) : BackgroundService
11 | {
12 | ///
13 | protected override async Task ExecuteAsync(CancellationToken stoppingToken)
14 | {
15 | if (!await WaitForAppStartupAsync(lifetime, stoppingToken).ConfigureAwait(false))
16 | {
17 | logger.ApplicationDidNotStartup();
18 | return;
19 | }
20 |
21 | await bus.StartAsync(stoppingToken).ConfigureAwait(false);
22 | }
23 |
24 | ///
25 | public override async Task StopAsync(CancellationToken cancellationToken)
26 | {
27 | await base.StopAsync(cancellationToken).ConfigureAwait(false);
28 | await bus.StopAsync(cancellationToken).ConfigureAwait(false);
29 | }
30 |
31 | private static async Task WaitForAppStartupAsync(IHostApplicationLifetime lifetime, CancellationToken stoppingToken)
32 | {
33 | var startedTcs = new TaskCompletionSource