{"id":37035533,"url":"https://github.com/rehmanab/topica","last_synced_at":"2026-01-14T04:12:22.285Z","repository":{"id":317111202,"uuid":"407979946","full_name":"rehmanab/topica","owner":"rehmanab","description":"Lightweight, modular library for managing messages and topics in .NET","archived":false,"fork":false,"pushed_at":"2025-11-24T10:25:01.000Z","size":2003,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-01-07T10:26:39.046Z","etag":null,"topics":["aws","azure","kafka","pulsar","rabbitmq","servicebus"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rehmanab.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2021-09-18T22:25:11.000Z","updated_at":"2025-11-24T10:25:05.000Z","dependencies_parsed_at":null,"dependency_job_id":"2637fc83-c5fd-4399-bda4-1539edc5926d","html_url":"https://github.com/rehmanab/topica","commit_stats":null,"previous_names":["rehmanab/topica"],"tags_count":31,"template":false,"template_full_name":null,"purl":"pkg:github/rehmanab/topica","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rehmanab%2Ftopica","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rehmanab%2Ftopica/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rehmanab%2Ftopica/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rehmanab%2Ftopica/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rehmanab","download_url":"https://codeload.github.com/rehmanab/topica/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rehmanab%2Ftopica/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28409179,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T01:52:23.358Z","status":"online","status_checked_at":"2026-01-14T02:00:06.678Z","response_time":107,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aws","azure","kafka","pulsar","rabbitmq","servicebus"],"created_at":"2026-01-14T04:12:21.563Z","updated_at":"2026-01-14T04:12:22.267Z","avatar_url":"https://github.com/rehmanab.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Topica\n\n[![Build](https://github.com/rehmanab/topica/actions/workflows/ci_main.yml/badge.svg)](https://github.com/rehmanab/topica/actions/workflows/ci_main.yml)\u0026nbsp;\u0026nbsp;\u0026nbsp;[![Publish Nuget Packages](https://github.com/rehmanab/topica/actions/workflows/ci_main_tag.yml/badge.svg)](https://github.com/rehmanab/topica/actions/workflows/ci_main_tag.yml)\n\nTopica is a lightweight, modular library for managing messages and topics in .NET applications. It provides a unified API for creating, publishing, and subscribing to messages across multiple messaging platforms, including AWS SQS/SNS, Azure Service Bus, Kafka, Pulsar, and RabbitMQ.\n\n## Features\n\n- Unified API for message publishing and subscription\n- Support for multiple brokers: AWS, Azure, Kafka, Pulsar, RabbitMQ\n- Extensible and modular architecture\n- Built-in dependency injection and logging support\n- Resilience with Polly integration\n\n## Project Structure\n\n- **Topica**: Core abstractions and utilities (`netstandard2.1`)\n- **Topica.Aws**: AWS SQS/SNS implementation\n- **Topica.Azure.ServiceBus**: Azure Service Bus implementation\n- **Topica.Kafka**: Kafka implementation\n- **Topica.Pulsar**: Pulsar implementation\n- **Topica.RabbitMq**: RabbitMQ implementation\n- **Topica.SharedMessageHandlers**: Shared message handler logic\n- **\\*.Host**: Example producer/consumer host applications for each platform\n- **Topica.SharedMessageHandlers**: Shared messages classes and handlers for all the Host producers \u0026 consumers\n- **Topica.Web**: An ASP.NET website that hosts Health Checks with a UI\n\n## Description\nThese are a set of libraries that handle topic, queue messages processing, where you can consume messages from a queue that is subscribed to a topic. \n\nConsumers can run multiple instances in parallel to split the workload. When using the nuget packages, you only need create the message and handler classes and correct handler class HandleAsync() method will be called where the generic type argument of the handler matches the `Type` property of the `BaseMessage`\n\nAfter creating a message class and a handler for that class, the subscriber will look for a message handler that implements that message type and execute its Validate then Handle methods.\n\n## Installation\n\nYou can view/run the docker compose files in the [docker-scripts](https://github.com/rehmanab/docker-scripts) GitHub repository folder for setting up local instances of the various messaging platforms.\n\n\nAdd the relevant NuGet packages to your project:\n\n```shell\ndotnet add package Topica (Required)\ndotnet add package Topica.Aws\ndotnet add package Topica.Azure.ServiceBus\ndotnet add package Topica.Kafka\ndotnet add package Topica.Pulsar\ndotnet add package Topica.RabbitMq\n```\n\n## Quick Start\n\n### 1. Define a Message \u0026 Handler\nCreate a message class that implements `BaseMessage`.\n\n```csharp\npublic class ButtonClickedMessageV1 : BaseMessage\n{\n    public string? ButtonText { get; set; }\n    public string? ButtonId { get; set; }\n    public string? UserId { get; set; }\n    public string? SessionId { get; set; }\n    public DateTime? Timestamp { get; set; }\n}\n```\n\nCreate a handler class that implements `IHandler\u003cButtonClickedMessageV1\u003e`.\n\n```csharp\npublic class ButtonClickedMessageHandlerV1(ILogger\u003cButtonClickedMessageHandlerV1\u003e logger) : IHandler\u003cButtonClickedMessageV1\u003e\n{\n    public async Task\u003cbool\u003e HandleAsync(ButtonClickedMessageV1 source, Dictionary\u003cstring, string\u003e? properties)\n    {\n        logger.LogInformation(\"Handle: {Name} for event: {Data} - {Props}\", nameof(ButtonClickedMessageV1), $\"{source.EventId} : {source.EventName}\", string.Join(\"; \", properties?.Select(x =\u003e $\"{x.Key}:{x.Value}\") ?? []));\n        return await Task.FromResult(true);\n    }\n\n    public bool ValidateMessage(ButtonClickedMessageV1 message)\n    {\n        // Do some validation on the incoming message\n        return true;\n    }\n}\n```\n\n### 2. Setup the startup dependencies and configuration using the extension method\nExample with AWS SNS Topics\n\nConfigure the messaging options in your `appsettings.json` or through code.\n\n```csharp\nservices.AddAwsTopica(c =\u003e\n{\n    c.ProfileName = hostSettings.ProfileName;\n    c.AccessKey = hostSettings.AccessKey;\n    c.SecretKey = hostSettings.SecretKey;\n    c.ServiceUrl = hostSettings.ServiceUrl;\n    c.RegionEndpoint = hostSettings.RegionEndpoint;\n}, Assembly.GetAssembly(typeof(ClassToReferenceAssembly)) ?? throw new InvalidOperationException());\n```\n`ClassToReferenceAssembly` is a holding class in the project where your messages \u0026 handlers are located, if they are in the same project, you can just use `Program`\n\nInject an instance of `IAwsTopicCreationBuilder` and use its builder methods to configure the topic and queue properties, this builder will also create the topic and subscribed queues if they dont exist on the source messaging system (AWS in this case). The setup for producer and consumer are similar because they will both independently create the topic and queues if they dont exist. \n\nTo use a builder that does NOT create the Topic and queue, please ensure that they already exist (else producing and consuming will throw an exception) use an instance of `IAwsTopicBuilder`\n\n#### Building a Producer and Consumer (not all are required, only the ones you need)\n```csharp\nvar producer = await builder\n    .WithWorkerName(nameof(ButtonClickedMessageV1)) // Just the name of the worker so you can identify it when you log\n    .WithTopicName(topicName)\n    .WithSubscribedQueues([\"topica_web_analytics_queue_sales_v1\", \"topica_web_analytics_queue_reporting_v1\"]) // Topic will publish to these queues\n    .WithQueueToSubscribeTo(\"topica_web_analytics_queue_sales_v1\") // Will consume from this queue\n    .WithFifoSettings(true, true) // First in First out, do duplication based on message content\n    .WithTemporalSettings(30, 0, 345600, 5) // (MessageVisibilityTimeoutSeconds, QueueMessageDelaySeconds, QueueMessageRetentionPeriodSeconds, QueueReceiveMessageWaitTimeSeconds)\n    .WithErrorQueueSettings(true, 5) // Create and error queue that is published to after 5 handling errors\n    .WithQueueSettings(262144) // QueueMaximumMessageSize KB\n    .BuildProducerAsync(cancellationToken);\n```\n\n```csharp\nvar consumer = await builder\n    .WithWorkerName(nameof(ButtonClickedMessageV1)) // Just the name of the worker so you can identify it when you log\n    .WithTopicName(\"topica_web_analytics_topic_v1\")\n    .WithSubscribedQueues([\"topica_web_analytics_queue_sales_v1\", \"topica_web_analytics_queue_reporting_v1\"]) // Topic will publish to these queues\n    .WithQueueToSubscribeTo(\"topica_web_analytics_queue_sales_v1\") // Will consume from this queue\n    .WithFifoSettings(true, true) // First in First out, do duplication based on message content\n    .WithTemporalSettings(30, 0, 345600, 5) // (MessageVisibilityTimeoutSeconds, QueueMessageDelaySeconds, QueueMessageRetentionPeriodSeconds, QueueReceiveMessageWaitTimeSeconds)\n    .WithErrorQueueSettings(true, 5) // Create and error queue that is published to after 5 handling errors\n    .WithQueueSettings(262144) // QueueMaximumMessageSize KB\n    .WithConsumeSettings(1, 10) // Number of parallel instances, QueueReceiveMaximumNumberOfMessages\n    .BuildConsumerAsync(cancellationToken);\n```\n\n### 3. Publishing a Message\nPublish messages using `IProducer` that was created above.\n\n```csharp\nvar message = new ButtonClickedMessageV1\n{\n    ConversationId = Guid.NewGuid(), \n    EventId = count, \n    EventName = \"button.clicked.web.v1\", \n    Type = nameof(ButtonClickedMessageV1), // This string value must match the name of the generic type parameter of the Handler when consuming messages. i.e. `IHandler\u003cButtonClickedMessageV1\u003e`\n    MessageGroupId = Guid.NewGuid().ToString()\n};\n\n// Add some AWS topic message attributes\nvar attributes = new Dictionary\u003cstring, string\u003e\n{\n    {\"traceparent\", \"AWS topic\" },\n    {\"tracestate\", \"AWS topic\" },\n};\n\nawait producer.ProduceAsync(message, attributes, cancellationToken);\n\n```\n\n### 4. Consuming from a Topic or Queue.\nConsume messages using `IConsumer` that was created above. Depending on your configuration of .WithConsumerSettings() instance count, those many instances of the worker will be spun up running in parallel allowing multiple different messages to be processed in parallel. The actual platform message system is responsible of passing a single unique message to any one consumer. i.e. if you run an instance count of 5 workers and there are 10 messages on the AWS queue, each worker will process 2 messages each...depending on each message handling time that is.\n\n```csharp\nawait consumer.ConsumeAsync(cancellationToken);\n```\n\n### 5. Running a Host\nEach *.Host project demonstrates a producer or consumer for a specific platform. For example, to run a RabbitMQ topic consumer:\n\n```code\ncd src/RabbitMq.Topic.Consumer.Host\ndotnet run\n```\n\nConfigure connection settings in appsettings.json as needed.\nEach Messaging platform supports its own configuration options, typically set in appsettings.json or via code. See the respective Host project for details.\n\n### 6. Running Topic.Web - Health Checks UI\nThe Topica.Web project is an ASP.NET Core web application that provides a health check UI for monitoring the status of your messaging services. It uses the AspNetCore.HealthChecks.UI package to display health check results in a user-friendly interface.\n\nThe Topica.Web project uses \"UserSecrets\" to manage sensitive configuration data during local development (i.e. running the project in VS or Rider). When running locally, then you can add your Messaging platform keys in your secret file, using the json from the appsettings.json\n\nTo enable a health check for a specific messaging service, change the relevant section to the `HealthCheckSettings` in your `appsettings.json` file. For example, to enable a health check for an AWS SNS Topic:\n```json\n{\n  \"HealthCheckSettings\": {\n    ...\n    \"AwsTopic\": {\n      \"Name\": \"AWS SNS Topic\",\n      \"Tag\": \"Aws\",\n      \"Enabled\": true, // Set to true to enable this health check\n      \"TimeOut\": \"00:00:15\"\n    }\n    ...\n  }\n}\n```\n\nTo run in Docker, then run the following command from the src/ directory:\n```bash\ndocker build -f Topica.Web\\Dockerfile -t topica.web:latest .\n```\n```bash\ndocker run -d -p 7055:7055 -p 7022:7022 --env ASPNETCORE_ENVIRONMENT=Development -e ASPNETCORE_URLS=http://*:7022 --name topica.web topica.web:latest\n```\n\nIf you want to run the https endpoint, then you must create a self-signed certificate and place it in the %USERPROFILE%\\\\.aspnet\\https\\ folder with the name aspnetapp.pfx and password \"password\". You can create a self-signed certificate. Then you can add these environment variables to your Docker run command:\n```\n-e ASPNETCORE_URLS=https://*:7055;http://*:7022 -e ASPNETCORE_Kestrel__Certificates__Default__Password=\"password\" -e ASPNETCORE_Kestrel__Certificates__Default__Path=/https/aspnetapp.pfx -v %USERPROFILE%\\.aspnet\\https:/https/\n```\n\nYou can then access the health check UI at:\n\nhttp://localhost:7022/health\nor\nhttps://localhost:7055/health\n\n## License\n\nMIT\n\u003chr/\u003e\n\n## Documentation\nFor more details, see the individual example host applications, and it's appsettings.json files for configuration options.\n\n### Example Consumer Hosts\n- [AWS SQS (Queue) Host](src/Aws.Queue.Consumer.Host)\n- [AWS SNS (Topic) Host](src/Aws.Topic.Consumer.Host)\n- [Azure Service Bus Host](src/Azure.ServiceBus.Topic.Consumer.Host)\n- [Kafka Host](src/Kafka.Topic.Consumer.Host)\n- [Pulsar Host](src/Pulsar.Topic.Consumer.Host)\n- [RabbitMQ Queue Host](src/RabbitMq.Queue.Consumer.Host)\n- [RabbitMQ Topic Host](src/RabbitMq.Topic.Consumer.Host)\n\n### Example Producer Hosts\n- [AWS SQS (Queue) Host](src/Aws.Queue.Producer.Host)\n- [AWS SNS (Topic) Host](src/Aws.Topic.Producer.Host)\n- [Azure Service Bus Host](src/Azure.ServiceBus.Topic.Producer.Host)\n- [Kafka Host](src/Kafka.Topic.Producer.Host)\n- [Pulsar Host](src/Pulsar.Topic.Producer.Host)\n- [RabbitMQ Queue Host](src/RabbitMq.Queue.Producer.Host)\n- [RabbitMQ Topic Host](src/RabbitMq.Topic.Producer.Host)\n\n### Libraries - Implementations\n- [Topica (Core)](src/Topica)\n- [Topica AWS](src/Topica.Aws)\n- [Topica Azure Service Bus](src/Topica.Azure.ServiceBus)\n- [Topica Kafka](src/Topica.Kafka)\n- [Topica Pulsar](src/Topica.Pulsar)\n- [Topica RabbitMQ](src/Topica.RabbitMq)\n\n### Web (Health Checks UI)\n- [Topica Web (ASP.NET Health Check UI)](src/Topica.Web)\n\n### Docker Compose Files\n- You can view/run the docker compose files in the [docker-scripts](https://github.com/rehmanab/docker-scripts) GitHub repository folder for setting up local instances of the various messaging platforms.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frehmanab%2Ftopica","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frehmanab%2Ftopica","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frehmanab%2Ftopica/lists"}