{"id":31381648,"url":"https://github.com/deveel/deveel.events","last_synced_at":"2026-04-22T06:03:06.887Z","repository":{"id":305813202,"uuid":"774007614","full_name":"deveel/deveel.events","owner":"deveel","description":"A simple framework to publish and events within an application","archived":false,"fork":false,"pushed_at":"2026-04-21T20:35:31.000Z","size":169,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-04-21T21:33:36.024Z","etag":null,"topics":["cloudevents","cloudevents-schema","dotnet","dotnetcore","event-schema","events","publisher","schema"],"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/deveel.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-03-18T19:29:17.000Z","updated_at":"2026-04-21T20:35:34.000Z","dependencies_parsed_at":"2025-07-22T06:45:52.208Z","dependency_job_id":"18d0ad65-a266-47a1-ae2e-1490968ea0ed","html_url":"https://github.com/deveel/deveel.events","commit_stats":null,"previous_names":["deveel/deveel.events"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/deveel/deveel.events","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/deveel%2Fdeveel.events","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/deveel%2Fdeveel.events/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/deveel%2Fdeveel.events/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/deveel%2Fdeveel.events/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/deveel","download_url":"https://codeload.github.com/deveel/deveel.events/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/deveel%2Fdeveel.events/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32123604,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-22T00:31:26.853Z","status":"online","status_checked_at":"2026-04-22T02:00:05.693Z","response_time":58,"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":["cloudevents","cloudevents-schema","dotnet","dotnetcore","event-schema","events","publisher","schema"],"created_at":"2025-09-28T10:40:18.028Z","updated_at":"2026-04-22T06:03:06.881Z","avatar_url":"https://github.com/deveel.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"![GitHub License](https://img.shields.io/github/license/deveel/deveel.events)\n![GitHub Release](https://img.shields.io/github/v/release/deveel/deveel.events) ![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/deveel/deveel.events/cicd.yml?logo=github)\n![Codecov](https://img.shields.io/codecov/c/github/deveel/deveel.events?logo=codecov)\n\n\n# Deveel Events\n\nThis project provides a simple and lightweight framework for publishing events to subscribers, using common channels and topics.\n\nThe ambition of this little framework is to implement a set of common patterns and practices that can be used to implement a simple and efficient event-driven architecture in a .NET application, using common approaches to create events and publish them.\n\nIt is not in the scope of this project to provide a full-featured event storage system, nor a complex pub/sub application: if you need such a system, you should consider using a message broker or a message queue system (such as RabbitMQ, Kafka, or Azure Service Bus) to implement a more complex and scalable event-driven architecture).\n\n## Motivation\n\nOften when developing applications, it is necessary to implement a mechanism to notify other parts of the system about changes or events that occur in the application: several times the implementor ends up rewriting boilerplate code to manage the events and notifications.\n\nAt the present time, there are several ways to implement such a mechanism, such as using a message broker, a message queue, or a pub/sub system, but every organization should implement its own way to manage events and notifications.\n\nWith this small effort, we aim to provide a simple and lightweight framework that can be used to implement a common way to publish events in a .NET application.\n\n## CloudEvents Standard\n\nThe framework is designed to be compliant with the [CloudEvents](https://cloudevents.io/) standard, making use of the `CloudEvent` class to represent the reference model for the event.\n\nThis choice is made to ensure the maximum compatibility with other systems and services that are compliant with the standard, and to provide a simple and efficient way to serialize and deserialize events.\n\n## Installation\n\nThe framework is available as a NuGet package, and can be installed using the `dotnet` cli.\n\nFor example, to install the package that provides the publisher to the Azure Service Bus, you can run the following command:\n\n```bash\ndotnet add package Deveel.Events.Publisher.AzureServiceBus\n```\n\nAlternatively, you can use the NuGet package manager in Visual Studio to search and install the package.\n\n### Framework Packages\n\nPackages provided by the framework are:\n\n| Package | Description | NuGet Package | Pre-Release\u003cbr/\u003e(GitHub Packages) |\n|---------|-------------|---------------|-------------------------------|\n| `Deveel.Events.Annotations` | A set of attributes used to describe the metadata of an event | [![NuGet](https://img.shields.io/nuget/v/Deveel.Events.Annotations.svg)](https://www.nuget.org/packages/Deveel.Events.Annotations) | [![GitHub](https://img.shields.io/badge/nuget-prerelease-yellow?logo=nuget)](https://github.com/deveel/deveel.events/pkgs/nuget/Deveel.Events.Annotations) |\n| `Deveel.Events.Publisher` | The core framework for publishing events | [![NuGet](https://img.shields.io/nuget/v/Deveel.Events.Publisher.svg)](https://www.nuget.org/packages/Deveel.Events.Publisher) | [![GitHub](https://img.shields.io/badge/nuget-prerelease-yellow?logo=nuget)](https://github.com/deveel/deveel.events/pkgs/nuget/Deveel.Events.Publisher) |\n| `Deveel.Events.Publisher.AzureServiceBus` | An implementation of the publisher using Azure Service Bus | [![NuGet](https://img.shields.io/nuget/v/Deveel.Events.Publisher.AzureServiceBus.svg)](https://www.nuget.org/packages/Deveel.Events.Publisher.AzureServiceBus) | [![GitHub](https://img.shields.io/badge/nuget-prerelease-yellow?logo=nuget)](https://github.com/deveel/deveel.events/pkgs/nuget/Deveel.Events.Publisher.AzureServiceBus) |\n| `Deveel.Events.Amqp.Annotations` | A set of attributes used to describe the metadata of an event published in AMQP queues | [![NuGet](https://img.shields.io/nuget/v/Deveel.Events.Amqp.Annotations.svg)](https://www.nuget.org/packages/Deveel.Events.Amqp.Annotations) | [![GitHub](https://img.shields.io/badge/nuget-prerelease-yellow?logo=nuget)](https://github.com/deveel/deveel.events/pkgs/nuget/Deveel.Events.Amqp.Annotations) |\n| `Deveel.Events.Publisher.RabbitMq` | An implementation of the publisher using RabbitMQ as a channel | [![NuGet](https://img.shields.io/nuget/v/Deveel.Events.Publisher.RabbitMq.svg)](https://www.nuget.org/packages/Deveel.Events.Publisher.RabbitMq) | [![GitHub](https://img.shields.io/badge/nuget-prerelease-yellow?logo=nuget)](https://github.com/deveel/deveel.events/pkgs/nuget/Deveel.Events.Publisher.RabbitMq) |\n| `Deveel.Events.Schema` | Core schema model, fluent builder, JSON writer, and schema validation | [![NuGet](https://img.shields.io/nuget/v/Deveel.Events.Schema.svg)](https://www.nuget.org/packages/Deveel.Events.Schema) | [![GitHub](https://img.shields.io/badge/nuget-prerelease-yellow?logo=nuget)](https://github.com/deveel/deveel.events/pkgs/nuget/Deveel.Events.Schema) |\n| `Deveel.Events.Schema.Yaml` | Exports an event schema as a YAML document | [![NuGet](https://img.shields.io/nuget/v/Deveel.Events.Schema.Yaml.svg)](https://www.nuget.org/packages/Deveel.Events.Schema.Yaml) | [![GitHub](https://img.shields.io/badge/nuget-prerelease-yellow?logo=nuget)](https://github.com/deveel/deveel.events/pkgs/nuget/Deveel.Events.Schema.Yaml) |\n| `Deveel.Events.Schema.AsyncApi` | Exports one or more event schemas as an AsyncAPI 2.x document (JSON or YAML) | [![NuGet](https://img.shields.io/nuget/v/Deveel.Events.Schema.AsyncApi.svg)](https://www.nuget.org/packages/Deveel.Events.Schema.AsyncApi) | [![GitHub](https://img.shields.io/badge/nuget-prerelease-yellow?logo=nuget)](https://github.com/deveel/deveel.events/pkgs/nuget/Deveel.Events.Schema.AsyncApi) |\n\n## Usage\n\nThe basic usage of the framework is to create an event, publish it to a channel, and subscribe to the channel to receive the event.\n\nThe following example shows how to create an event, publish it to a channel, and subscribe to the channel to receive the event.\n\nTo enable this capability, you must first register the publisher in the service collection of your application:\n\n```csharp\nusing Deveel.Events;\n\nvar builder = WebApplication.CreateBuilder(args);\n\n// ...\n\nbuilder.Services.AddEventPublisher();\n```\n\nThen, you can create an event and publish it to a channel:\n\n```csharp\nusing Deveel.Events;\n\npublic class MyService {\n    private readonly IEventPublisher publisher;\n\n    public MyService(IEventPublisher publisher) {\n        this.publisher = publisher;\n    }\n\n    public async Task PublishEventAsync() {\n        var @event = new CloudEvent(\"com.example.myevent\", new Uri(\"http://example.com/events/123\"), \"Hello, World!\") {\n            ContentType = \"text/plain\",\n            DataSchema = new Uri(\"http://example.com/schema\"),\n            Source = new Uri(\"http://example.com\"),\n            Data = \"Hello, World!\"\n        };\n\n        await publisher.PublishEventAsync(@event);\n    }\n}\n```\n\nNote that the above example will publish the event to all the channels that are registered in the publisher.\n\n### Publishing from Event Data\n\nIf you have a class that represents the data of an event, you can use the `EventAttribute` to decorate such a class to describe the metadata of the event containing it.\n\nFor example, consider the following class:\n\n```csharp\nusing Deveel.Events.Annotations;\n\n[Event(\"com.example.myevent\", \"1.0\")]\npublic class MyEventData {\n    [Required]\n    public string Message { get; set; }\n}\n```\n\nYou can then publish an event using the data class:\n\n```csharp\nusing Deveel.Events;\n\npublic class MyService {\n    private readonly IEventPublisher publisher;\n\n    public MyService(IEventPublisher publisher) {\n        this.publisher = publisher;\n    }\n    \n    public async Task PublishEventAsync() {\n        var data = new MyEventData {\n            Message = \"Hello, World!\"\n        };\n        \n        await publisher.PublishAsync(data);\n    }\n}\n```\n\n## Event Schema\n\nThe `Deveel.Events.Schema` package provides a way to describe and validate the structure of events through schemas, ensuring that events conform to an expected contract.\n\n### Installation\n\n```bash\ndotnet add package Deveel.Events.Schema\n```\n\n### Creating a Schema with the Fluent Builder\n\nThe `EventSchema.Build()` factory method returns an `EventSchemaBuilder` that allows you to describe every aspect of an event schema in a fluent, readable style:\n\n```csharp\nusing Deveel.Events;\n\nvar schema = EventSchema.Build(\"order.placed\")\n    .WithVersion(\"1.0\")\n    .WithContentType(\"application/json\")\n    .WithDescription(\"Raised when a customer places an order\")\n    .AddProperty(\"order_id\",  \"guid\",   p =\u003e p.Required())\n    .AddProperty(\"amount\",    \"money\",  p =\u003e p.Required().WithRange\u003cdecimal\u003e(0m, 1_000_000m))\n    .AddProperty(\"currency\",  \"string\", p =\u003e p.Required())\n    .AddProperty(\"notes\",     \"string\", p =\u003e p.Nullable())\n    .Build();\n```\n\nYou can also describe a property with a configure delegate for richer control:\n\n```csharp\nvar schema = EventSchema.Build(\"user.registered\")\n    .WithVersion(\"1.0\")\n    .AddProperty(\"email\", p =\u003e p\n        .OfType(\"string\")\n        .Required()\n        .WithDescription(\"The email address of the new user\"))\n    .AddProperty(\"age\", p =\u003e p\n        .OfType(\"int\")\n        .WithRange\u003cint\u003e(18, 120))\n    .AddProperty(\"nickname\", p =\u003e p\n        .OfType(\"string\")\n        .Nullable())\n    .Build();\n```\n\n### Generating a Schema from an Annotated Class\n\nIf you already have a class decorated with `[Event]` and standard data-annotation attributes, you can derive the schema automatically without writing it by hand:\n\n```csharp\nusing System.ComponentModel.DataAnnotations;\nusing Deveel.Events.Annotations;\n\n[Event(\"order.placed\", \"1.0\")]\npublic class OrderPlacedData {\n    [Required]\n    public Guid OrderId { get; set; }\n\n    [Required]\n    [Range(0.0, 1_000_000.0)]\n    public decimal Amount { get; set; }\n\n    [Required]\n    public string Currency { get; set; } = default!;\n\n    public string? Notes { get; set; }\n}\n```\n\nUse the static helper to create the schema:\n\n```csharp\n// Via the static convenience method\nvar schema = EventSchema.FromDataType\u003cOrderPlacedData\u003e();\n\n// Or via the injectable factory (preferred in DI scenarios)\nusing Deveel.Events;\n\npublic class MyService {\n    private readonly IEventSchemaFactory schemaFactory;\n\n    public MyService(IEventSchemaFactory schemaFactory) {\n        this.schemaFactory = schemaFactory;\n    }\n\n    public EventSchema GetSchema() =\u003e schemaFactory.CreateFromType\u003cOrderPlacedData\u003e();\n}\n```\n\n### Exporting the Schema as JSON\n\nA schema can be serialised to a JSON stream with `EventSchemaJsonWriter`:\n\n```csharp\nusing Deveel.Events;\nusing System.Text.Json;\n\nvar schema = EventSchema.FromDataType\u003cOrderPlacedData\u003e();\n\nvar writer = new EventSchemaJsonWriter(new JsonWriterOptions { Indented = true });\n\nawait using var stream = File.OpenWrite(\"order-placed-schema.json\");\nawait writer.WriteToAsync(stream, schema);\n```\n\nThe output will look similar to:\n\n```json\n{\n  \"type\": \"order.placed\",\n  \"version\": \"1.0\",\n  \"contentType\": \"object\",\n  \"properties\": {\n    \"OrderId\": { \"dataType\": \"guid\", \"required\": true },\n    \"Amount\":  { \"dataType\": \"money\", \"required\": true, \"min\": 0, \"max\": 1000000 },\n    \"Currency\":{ \"dataType\": \"string\", \"required\": true },\n    \"Notes\":   { \"dataType\": \"string\", \"nullable\": true }\n  }\n}\n```\n\n### Exporting the Schema as YAML\n\nInstall the package:\n\n```bash\ndotnet add package Deveel.Events.Schema.Yaml\n```\n\nUse `EventSchemaYamlWriter` (which implements `IEventSchemaWriter`) to serialise a schema to a YAML stream:\n\n```csharp\nusing Deveel.Events;\n\nvar schema = EventSchema.FromDataType\u003cOrderPlacedData\u003e();\n\nvar writer = new EventSchemaYamlWriter();   // uses camelCase by default\n\nawait using var stream = File.OpenWrite(\"order-placed-schema.yaml\");\nawait writer.WriteToAsync(stream, schema);\n```\n\nThe output will look similar to:\n\n```yaml\ntype: order.placed\nversion: 1.0\ncontentType: object\nproperties:\n  orderId:\n    dataType: guid\n    required: true\n  amount:\n    dataType: money\n    required: true\n    min: 0\n    max: 1000000\n  currency:\n    dataType: string\n    required: true\n  notes:\n    dataType: string\n    nullable: true\n```\n\nYou can supply a custom `YamlDotNet.Serialization.ISerializer` to the constructor to control naming conventions, anchors, and other serialization options.\n\n### Exporting the Schema as AsyncAPI\n\nInstall the package:\n\n```bash\ndotnet add package Deveel.Events.Schema.AsyncApi\n```\n\n#### Single schema → standalone AsyncAPI document\n\n`EventSchemaAsyncApiWriter` wraps a single `IEventSchema` in a fully valid AsyncAPI 2.x document. It exposes the schema under `components/schemas`, declares a corresponding message under `components/messages`, and wires a subscribe channel:\n\n```csharp\nusing Deveel.Events;\n\nvar schema = EventSchema.FromDataType\u003cOrderPlacedData\u003e();\n\n// Output as JSON (default)\nvar writer = new EventSchemaAsyncApiWriter(\n    format: AsyncApiFormat.Json,\n    title: \"Order Events\",\n    documentVersion: \"1.0\");\n\nawait using var stream = File.OpenWrite(\"order-placed-asyncapi.json\");\nawait writer.WriteToAsync(stream, schema);\n```\n\nTo produce YAML instead, pass `AsyncApiFormat.Yaml`:\n\n```csharp\nvar writer = new EventSchemaAsyncApiWriter(AsyncApiFormat.Yaml);\n\nawait using var stream = File.OpenWrite(\"order-placed-asyncapi.yaml\");\nawait writer.WriteToAsync(stream, schema);\n```\n\n#### Multiple schemas → combined AsyncAPI document\n\n`EventSchemasAsyncApiWriter` merges several schemas into a single AsyncAPI document — useful for generating a service-wide contract file:\n\n```csharp\nusing Deveel.Events;\n\nIEnumerable\u003cIEventSchema\u003e schemas = new[] {\n    EventSchema.FromDataType\u003cOrderPlacedData\u003e(),\n    EventSchema.FromDataType\u003cOrderCancelledData\u003e(),\n    EventSchema.FromDataType\u003cUserRegisteredData\u003e()\n};\n\nvar writer = new EventSchemasAsyncApiWriter(\n    title: \"My Service Events\",\n    version: \"2.0\",\n    format: AsyncApiFormat.Yaml);\n\nawait using var stream = File.OpenWrite(\"events-asyncapi.yaml\");\nawait writer.WriteToAsync(stream, schemas);\n```\n\n#### Using the extension methods directly\n\nThe `EventSchemaAsyncApiExtensions` class exposes lower-level helpers when you need finer control:\n\n```csharp\nusing Deveel.Events;\nusing NJsonSchema;\nusing Saunter.AsyncApiSchema.v2;\n\nvar schema = EventSchema.FromDataType\u003cOrderPlacedData\u003e();\n\n// Convert to NJsonSchema\nJsonSchema jsonSchema = schema.ToJsonSchema();\n\n// Convert to an AsyncAPI Message\nMessage message = schema.ToAsyncApiMessage();\n\n// Build a standalone AsyncApiDocument\nAsyncApiDocument document = schema.ToAsyncApiDocument(title: \"Order Events\", version: \"1.0\");\n\n// Or add to an existing document\nvar existingDoc = new AsyncApiDocument { /* ... */ };\nexistingDoc.AddSchema(schema);\n```\n\n### Validating an Event Against a Schema\n\nThe `IEventSchemaValidator` service validates a `CloudEvent` instance against an `IEventSchema` and returns an asynchronous stream of `ValidationResult` objects — one per violated constraint.\n\n```csharp\nusing CloudNative.CloudEvents;\nusing Deveel.Events;\nusing System.ComponentModel.DataAnnotations;\n\npublic class OrderService {\n    private readonly IEventSchemaValidator validator;\n    private readonly IEventPublisher publisher;\n\n    public OrderService(IEventSchemaValidator validator, IEventPublisher publisher) {\n        this.validator = validator;\n        this.publisher = publisher;\n    }\n\n    public async Task PlaceOrderAsync(OrderPlacedData data) {\n        var schema = EventSchema.FromDataType\u003cOrderPlacedData\u003e();\n\n        var @event = new CloudEvent {\n            Type    = \"order.placed\",\n            Source  = new Uri(\"https://myapp.example.com/orders\"),\n            Data    = data\n        };\n\n        // Collect all validation errors before publishing\n        var errors = new List\u003cValidationResult\u003e();\n        await foreach (var result in validator.ValidateEventAsync(schema, @event)) {\n            errors.Add(result);\n        }\n\n        if (errors.Count \u003e 0) {\n            var messages = string.Join(\", \", errors.Select(e =\u003e e.ErrorMessage));\n            throw new InvalidOperationException($\"Event is invalid: {messages}\");\n        }\n\n        await publisher.PublishAsync(data);\n    }\n}\n```\n\n\u003e **Tip:** Register the validator (and the schema factory) via the DI container by including the `Deveel.Events.Schema` services in your `IServiceCollection`.\n\n## Future Work\n\nThe framework is still in its early stages, and there are several areas that need to be improved and extended.\n\nSome of the areas that we plan to work on in the future are:\n\n- Supporting custom event serializers and deserializers\n- Implementing more publishers for different messaging systems (eg. RabbitMQ, Kafka, etc.)\n- Supporting the deserialization of events from channels, to make consistent the published events are consumed\n- Allow the selection of the channel to publish an event among the registered ones (eg. with named channels)\n\nYou can monitor the list of [open issues](https://github.com/deveel/deveel.events/issues) to see what we are working on and what we plan to do in the future.\n\n## Contributing\n\nWe welcome contributions to the project, and we encourage you to submit issues and pull requests to help us improve the framework.\n\nIf you want to contribute to the project, please read the [Contributing Guidelines](CONTRIBUTING.md) file to understand how to contribute to the project.\n\n## License\n\nThe project is released under the [MIT License](LICENSE), and it is free to use and distribute for any purpose.\n\nSee the [License](LICENSE) file for more information.\n\n## Authors\n\nThe project is developed and maintained by the [Deveel](https://deveel.com) team, and it is released as an open-source project to the community.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdeveel%2Fdeveel.events","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdeveel%2Fdeveel.events","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdeveel%2Fdeveel.events/lists"}