{"id":29195904,"url":"https://github.com/marcominerva/simpletransit","last_synced_at":"2026-04-27T01:31:44.855Z","repository":{"id":301321127,"uuid":"963344043","full_name":"marcominerva/SimpleTransit","owner":"marcominerva","description":"A simple implementation of an in-memory publisher/subscriber pattern ","archived":false,"fork":false,"pushed_at":"2025-06-26T08:26:05.000Z","size":83,"stargazers_count":1,"open_issues_count":2,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-06-26T09:32:55.607Z","etag":null,"topics":["c-sharp","dotnet","helpers-library","pub-sub"],"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/marcominerva.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","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}},"created_at":"2025-04-09T14:33:45.000Z","updated_at":"2025-06-23T08:38:09.000Z","dependencies_parsed_at":"2025-06-26T09:34:58.637Z","dependency_job_id":"1c592342-bbb2-4697-826d-ccd25b27b681","html_url":"https://github.com/marcominerva/SimpleTransit","commit_stats":null,"previous_names":["marcominerva/simpletransit"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/marcominerva/SimpleTransit","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcominerva%2FSimpleTransit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcominerva%2FSimpleTransit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcominerva%2FSimpleTransit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcominerva%2FSimpleTransit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/marcominerva","download_url":"https://codeload.github.com/marcominerva/SimpleTransit/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcominerva%2FSimpleTransit/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263077628,"owners_count":23410167,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["c-sharp","dotnet","helpers-library","pub-sub"],"created_at":"2025-07-02T05:06:48.283Z","updated_at":"2026-04-27T01:31:44.849Z","avatar_url":"https://github.com/marcominerva.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# SimpleTransit\n\n[![Lint Code Base](https://github.com/marcominerva/SimpleTransit/actions/workflows/linter.yml/badge.svg)](https://github.com/marcominerva/SimpleTransit/actions/workflows/linter.yml)\n[![CodeQL](https://github.com/marcominerva/SimpleTransit/actions/workflows/github-code-scanning/codeql/badge.svg)](https://github.com/marcominerva/SimpleTransit/actions/workflows/github-code-scanning/codeql)\n[![Nuget](https://img.shields.io/nuget/v/SimpleTransit)](https://www.nuget.org/packages/SimpleTransit)\n[![Nuget](https://img.shields.io/nuget/dt/SimpleTransit)](https://www.nuget.org/packages/SimpleTransit)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/marcominerva/SimpleTransit/blob/master/LICENSE.txt)\n\nA simple, lightweight implementation of an in-memory publisher/subscriber pattern for .NET applications. SimpleTransit provides a clean and efficient way to implement message-driven architectures using either direct notification handling or queued message processing.\n\n## Features\n\n- **Dual Messaging Patterns**: Support for both immediate notifications and queued message processing\n- **Dependency Injection Integration**: Seamless integration with Microsoft.Extensions.DependencyInjection\n- **ASP.NET Core Ready**: Built-in support for HTTP context-aware scoping\n- **Type-Safe**: Strongly-typed message handling with generic interfaces\n- **Minimal Dependencies**: Lightweight with minimal external dependencies\n- **Multi-Target Support**: Compatible with .NET 8.0, 9.0 and 10.0\n\n## Installation\n\nSimpleTransit is available as NuGet packages:\n\n### Main Package\n\n```bash\ndotnet add package SimpleTransit\n```\n\n### Abstractions Package (for shared contracts)\n\n```bash\ndotnet add package SimpleTransit.Abstractions\n```\n\n## Quick Start\n\n### 1. Configure Services\n\nAdd SimpleTransit to your dependency injection container:\n\n```csharp\nvar builder = WebApplication.CreateBuilder(args);\n\n// Register SimpleTransit and automatically discover handlers/consumers\nbuilder.Services.AddSimpleTransit(options =\u003e\n{\n    options.RegisterServicesFromAssemblyContaining\u003cProgram\u003e();\n});\n\nvar app = builder.Build();\n```\n\n### 2. Define Your Messages\n\n```csharp\n// For notifications (direct handling)\npublic record PersonCreated(string FirstName, string LastName, string? City);\n\n// For queued messages (implement IMessage)\npublic record ProductCreated(string Name, string Description, double Price) : IMessage;\n```\n\n### 3. Create Handlers\n\n#### Notification Handler (Immediate Processing)\n\n```csharp\npublic class PersonCreatedNotificationHandler(ILogger\u003cPersonCreatedNotificationHandler\u003e logger) : INotificationHandler\u003cPersonCreated\u003e\n{\n    public async Task HandleAsync(PersonCreated message, CancellationToken cancellationToken)\n    {\n        logger.LogInformation(\"Person created: {FirstName} {LastName} from {City}\", \n            message.FirstName, message.LastName, message.City);\n        \n        // Handle the notification immediately\n        await DoSomethingAsync(message);\n    }\n}\n```\n\n#### Message Consumer (Queued background Processing)\n\n```csharp\npublic class ProductCreatedConsumer(ILogger\u003cProductCreatedConsumer\u003e logger) : IConsumer\u003cProductCreated\u003e\n{\n    public async Task HandleAsync(ProductCreated message, CancellationToken cancellationToken)\n    {\n        logger.LogInformation(\"Processing product: {ProductName}...\", message.Name);\n        \n        // Simulate processing\n        await Task.Delay(1000, cancellationToken);\n        \n        logger.LogInformation(\"Product processed: {ProductName}\", message.Name);\n    }\n}\n```\n\n### 4. Publish Messages\n\n```csharp\napp.MapPost(\"/api/people\", async (PersonCreated person, INotificationPublisher notificationPublisher) =\u003e\n{\n    // Publish notification (handled immediately)\n    await notificationPublisher.NotifyAsync(person);\n    return TypedResults.Ok();\n});\n\napp.MapPost(\"/api/products\", async (ProductCreated product, IMessagePublisher messagePublisher) =\u003e\n{\n    // Publish message (queued for processing)\n    await messagePublisher.PublishAsync(product);\n    return TypedResults.Accepted();\n});\n```\n\n## Usage Patterns\n\n### Notifications vs Messages\n\nSimpleTransit supports two distinct messaging patterns:\n\n#### 1. Notifications (Immediate Processing)\n\n- **Purpose**: Immediate handling of events\n- **Interface**: `INotificationHandler\u003cT\u003e`\n- **Publisher**: `INotificationPublisher`\n- **Execution**: Notifications are handled in the same context of the caller that invokes `NotifyAsync`\n- **Use Cases**: Logging, immediate side effects, real-time updates\n\n#### 2. Messages (Queued background Processing)\n\n- **Purpose**: Reliable, background processing\n- **Interface**: `IConsumer\u003cT\u003e` where `T : IMessage`\n- **Publisher**: `IMessagePublisher`\n- **Execution**: Asynchronous queue processing\n- **Use Cases**: Long-running operations, batch processing, reliable delivery\n\n## Configuration Options\n\n### Manual Registration\n\n```csharp\nbuilder.Services.AddSimpleTransit(options =\u003e\n{\n    // Mark that you have notification handlers\n    options.UseNotificationHandlers();\n    \n    // Mark that you have message consumers\n    options.UseMessageConsumers();\n});\n\n// Manually register your handlers\nbuilder.Services.AddTransient\u003cINotificationHandler\u003cPersonCreated\u003e, PersonCreatedNotificationHandler\u003e();\nbuilder.Services.AddTransient\u003cIConsumer\u003cProductCreated\u003e, ProductCreatedConsumer\u003e();\n```\n\n### Automatic Registration\n\n```csharp\nbuilder.Services.AddSimpleTransit(options =\u003e\n{\n    // Register all handlers and consumers from specified assembly\n    options.RegisterServicesFromAssemblyContaining\u003cProgram\u003e();\n    \n    // Or from a specific assembly\n    options.RegisterServicesFromAssembly(typeof(MyHandler).Assembly);\n    \n    // With optional filtering\n    options.RegisterServicesFromAssembly(\n        assembly, \n        type =\u003e type.Namespace?.StartsWith(\"MyApp.Handlers\") == true);\n});\n```\n\n## Advanced Scenarios\n\n### Multiple Handlers\n\nMultiple notification handlers can be registered for the same message type:\n\n```csharp\npublic class EmailNotificationHandler : INotificationHandler\u003cPersonCreated\u003e\n{\n    public async Task HandleAsync(PersonCreated message, CancellationToken cancellationToken)\n    {\n        // Send email\n    }\n}\n\npublic class AuditNotificationHandler : INotificationHandler\u003cPersonCreated\u003e\n{\n    public async Task HandleAsync(PersonCreated message, CancellationToken cancellationToken)\n    {\n        // Log to audit system\n    }\n}\n```\n\n### Error Handling\n\nExceptions thrown by notification handlers are forwarded to the caller, allowing for proper error handling. Exceptions from background message consumers are not propagated.\n\n```csharp\ntry\n{\n    await notificationPublisher.NotifyAsync(message);\n}\ncatch (Exception ex)\n{\n    // Handle errors from any of the notification handlers\n    logger.LogError(ex, \"Error processing notification\");\n}\n```\n\n### Scoped Services\n\nSimpleTransit properly handles service scoping, especially in ASP.NET Core applications:\n\n```csharp\npublic class DatabaseHandler(MyDbContext context) : INotificationHandler\u003cPersonCreated\u003e\n{\n    public async Task HandleAsync(PersonCreated message, CancellationToken cancellationToken)\n    {\n        // Use scoped DbContext safely\n        context.People.Add(new Person { Name = message.FirstName });\n        await context.SaveChangesAsync(cancellationToken);\n    }\n}\n```\n\n## Best Practices\n\n1. **Choose the Right Pattern**: Use notifications for immediate actions, messages for background processing\n2. **Keep Handlers Focused**: Each handler should have a single responsibility\n3. **Handle Errors Gracefully**: Always consider error scenarios in your handlers\n4. **Use Cancellation Tokens**: Support cancellation for long-running operations\n5. **Leverage Dependency Injection**: Take advantage of scoped services for database operations\n6. **Consider Performance**: Notifications are executed synchronously, so keep them fast\n\n## Samples\n\nA complete sample application is available in the [`samples/SimpleTransitSample`](samples/SimpleTransitSample) directory, demonstrating:\n\n- Web API integration\n- Both notification and message patterns\n- Service registration and configuration\n- Real-world usage scenarios\n\nTo run the sample:\n\n```bash\ncd samples/SimpleTransitSample\ndotnet run\n```\n\nThen navigate to the Swagger UI at the URL specified in the console to test the API endpoints.\n\n## Contributing\n\nContributions are welcome! Please feel free to submit issues, feature requests, or pull requests.\n\n### Development Guidelines\n\n1. **Fork the repository** and create a feature branch\n2. **Follow existing code style** and conventions\n3. **Add tests** for new functionality\n4. **Update documentation** as needed\n5. **Ensure all tests pass** before submitting\n\n### Building the Project\n\n```bash\n# Clone the repository\ngit clone https://github.com/marcominerva/SimpleTransit.git\ncd SimpleTransit\n\n# Build the solution\ndotnet build\n\n# Run tests (if available)\ndotnet test\n```\n\n### Reporting Issues\n\nWhen reporting issues, please include:\n- .NET version\n- SimpleTransit version\n- Minimal reproduction example\n- Expected vs actual behavior\n\n## License\n\nThis project is licensed under the [MIT License](LICENSE.txt).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarcominerva%2Fsimpletransit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmarcominerva%2Fsimpletransit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarcominerva%2Fsimpletransit/lists"}