cloudevents / cloudevents/sdk-csharp
Whats the suggested way to declare strongly typed events? (And why is CloudEvent sealed?)
Nobody has claimed this yet.
- Dominant language
- C#
- Stars
- 334
- Forks
- 88
- Avg merge
- 7m
- Merged PRs (30d)
- 2
Description
Hi all,
I have bee working in event-driven architectures using RabbitMQ for the last years, and the approach, for relatively small products, is that the project that owns an event is declaring the event in a separate project like (oversimplifying):
public record MyEvent(string topic, ..., MyPayload payload) : BaseEvent { ... }
A library receives the instance and serializes it all to publish it to RabbitMQ. And on the subscribing side, it uses the class definition to deserialize the string and pass it onto the subscription.
This allows all actors (publishers, subscribers, tests, etc) to use a single definition for a single event while freeing all the code from serialization, deserialization and casting.
I am looking to migrate this implementation to CloudEvents, so the first thing I thought about was:
public record BaseEvent<T> : CloudEvent
{
// constructor...
// json attribute
public TPayload Payload {get:}
}
But CloudEvent is sealed :(
My first alternative is to declare my BaseEvent with operators to cast to and from CloudEvent:
using CloudNative.CloudEvents;
using System.Text.Json;
public abstract record BaseEvent<TPayload>
{
public string Id { get; init; } = Guid.NewGuid().ToString();
public string Type { get; init; }
public Uri Source { get; init; }
public string Subject { get; init; }
public DateTimeOffset Time { get; init; } = DateTimeOffset.UtcNow;
public TPayload Data { get; init; }
protected BaseEvent(TPayload data, string source, string type, string subject = null)
{
Data = data;
Source = new Uri(source);
Type = type;
Subject = subject;
}
public static implicit operator CloudEvent(BaseEvent<TPayload> baseEvent)
{
return new CloudEvent
{
Id = baseEvent.Id,
Type = baseEvent.Type,
Source = baseEvent.Source,
Subject = baseEvent.Subject,
Time = baseEvent.Time,
Data = JsonSerializer.Serialize(baseEvent.Data),
DataContentType = "application/json"
};
}
public static implicit operator BaseEvent<TPayload>(CloudEvent cloudEvent)
{
var data = JsonSerializer.Deserialize<TPayload>(cloudEvent.Data.ToString());
var baseEvent = Activator.CreateInstance(typeof(BaseEvent<TPayload>), data, cloudEvent.Source.ToString(), cloudEvent.Type, cloudEvent.Subject) as BaseEvent<TPayload>;
baseEvent.Id = cloudEvent.Id;
baseEvent.Time = cloudEvent.Time.Value;
return baseEvent;
}
}
But before I move forward, I am double checking:
- What would be the proposed way to declare cloud events strongly typed?
An additionally:
- Why is
CloudEventsealed? - Why is it a class and not a record?
Thanks
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
No repository files, tests, or implementation entry points are identified. Start by reviewing the CloudEvent API and the strongly typed BaseEvent and conversion approach shown in the issue. Done means providing a settled recommendation for strongly typed declarations and explaining the sealed-class and class-versus-record design choices.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp, rabbitmq
- Domain
- backend, distributed-systems
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100