Particular / NServiceBus

Build, version, and monitor better microservices with the most powerful service platform for .NET
https://particular.net/nservicebus/
Other
2.07k stars 650 forks source link

Dispatch binary messages in incoming message context via `ReadOnlyMemory<Char>` or `Stream` #7069

Open ramonsmits opened 4 weeks ago

ramonsmits commented 4 weeks ago

Is your feature related to a problem? Please describe.

I tried to send a custom serialized message satellite queue but this is just not possible. You can obtain a IMessageDispatcher but that does not batch messages as part of an incoming message context.

Describe the requested feature

I my use case I'm not that interested in needing to limit the headers. I'm fine with the headers as long as additional headers can still be added via for example SendOptions and its only specific to just send binary data:

Having these APIs would allow to very efficiently send binary payloads that do not require serialization. No point to serialize a binary in a message with a single byte[] property to JSON as Base64 encoded. Serializer overhead and payload bloat

Send ReadOnlyMemory<byte>:

async Task Send(string address, ReadOnlyMemory<byte> body, SendOptions sendOptions);

Send Stream:

async Task Send(string address, Stream body, SendOptions sendOptions);

Claim check pattern

It allows to send files that fit the transports its maximum message payload. In my case its not needed but we could even apply the claim check pattern via databus if the binary payload does not fit the transport its message size limit.

Receiving

Such payloads can be processed via RAW endpoints.

It would also be nice if such payloads could be received via handlers. This is just some pseudo code but not really required.

interface IHandleBinaryMessage
{
    Task Handle(ReadOnlyMemory<byte> body, MessageContext context);
}

class EnclosedMessageTypeAttribute : Attribute
{
    public EnclosedMessageTypeAttribute(string name)
    {
    }
    public EnclosedMessageTypeAttribute(Type type)
    {
    }
}

[MapToEnclosedMessageType("MyMessageTypeKey")]
public Task Handle : IHandleBinaryMessage
{
    public async Task Handle(ReadOnlyMemory<byte> body, MessageContext context)
    {
        await File.WriteAllBytes("myfile.txt", body);
    }
}

// or map to an existing type!

[MapToEnclosedMessageType(typeof(MySpecialMessage))]
public Task Handle : IHandleBinaryMessage
{
    public async Task Handle(ReadOnlyMemory<byte> body, MessageContext context)
    {
        await File.WriteAllBytes("myfile.txt", body);
    }
}

Describe alternatives you've considered

Transport operations

Sending ReadOnlyMemory<byte> would pretty much be achieved if the API could allow sending TransportOperation or maybe a bit less heavy OutgoingMessage:

A spike exists that does a bit of RAW handling:

Additional Context

No response