diff --git a/Directory.Build.props b/Directory.Build.props
index 0841373d3..f5e37e1f8 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -60,6 +60,10 @@
cobertura,json
[*.Benchmarks]*,[*Sample*]*,[*Test*]*,[xunit.*]*
+
+
+ 0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7
+
diff --git a/Directory.Packages.props b/Directory.Packages.props
index ee1f7015e..39d61c9b7 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -1,9 +1,9 @@
-
+
-
+
@@ -11,7 +11,7 @@
-
+
@@ -19,14 +19,14 @@
+
-
-
+
diff --git a/samples/src/JustSaying.Sample.Restaurant.KitchenConsole/Program.cs b/samples/src/JustSaying.Sample.Restaurant.KitchenConsole/Program.cs
index d9a8e61ae..55d22fbf3 100644
--- a/samples/src/JustSaying.Sample.Restaurant.KitchenConsole/Program.cs
+++ b/samples/src/JustSaying.Sample.Restaurant.KitchenConsole/Program.cs
@@ -97,7 +97,7 @@ static async Task Run()
config.Publications(x =>
{
// Creates the following if they do not already exist
- // - a SNS topic of name `orderreadyevent` with two tags:
+ // - an SNS topic of name `orderreadyevent` with two tags:
// - "IsOrderEvent" with no value
// - "Publisher" with the value "KitchenConsole"
x.WithTopic(cfg =>
diff --git a/src/JustSaying.Extensions.DependencyInjection.Microsoft/IServiceCollectionExtensions.cs b/src/JustSaying.Extensions.DependencyInjection.Microsoft/IServiceCollectionExtensions.cs
index a9d7c5af0..81d4a5862 100644
--- a/src/JustSaying.Extensions.DependencyInjection.Microsoft/IServiceCollectionExtensions.cs
+++ b/src/JustSaying.Extensions.DependencyInjection.Microsoft/IServiceCollectionExtensions.cs
@@ -5,6 +5,7 @@
using JustSaying.Fluent;
using JustSaying.Messaging;
using JustSaying.Messaging.Channels.Receive;
+using JustSaying.Messaging.Compression;
using JustSaying.Messaging.MessageHandling;
using JustSaying.Messaging.MessageSerialization;
using JustSaying.Messaging.Middleware.Logging;
@@ -139,16 +140,11 @@ public static IServiceCollection AddJustSaying(this IServiceCollection services,
services.TryAddSingleton(serviceProvider => serviceProvider.GetRequiredService());
services.TryAddSingleton(serviceProvider => serviceProvider.GetRequiredService());
- services.TryAddSingleton();
+ services.TryAddSingleton();
services.TryAddSingleton();
services.TryAddSingleton();
- services.TryAddSingleton(
- (p) =>
- {
- var config = p.GetRequiredService();
- var serializerFactory = p.GetRequiredService();
- return new MessageSerializationRegister(config.MessageSubjectProvider, serializerFactory);
- });
+ services.TryAddEnumerable(ServiceDescriptor.Singleton());
+ services.TryAddSingleton();
services.TryAddSingleton();
diff --git a/src/JustSaying.Extensions.DependencyInjection.StructureMap/JustSayingRegistry.cs b/src/JustSaying.Extensions.DependencyInjection.StructureMap/JustSayingRegistry.cs
index 59be6c2df..df909488e 100644
--- a/src/JustSaying.Extensions.DependencyInjection.StructureMap/JustSayingRegistry.cs
+++ b/src/JustSaying.Extensions.DependencyInjection.StructureMap/JustSayingRegistry.cs
@@ -2,6 +2,7 @@
using JustSaying.AwsTools.QueueCreation;
using JustSaying.Fluent;
using JustSaying.Messaging.Channels.Receive;
+using JustSaying.Messaging.Compression;
using JustSaying.Messaging.MessageHandling;
using JustSaying.Messaging.MessageSerialization;
using JustSaying.Messaging.Middleware.Logging;
@@ -9,6 +10,7 @@
using JustSaying.Messaging.Monitoring;
using JustSaying.Naming;
using StructureMap;
+using StructureMap.Pipeline;
namespace JustSaying;
@@ -33,7 +35,7 @@ public JustSayingRegistry()
For().Use(context => context.GetInstance()).Singleton();
For().Use(context => context.GetInstance()).Singleton();
For().Use().Singleton();
- For().Use().Singleton();
+ For().Use().Singleton();
For().Use().Singleton();
For().Use().Singleton();
@@ -43,18 +45,8 @@ public JustSayingRegistry()
For().Transient();
For().Transient();
-
- For()
- .Use(
- nameof(IMessageSerializationRegister),
- (p) =>
- {
- var config = p.GetInstance();
- var serializerFactory = p.GetInstance();
- return new MessageSerializationRegister(config.MessageSubjectProvider, serializerFactory);
- })
- .Singleton();
-
+ For().Add().Singleton();
+ For().Singleton();
For().Use().Singleton();
For().Singleton();
diff --git a/src/JustSaying/AwsTools/MessageAttributeKeys.cs b/src/JustSaying/AwsTools/MessageAttributeKeys.cs
new file mode 100644
index 000000000..1370f7218
--- /dev/null
+++ b/src/JustSaying/AwsTools/MessageAttributeKeys.cs
@@ -0,0 +1,12 @@
+namespace JustSaying.AwsTools;
+
+///
+/// Contains constant key values for message attributes.
+///
+internal static class MessageAttributeKeys
+{
+ ///
+ /// Represents the key for the Content-Encoding attribute.
+ ///
+ public const string ContentEncoding = "Content-Encoding";
+}
diff --git a/src/JustSaying/AwsTools/MessageHandling/Compression/PublishCompressionOptions.cs b/src/JustSaying/AwsTools/MessageHandling/Compression/PublishCompressionOptions.cs
new file mode 100644
index 000000000..6b26914af
--- /dev/null
+++ b/src/JustSaying/AwsTools/MessageHandling/Compression/PublishCompressionOptions.cs
@@ -0,0 +1,26 @@
+using JustSaying.Messaging.Compression;
+
+namespace JustSaying.AwsTools.MessageHandling;
+
+///
+/// Represents options for message compression during publishing.
+///
+public sealed class PublishCompressionOptions
+{
+ ///
+ /// Gets or sets the message length threshold in bytes.
+ /// Messages larger than this threshold will be compressed.
+ ///
+ ///
+ /// The default value is 260,096 bytes (254 KB), 2KB less than the SNS and SQS limit.
+ ///
+ public int MessageLengthThreshold { get; set; } = 254 * 1024;
+
+ ///
+ /// Gets or sets the compression encoding to be used.
+ ///
+ ///
+ /// This should correspond to a registered compression algorithm in the .
+ ///
+ public string CompressionEncoding { get; set; }
+}
diff --git a/src/JustSaying/AwsTools/MessageHandling/Dispatch/IMessageDispatcher.cs b/src/JustSaying/AwsTools/MessageHandling/Dispatch/IMessageDispatcher.cs
index bb48f7f1b..f4353e422 100644
--- a/src/JustSaying/AwsTools/MessageHandling/Dispatch/IMessageDispatcher.cs
+++ b/src/JustSaying/AwsTools/MessageHandling/Dispatch/IMessageDispatcher.cs
@@ -5,7 +5,7 @@ namespace JustSaying.AwsTools.MessageHandling.Dispatch;
///
/// Dispatches messages to the queue.
///
-public interface IMessageDispatcher
+internal interface IMessageDispatcher
{
///
/// Dispatches the message in to the queue in the context.
@@ -14,4 +14,4 @@ public interface IMessageDispatcher
/// A to stop processing the message dispatch.
/// A that completes once the message has been dispatched.
Task DispatchMessageAsync(IQueueMessageContext messageContext, CancellationToken cancellationToken);
-}
\ No newline at end of file
+}
diff --git a/src/JustSaying/AwsTools/MessageHandling/Dispatch/MessageDispatcher.cs b/src/JustSaying/AwsTools/MessageHandling/Dispatch/MessageDispatcher.cs
index 83b6f5c27..f7e96a919 100644
--- a/src/JustSaying/AwsTools/MessageHandling/Dispatch/MessageDispatcher.cs
+++ b/src/JustSaying/AwsTools/MessageHandling/Dispatch/MessageDispatcher.cs
@@ -8,21 +8,18 @@
namespace JustSaying.AwsTools.MessageHandling.Dispatch;
-public class MessageDispatcher : IMessageDispatcher
+internal sealed class MessageDispatcher : IMessageDispatcher
{
- private readonly IMessageSerializationRegister _serializationRegister;
private readonly IMessageMonitor _messagingMonitor;
private readonly MiddlewareMap _middlewareMap;
- private static ILogger _logger;
+ private readonly ILogger _logger;
public MessageDispatcher(
- IMessageSerializationRegister serializationRegister,
IMessageMonitor messagingMonitor,
MiddlewareMap middlewareMap,
ILoggerFactory loggerFactory)
{
- _serializationRegister = serializationRegister;
_messagingMonitor = messagingMonitor;
_middlewareMap = middlewareMap;
_logger = loggerFactory.CreateLogger("JustSaying");
@@ -42,6 +39,7 @@ public async Task DispatchMessageAsync(
if (!success)
{
+ _logger.LogTrace("DeserializeMessage failed. Message will not be dispatched.");
return;
}
@@ -68,7 +66,6 @@ public async Task DispatchMessageAsync(
await middleware.RunAsync(handleContext, null, cancellationToken)
.ConfigureAwait(false);
-
}
private async Task<(bool success, Message typedMessage, MessageAttributes attributes)>
@@ -76,10 +73,11 @@ await middleware.RunAsync(handleContext, null, cancellationToken)
{
try
{
- _logger.LogDebug("Attempting to deserialize message with serialization register {Type}",
- _serializationRegister.GetType().FullName);
- var messageWithAttributes = _serializationRegister.DeserializeMessage(messageContext.Message.Body);
- return (true, messageWithAttributes.Message, messageWithAttributes.MessageAttributes);
+ _logger.LogDebug("Attempting to deserialize message.");
+
+ var (message, attributes) = await messageContext.MessageConverter.ConvertToInboundMessageAsync(messageContext.Message, cancellationToken);
+
+ return (true, message, attributes);
}
catch (MessageFormatNotSupportedException ex)
{
@@ -93,6 +91,11 @@ await middleware.RunAsync(handleContext, null, cancellationToken)
return (false, null, null);
}
+ catch (OperationCanceledException)
+ {
+ // Ignore cancellation
+ return (false, null, null);
+ }
catch (Exception ex)
{
_logger.LogError(
diff --git a/src/JustSaying/AwsTools/MessageHandling/ForeignTopicArnProvider.cs b/src/JustSaying/AwsTools/MessageHandling/ForeignTopicArnProvider.cs
index 40afe039d..1a36f393f 100644
--- a/src/JustSaying/AwsTools/MessageHandling/ForeignTopicArnProvider.cs
+++ b/src/JustSaying/AwsTools/MessageHandling/ForeignTopicArnProvider.cs
@@ -2,17 +2,10 @@
namespace JustSaying.AwsTools.MessageHandling;
-internal class ForeignTopicArnProvider(RegionEndpoint regionEndpoint, string accountId, string topicName) : ITopicArnProvider
+internal class ForeignTopicArnProvider(RegionEndpoint regionEndpoint, string accountId, string topicName)
{
-
private readonly string _arn = $"arn:aws:sns:{regionEndpoint.SystemName}:{accountId}:{topicName}";
- public Task ArnExistsAsync()
- {
- // Assume foreign topics exist, we actually find out when we attempt to subscribe
- return Task.FromResult(true);
- }
-
public Task GetArnAsync()
{
return Task.FromResult(_arn);
diff --git a/src/JustSaying/AwsTools/MessageHandling/IInboundMessageConverter.cs b/src/JustSaying/AwsTools/MessageHandling/IInboundMessageConverter.cs
new file mode 100644
index 000000000..c175fb443
--- /dev/null
+++ b/src/JustSaying/AwsTools/MessageHandling/IInboundMessageConverter.cs
@@ -0,0 +1,18 @@
+using JustSaying.Messaging.MessageSerialization;
+
+namespace JustSaying.Messaging;
+
+public interface IInboundMessageConverter
+{
+ ///
+ /// Converts an Amazon SQS message to a object.
+ ///
+ /// The Amazon SQS message to convert.
+ /// A token to monitor for cancellation requests.
+ /// A object containing the deserialized message body and attributes.
+ ///
+ /// This method handles the conversion of both raw SQS messages and SNS-wrapped messages.
+ /// It also applies any necessary decompression to the message body.
+ ///
+ ValueTask ConvertToInboundMessageAsync(Amazon.SQS.Model.Message message, CancellationToken cancellationToken = default);
+}
diff --git a/src/JustSaying/AwsTools/MessageHandling/IOutboundMessageConverter.cs b/src/JustSaying/AwsTools/MessageHandling/IOutboundMessageConverter.cs
new file mode 100644
index 000000000..cc20d09aa
--- /dev/null
+++ b/src/JustSaying/AwsTools/MessageHandling/IOutboundMessageConverter.cs
@@ -0,0 +1,27 @@
+using JustSaying.Messaging.MessageSerialization;
+using JustSaying.Models;
+
+namespace JustSaying.Messaging;
+
+public interface IOutboundMessageConverter
+{
+ ///
+ /// Converts a message to a format suitable for publishing, applying necessary transformations and compression.
+ ///
+ /// The original message to be converted.
+ /// Metadata associated with the publish operation, including any custom message attributes.
+ /// A token to monitor for cancellation requests.
+ /// A object containing the converted message body, attributes, and any additional publishing information.
+ ///
+ /// This method handles the following operations:
+ ///
+ /// - Serializes the message body
+ /// - Adds custom message attributes
+ /// - Applies compression to the message body if it meets specified criteria
+ /// - Adds compression-related attributes if compression is applied
+ /// - Prepares the message for SNS (if applicable) by setting the subject
+ ///
+ /// The exact behavior may vary based on the destination type and compression options.
+ ///
+ ValueTask ConvertToOutboundMessageAsync(Message message, PublishMetadata publishMetadata, CancellationToken cancellationToken = default);
+}
diff --git a/src/JustSaying/AwsTools/MessageHandling/ISqsQueue.cs b/src/JustSaying/AwsTools/MessageHandling/ISqsQueue.cs
index 97bf4dc6d..01b033001 100644
--- a/src/JustSaying/AwsTools/MessageHandling/ISqsQueue.cs
+++ b/src/JustSaying/AwsTools/MessageHandling/ISqsQueue.cs
@@ -76,4 +76,4 @@ Task ChangeMessageVisibilityAsync(
int visibilityTimeoutInSeconds,
CancellationToken cancellationToken);
-}
\ No newline at end of file
+}
diff --git a/src/JustSaying/AwsTools/MessageHandling/ITopicArnProvider.cs b/src/JustSaying/AwsTools/MessageHandling/ITopicArnProvider.cs
deleted file mode 100644
index c2b1a5cd8..000000000
--- a/src/JustSaying/AwsTools/MessageHandling/ITopicArnProvider.cs
+++ /dev/null
@@ -1,7 +0,0 @@
-namespace JustSaying.AwsTools.MessageHandling;
-
-internal interface ITopicArnProvider
-{
- Task ArnExistsAsync();
- Task GetArnAsync();
-}
\ No newline at end of file
diff --git a/src/JustSaying/AwsTools/MessageHandling/InboundMessageConverter.cs b/src/JustSaying/AwsTools/MessageHandling/InboundMessageConverter.cs
new file mode 100644
index 000000000..fe9844c70
--- /dev/null
+++ b/src/JustSaying/AwsTools/MessageHandling/InboundMessageConverter.cs
@@ -0,0 +1,148 @@
+using System.Text;
+using System.Text.Json;
+using System.Text.Json.Nodes;
+using JustSaying.AwsTools;
+using JustSaying.Messaging.Compression;
+using JustSaying.Messaging.MessageHandling;
+using JustSaying.Messaging.MessageSerialization;
+
+namespace JustSaying.Messaging;
+
+internal sealed class InboundMessageConverter : IInboundMessageConverter
+{
+ private readonly IMessageBodySerializer _bodySerializer;
+ private readonly MessageCompressionRegistry _compressionRegistry;
+ private readonly bool _isRawMessage;
+
+ public InboundMessageConverter(IMessageBodySerializer bodySerializer, MessageCompressionRegistry compressionRegistry, bool isRawMessage)
+ {
+ _bodySerializer = bodySerializer;
+ _compressionRegistry = compressionRegistry;
+ _isRawMessage = isRawMessage;
+ }
+
+ public ValueTask ConvertToInboundMessageAsync(Amazon.SQS.Model.Message message, CancellationToken cancellationToken = default)
+ {
+ string body = message.Body;
+ var attributes = GetMessageAttributes(message, body);
+
+ if (body is not null && !_isRawMessage)
+ {
+ var jsonNode = JsonNode.Parse(body);
+ if (jsonNode is JsonObject jsonObject && jsonObject.TryGetPropertyValue("Message", out var messageNode))
+ {
+ body = messageNode?.GetValue();
+ }
+ }
+ body = ApplyBodyDecompression(body, attributes);
+ var result = _bodySerializer.Deserialize(body);
+ return new ValueTask(new InboundMessage(result, attributes));
+ }
+
+ private string ApplyBodyDecompression(string body, MessageAttributes attributes)
+ {
+ var contentEncoding = attributes.Get(MessageAttributeKeys.ContentEncoding);
+ if (contentEncoding is not null)
+ {
+ var decompressor = _compressionRegistry.GetCompression(contentEncoding.StringValue);
+ if (decompressor is null)
+ {
+ throw new InvalidOperationException($"Compression encoding '{contentEncoding.StringValue}' is not registered.");
+ }
+
+ body = decompressor.Decompress(body);
+ }
+
+ return body;
+ }
+
+ private static MessageAttributes GetMessageAttributes(Amazon.SQS.Model.Message message, string body)
+ {
+ return IsSnsPayload(body) ? GetMessageAttributes(body) : GetRawMessageAttributes(message);
+ }
+
+ private static MessageAttributes GetMessageAttributes(string message)
+ {
+ using var jsonDocument = JsonDocument.Parse(message);
+
+ if (!jsonDocument.RootElement.TryGetProperty("MessageAttributes", out var attributesElement))
+ {
+ return new MessageAttributes();
+ }
+
+ Dictionary attributes = new();
+ foreach (var property in attributesElement.EnumerateObject())
+ {
+ var dataType = property.Value.GetProperty("Type").GetString();
+ var dataValue = property.Value.GetProperty("Value").GetString();
+
+ attributes.Add(property.Name, ParseMessageAttribute(dataType, dataValue));
+ }
+
+ return new MessageAttributes(attributes);
+ }
+
+ private static MessageAttributeValue ParseMessageAttribute(string dataType, string dataValue)
+ {
+ // Check for a prefix instead of an exact match as SQS supports custom-type labels, or example, "Binary.gif".
+ // See https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-message-metadata.html#sqs-message-attributes.
+ bool isBinary = dataType?.StartsWith("Binary", StringComparison.Ordinal) is true;
+
+ return new()
+ {
+ DataType = dataType,
+ StringValue = !isBinary ? dataValue : null,
+ BinaryValue = isBinary ? Convert.FromBase64String(dataValue) : null
+ };
+ }
+
+ private static MessageAttributes GetRawMessageAttributes(Amazon.SQS.Model.Message message)
+ {
+ if (message.MessageAttributes is null)
+ {
+ return new MessageAttributes();
+ }
+
+ Dictionary rawAttributes = new ();
+
+ foreach (var messageMessageAttribute in message.MessageAttributes)
+ {
+ var dataType = messageMessageAttribute.Value.DataType;
+ var dataValue = messageMessageAttribute.Value.StringValue;
+ rawAttributes.Add(messageMessageAttribute.Key, ParseMessageAttribute(dataType, dataValue));
+ }
+
+ return new MessageAttributes(rawAttributes);
+ }
+
+ private static bool IsSnsPayload(string body)
+ {
+ if (body is null)
+ {
+ return false;
+ }
+
+ try
+ {
+ var utf8JsonReader = new Utf8JsonReader(Encoding.UTF8.GetBytes(body));
+ if (!JsonDocument.TryParseValue(ref utf8JsonReader, out var jsonDocument))
+ {
+ return false;
+ }
+
+ using (jsonDocument)
+ {
+ if (jsonDocument.RootElement.TryGetProperty("Type", out var typeElement))
+ {
+ return typeElement.GetString() is "Notification";
+ }
+ }
+ }
+ catch
+ {
+ // ignored
+ }
+
+ return false;
+ }
+}
diff --git a/src/JustSaying/AwsTools/MessageHandling/LocalTopicArnProvider.cs b/src/JustSaying/AwsTools/MessageHandling/LocalTopicArnProvider.cs
deleted file mode 100644
index ffe5a49e5..000000000
--- a/src/JustSaying/AwsTools/MessageHandling/LocalTopicArnProvider.cs
+++ /dev/null
@@ -1,44 +0,0 @@
-using Amazon.SimpleNotificationService;
-
-namespace JustSaying.AwsTools.MessageHandling;
-
-internal class LocalTopicArnProvider : ITopicArnProvider
-{
- private readonly IAmazonSimpleNotificationService _client;
- private readonly Lazy> _lazyGetArnAsync;
- private bool _exists;
-
- public LocalTopicArnProvider(IAmazonSimpleNotificationService client, string topicName)
- {
- _client = client;
-
- _lazyGetArnAsync = new Lazy>(() => GetArnInternalAsync(topicName));
- }
-
- private async Task GetArnInternalAsync(string topicName)
- {
- try
- {
- var topic = await _client.FindTopicAsync(topicName).ConfigureAwait(false);
-
- _exists = true;
- return topic.TopicArn;
- }
- catch (Exception)
- {
- // ignored
- }
- return null;
- }
-
- public Task GetArnAsync()
- {
- return _lazyGetArnAsync.Value;
- }
-
- public async Task ArnExistsAsync()
- {
- _ = await _lazyGetArnAsync.Value.ConfigureAwait(false);
- return _exists;
- }
-}
diff --git a/src/JustSaying/AwsTools/MessageHandling/OutboundMessageConverter.cs b/src/JustSaying/AwsTools/MessageHandling/OutboundMessageConverter.cs
new file mode 100644
index 000000000..e991ec95b
--- /dev/null
+++ b/src/JustSaying/AwsTools/MessageHandling/OutboundMessageConverter.cs
@@ -0,0 +1,163 @@
+using System.Text;
+using System.Text.Json.Nodes;
+using JustSaying.AwsTools;
+using JustSaying.AwsTools.MessageHandling;
+using JustSaying.Messaging.Compression;
+using JustSaying.Messaging.MessageSerialization;
+using JustSaying.Models;
+
+namespace JustSaying.Messaging;
+
+internal sealed class OutboundMessageConverter : IOutboundMessageConverter
+{
+ private readonly PublishDestinationType _destinationType;
+ private readonly IMessageBodySerializer _bodySerializer;
+ private readonly MessageCompressionRegistry _compressionRegistry;
+ private readonly PublishCompressionOptions _compressionOptions;
+ private readonly string _subject;
+ private readonly bool _isRawMessage;
+
+ public OutboundMessageConverter(
+ PublishDestinationType destinationType,
+ IMessageBodySerializer bodySerializer,
+ MessageCompressionRegistry compressionRegistry,
+ PublishCompressionOptions compressionOptions,
+ string subject,
+ bool isRawMessage)
+ {
+ _destinationType = destinationType;
+ _bodySerializer = bodySerializer;
+ _compressionRegistry = compressionRegistry;
+ _compressionOptions = compressionOptions;
+ _subject = subject;
+ _isRawMessage = isRawMessage;
+ }
+
+ public ValueTask ConvertToOutboundMessageAsync(Message message, PublishMetadata publishMetadata, CancellationToken cancellationToken = default)
+ {
+ var messageBody = _bodySerializer.Serialize(message);
+
+ Dictionary attributeValues = new();
+ AddMessageAttributes(attributeValues, publishMetadata);
+
+ (string compressedMessage, string contentEncoding) = CompressMessageBody(messageBody, publishMetadata);
+ if (compressedMessage is not null)
+ {
+ messageBody = compressedMessage;
+ attributeValues.Add(MessageAttributeKeys.ContentEncoding, new MessageAttributeValue { DataType = "String", StringValue = contentEncoding });
+ }
+
+ if (_destinationType == PublishDestinationType.Queue && !_isRawMessage)
+ {
+ messageBody = new JsonObject
+ {
+ ["Message"] = messageBody,
+ ["Subject"] = _subject
+ }.ToJsonString();
+ }
+
+ return new ValueTask(new OutboundMessage(messageBody, attributeValues, _subject));
+ }
+
+ private static void AddMessageAttributes(Dictionary requestMessageAttributes, PublishMetadata metadata)
+ {
+ if (metadata?.MessageAttributes == null || metadata.MessageAttributes.Count == 0)
+ {
+ return;
+ }
+
+ foreach (var attribute in metadata.MessageAttributes)
+ {
+ requestMessageAttributes.Add(attribute.Key, attribute.Value);
+ }
+ }
+
+ ///
+ /// Compresses a message if it meets the specified compression criteria.
+ ///
+ /// The original message to potentially compress.
+ /// Metadata associated with the message.
+ /// A tuple containing the compressed message (or null if not compressed) and the content encoding used (or null if not compressed).
+ internal (string compressedMessage, string contentEncoding) CompressMessageBody(string message, PublishMetadata metadata)
+ {
+ string contentEncoding = null;
+ string compressedMessage = null;
+
+ if (_compressionOptions?.CompressionEncoding is { } compressionEncoding && _compressionRegistry is not null)
+ {
+ var messageSize = CalculateTotalMessageSize(message, metadata);
+ if (messageSize >= _compressionOptions.MessageLengthThreshold)
+ {
+ var compression = _compressionRegistry.GetCompression(compressionEncoding);
+ if (compression is null)
+ {
+ throw new InvalidOperationException($"No compression algorithm registered for encoding '{compressionEncoding}'.");
+ }
+
+ // For queue messages that aren't raw, we need to extract the inner message before compression
+ if (_destinationType == PublishDestinationType.Queue && !_isRawMessage)
+ {
+ var jsonNode = JsonNode.Parse(message);
+ if (jsonNode is JsonObject jsonObject && jsonObject.TryGetPropertyValue("Message", out var messageNode))
+ {
+ message = messageNode?.GetValue();
+ }
+ }
+
+ compressedMessage = compression.Compress(message);
+ contentEncoding = compressionEncoding;
+ }
+ }
+
+ return (compressedMessage, contentEncoding);
+ }
+
+ ///
+ /// Calculates the total size of a message, including its metadata.
+ ///
+ /// The message content.
+ /// Metadata associated with the message.
+ /// The total size of the message in bytes.
+ private int CalculateTotalMessageSize(string message, PublishMetadata metadata)
+ {
+ int messageSize = 0;
+
+ // For queue messages that aren't raw, we need to account for the wrapper structure
+ if (_destinationType == PublishDestinationType.Queue && !_isRawMessage)
+ {
+ // Calculate size of the wrapper object with escaped message
+ var wrappedMessage = new JsonObject
+ {
+ ["Message"] = message,
+ ["Subject"] = _subject
+ }.ToJsonString();
+
+ messageSize = Encoding.UTF8.GetByteCount(wrappedMessage);
+ }
+ else
+ {
+ // For non-queue or raw messages, just calculate the direct message size
+ messageSize = Encoding.UTF8.GetByteCount(message);
+ }
+
+ if (metadata?.MessageAttributes != null)
+ {
+ foreach (var attribute in metadata.MessageAttributes)
+ {
+ messageSize += Encoding.UTF8.GetByteCount(attribute.Key);
+ messageSize += Encoding.UTF8.GetByteCount(attribute.Value.DataType);
+ if (attribute.Value.StringValue is not null)
+ {
+ messageSize += Encoding.UTF8.GetByteCount(attribute.Value.StringValue);
+ }
+
+ if (attribute.Value.BinaryValue is not null)
+ {
+ messageSize += attribute.Value.BinaryValue.Count;
+ }
+ }
+ }
+
+ return messageSize;
+ }
+}
diff --git a/src/JustSaying/AwsTools/MessageHandling/PublishDestinationType.cs b/src/JustSaying/AwsTools/MessageHandling/PublishDestinationType.cs
new file mode 100644
index 000000000..40502f8c3
--- /dev/null
+++ b/src/JustSaying/AwsTools/MessageHandling/PublishDestinationType.cs
@@ -0,0 +1,7 @@
+namespace JustSaying.AwsTools.MessageHandling;
+
+internal enum PublishDestinationType
+{
+ Topic = 1,
+ Queue = 2
+}
diff --git a/src/JustSaying/AwsTools/MessageHandling/SnsMessagePublisher.cs b/src/JustSaying/AwsTools/MessageHandling/SnsMessagePublisher.cs
index ad7624860..a67a7df36 100644
--- a/src/JustSaying/AwsTools/MessageHandling/SnsMessagePublisher.cs
+++ b/src/JustSaying/AwsTools/MessageHandling/SnsMessagePublisher.cs
@@ -3,50 +3,38 @@
using Amazon.SimpleNotificationService.Model;
using JustSaying.Messaging;
using JustSaying.Messaging.Interrogation;
-using JustSaying.Messaging.MessageSerialization;
using JustSaying.Models;
using Microsoft.Extensions.Logging;
using MessageAttributeValue = Amazon.SimpleNotificationService.Model.MessageAttributeValue;
namespace JustSaying.AwsTools.MessageHandling;
-public class SnsMessagePublisher : IMessagePublisher, IMessageBatchPublisher, IInterrogable
+internal sealed class SnsMessagePublisher(
+ IAmazonSimpleNotificationService client,
+ IOutboundMessageConverter messageConverter,
+ ILoggerFactory loggerFactory,
+ Func handleException,
+ Func, bool> handleBatchException) : IMessagePublisher, IMessageBatchPublisher, IInterrogable
{
- private readonly IMessageSerializationRegister _serializationRegister;
- private readonly IMessageSubjectProvider _messageSubjectProvider;
- private readonly Func _handleException;
- private readonly ILogger _logger;
-
- public Func, bool> HandleBatchException { get; set; }
+ private readonly IOutboundMessageConverter _messageConverter = messageConverter;
+ private readonly Func _handleException = handleException;
+ private readonly Func, bool> _handleBatchException = handleBatchException;
+ private readonly IAmazonSimpleNotificationService _client = client;
+ private readonly ILogger _logger = loggerFactory.CreateLogger("JustSaying.Publish");
public Action MessageResponseLogger { get; set; }
public Action> MessageBatchResponseLogger { get; set; }
public string Arn { get; internal set; }
- protected IAmazonSimpleNotificationService Client { get; }
-
- public SnsMessagePublisher(
- IAmazonSimpleNotificationService client,
- IMessageSerializationRegister serializationRegister,
- ILoggerFactory loggerFactory,
- IMessageSubjectProvider messageSubjectProvider,
- Func handleException = null)
- : this(null, client, serializationRegister, loggerFactory, messageSubjectProvider, handleException)
- {
- }
public SnsMessagePublisher(
string topicArn,
IAmazonSimpleNotificationService client,
- IMessageSerializationRegister serializationRegister,
+ IOutboundMessageConverter messageConverter,
ILoggerFactory loggerFactory,
- IMessageSubjectProvider messageSubjectProvider,
- Func handleException = null)
+ Func handleException,
+ Func, bool> handleBatchException)
+ : this(client, messageConverter, loggerFactory, handleException, handleBatchException)
{
Arn = topicArn;
- Client = client;
- _serializationRegister = serializationRegister;
- _logger = loggerFactory.CreateLogger("JustSaying.Publish");
- _handleException = handleException;
- _messageSubjectProvider = messageSubjectProvider;
}
public Task StartAsync(CancellationToken cancellationToken) => Task.CompletedTask;
@@ -56,11 +44,11 @@ public Task PublishAsync(Message message, CancellationToken cancellationToken)
public async Task PublishAsync(Message message, PublishMetadata metadata, CancellationToken cancellationToken)
{
- var request = BuildPublishRequest(message, metadata);
+ var request = await BuildPublishRequestAsync(message, metadata);
PublishResponse response = null;
try
{
- response = await Client.PublishAsync(request, cancellationToken).ConfigureAwait(false);
+ response = await _client.PublishAsync(request, cancellationToken).ConfigureAwait(false);
}
catch (AmazonServiceException ex)
{
@@ -96,30 +84,33 @@ public async Task PublishAsync(Message message, PublishMetadata metadata, Cancel
private bool ClientExceptionHandler(Exception ex, Message message) => _handleException?.Invoke(ex, message) ?? false;
- private PublishRequest BuildPublishRequest(Message message, PublishMetadata metadata)
+ private async Task BuildPublishRequestAsync(Message message, PublishMetadata metadata)
{
- string messageToSend = _serializationRegister.Serialize(message, serializeForSnsPublishing: true);
- string messageType = _messageSubjectProvider.GetSubjectForType(message.GetType());
+ var (messageToSend, attributes, subject) = await _messageConverter.ConvertToOutboundMessageAsync(message, metadata);
- return new PublishRequest
+ var request = new PublishRequest
{
TopicArn = Arn,
- Subject = messageType,
+ Subject = subject,
Message = messageToSend,
- MessageAttributes = BuildMessageAttributes(metadata)
};
+
+ AddMessageAttributes(request.MessageAttributes, attributes);
+
+ return request;
}
- private static Dictionary BuildMessageAttributes(PublishMetadata metadata)
+ private static void AddMessageAttributes(Dictionary requestMessageAttributes, Dictionary attributes)
{
- if (metadata?.MessageAttributes == null || metadata.MessageAttributes.Count == 0)
+ if (attributes == null || attributes.Count == 0)
{
- return null;
+ return;
}
- return metadata.MessageAttributes.ToDictionary(
- source => source.Key,
- source => BuildMessageAttributeValue(source.Value));
+ foreach (var attribute in attributes)
+ {
+ requestMessageAttributes.Add(attribute.Key, BuildMessageAttributeValue(attribute.Value));
+ }
}
private static MessageAttributeValue BuildMessageAttributeValue(Messaging.MessageAttributeValue value)
@@ -142,7 +133,7 @@ private static MessageAttributeValue BuildMessageAttributeValue(Messaging.Messag
}
///
- public virtual InterrogationResult Interrogate()
+ public InterrogationResult Interrogate()
{
return new InterrogationResult(new { Arn });
}
@@ -155,12 +146,12 @@ public async Task PublishAsync(IEnumerable messages, PublishBatchMetada
foreach (var chunk in messages.Chunk(size))
{
- var request = BuildPublishBatchRequest(chunk, metadata);
+ var request = await BuildPublishBatchRequestAsync(chunk, metadata);
PublishBatchResponse response = null;
try
{
- response = await Client.PublishBatchAsync(request, cancellationToken).ConfigureAwait(false);
+ response = await _client.PublishBatchAsync(request, cancellationToken).ConfigureAwait(false);
}
catch (AmazonServiceException ex)
{
@@ -232,25 +223,26 @@ public async Task PublishAsync(IEnumerable messages, PublishBatchMetada
}
private bool ClientExceptionHandler(Exception ex, IReadOnlyCollection messages)
- => HandleBatchException?.Invoke(ex, messages) ?? false;
+ => _handleBatchException?.Invoke(ex, messages) ?? false;
- private PublishBatchRequest BuildPublishBatchRequest(Message[] messages, PublishMetadata metadata)
+ private async Task BuildPublishBatchRequestAsync(Message[] messages, PublishMetadata metadata)
{
var entries = new List(messages.Length);
foreach (var message in messages)
{
- string subject = _messageSubjectProvider.GetSubjectForType(message.GetType());
- string payload = _serializationRegister.Serialize(message, serializeForSnsPublishing: true);
- var attributes = BuildMessageAttributes(metadata);
+ var (messageToSend, attributes, subject) = await _messageConverter.ConvertToOutboundMessageAsync(message, metadata);
- entries.Add(new()
+ PublishBatchRequestEntry request = new()
{
Id = message.UniqueKey(),
Subject = subject,
- Message = payload,
- MessageAttributes = attributes,
- });
+ Message = messageToSend,
+ };
+
+ AddMessageAttributes(request.MessageAttributes, attributes);
+
+ entries.Add(request);
}
return new PublishBatchRequest
diff --git a/src/JustSaying/AwsTools/MessageHandling/SqsMessagePublisher.cs b/src/JustSaying/AwsTools/MessageHandling/SqsMessagePublisher.cs
index 282094c62..be2832af9 100644
--- a/src/JustSaying/AwsTools/MessageHandling/SqsMessagePublisher.cs
+++ b/src/JustSaying/AwsTools/MessageHandling/SqsMessagePublisher.cs
@@ -3,15 +3,15 @@
using Amazon.SQS.Model;
using JustSaying.Messaging;
using JustSaying.Messaging.Interrogation;
-using JustSaying.Messaging.MessageSerialization;
using Microsoft.Extensions.Logging;
using Message = JustSaying.Models.Message;
+using MessageAttributeValue = Amazon.SQS.Model.MessageAttributeValue;
namespace JustSaying.AwsTools.MessageHandling;
-public class SqsMessagePublisher(
+internal sealed class SqsMessagePublisher(
IAmazonSQS client,
- IMessageSerializationRegister serializationRegister,
+ OutboundMessageConverter messageConverter,
ILoggerFactory loggerFactory) : IMessagePublisher, IMessageBatchPublisher
{
private readonly ILogger _logger = loggerFactory.CreateLogger("JustSaying.Publish");
@@ -23,8 +23,8 @@ public class SqsMessagePublisher(
public SqsMessagePublisher(
Uri queueUrl,
IAmazonSQS client,
- IMessageSerializationRegister serializationRegister,
- ILoggerFactory loggerFactory) : this(client, serializationRegister, loggerFactory)
+ OutboundMessageConverter messageConverter,
+ ILoggerFactory loggerFactory) : this(client, messageConverter, loggerFactory)
{
QueueUrl = queueUrl;
}
@@ -41,7 +41,7 @@ public async Task PublishAsync(Message message, PublishMetadata metadata, Cancel
{
EnsureQueueUrl();
- var request = BuildSendMessageRequest(message, metadata);
+ var request = await BuildSendMessageRequestAsync(message, metadata);
SendMessageResponse response;
try
{
@@ -76,14 +76,18 @@ public async Task PublishAsync(Message message, PublishMetadata metadata, Cancel
}
}
- private SendMessageRequest BuildSendMessageRequest(Message message, PublishMetadata metadata)
+ private async Task BuildSendMessageRequestAsync(Message message, PublishMetadata metadata)
{
+ var (messageBody, attributes, _) = await messageConverter.ConvertToOutboundMessageAsync(message, metadata);
+
var request = new SendMessageRequest
{
- MessageBody = GetMessageInContext(message),
- QueueUrl = QueueUrl.AbsoluteUri,
+ MessageBody = messageBody,
+ QueueUrl = QueueUrl.AbsoluteUri
};
+ AddMessageAttributes(request.MessageAttributes, attributes);
+
if (metadata?.Delay != null)
{
request.DelaySeconds = (int)metadata.Delay.Value.TotalSeconds;
@@ -92,7 +96,37 @@ private SendMessageRequest BuildSendMessageRequest(Message message, PublishMetad
return request;
}
- public string GetMessageInContext(Message message) => serializationRegister.Serialize(message, serializeForSnsPublishing: false);
+ private static void AddMessageAttributes(Dictionary requestMessageAttributes, Dictionary messageAttributes)
+ {
+ if (messageAttributes == null || messageAttributes.Count == 0)
+ {
+ return;
+ }
+
+ foreach (var attribute in messageAttributes)
+ {
+ requestMessageAttributes.Add(attribute.Key, BuildMessageAttributeValue(attribute.Value));
+ }
+ }
+
+ private static MessageAttributeValue BuildMessageAttributeValue(Messaging.MessageAttributeValue value)
+ {
+ if (value == null)
+ {
+ return null;
+ }
+
+ var binaryValueStream = value.BinaryValue != null
+ ? new MemoryStream([.. value.BinaryValue], false)
+ : null;
+
+ return new MessageAttributeValue
+ {
+ StringValue = value.StringValue,
+ BinaryValue = binaryValueStream,
+ DataType = value.DataType
+ };
+ }
///
public InterrogationResult Interrogate()
@@ -113,7 +147,7 @@ public async Task PublishAsync(IEnumerable messages, PublishBatchMetada
foreach (var chunk in messages.Chunk(size))
{
- var request = BuildSendMessageBatchRequest(chunk, metadata);
+ var request = await BuildSendMessageBatchRequestAsync(chunk, metadata);
SendMessageBatchResponse response;
try
{
@@ -184,19 +218,23 @@ public async Task PublishAsync(IEnumerable messages, PublishBatchMetada
}
}
- private SendMessageBatchRequest BuildSendMessageBatchRequest(Message[] messages, PublishMetadata metadata)
+ private async Task BuildSendMessageBatchRequestAsync(Message[] messages, PublishMetadata metadata)
{
var entries = new List(messages.Length);
int? delaySeconds = metadata?.Delay is { } delay ? (int)delay.TotalSeconds : null;
foreach (var message in messages)
{
+ var (messageBody, attributes, _) = await messageConverter.ConvertToOutboundMessageAsync(message, metadata);
+
var entry = new SendMessageBatchRequestEntry
{
Id = message.UniqueKey(),
- MessageBody = GetMessageInContext(message),
+ MessageBody = messageBody
};
+ AddMessageAttributes(entry.MessageAttributes, attributes);
+
if (delaySeconds is { } value)
{
entry.DelaySeconds = value;
diff --git a/src/JustSaying/AwsTools/MessageHandling/SqsQueueReader.cs b/src/JustSaying/AwsTools/MessageHandling/SqsQueueReader.cs
index 0a33a5410..00e001868 100644
--- a/src/JustSaying/AwsTools/MessageHandling/SqsQueueReader.cs
+++ b/src/JustSaying/AwsTools/MessageHandling/SqsQueueReader.cs
@@ -1,4 +1,5 @@
using Amazon.SQS.Model;
+using JustSaying.Messaging;
using JustSaying.Messaging.Channels.Context;
namespace JustSaying.AwsTools.MessageHandling;
@@ -6,10 +7,12 @@ namespace JustSaying.AwsTools.MessageHandling;
internal class SqsQueueReader
{
private readonly ISqsQueue _sqsQueue;
+ private readonly IInboundMessageConverter _messageConverter;
- internal SqsQueueReader(ISqsQueue sqsQueue)
+ internal SqsQueueReader(ISqsQueue sqsQueue, IInboundMessageConverter messageConverter)
{
_sqsQueue = sqsQueue;
+ _messageConverter = messageConverter;
}
internal string QueueName => _sqsQueue.QueueName;
@@ -20,7 +23,7 @@ internal SqsQueueReader(ISqsQueue sqsQueue)
internal IQueueMessageContext ToMessageContext(Message message)
{
- return new QueueMessageContext(message, this);
+ return new QueueMessageContext(message, this, _messageConverter);
}
internal async Task> GetMessagesAsync(
@@ -57,4 +60,4 @@ await _sqsQueue.ChangeMessageVisibilityAsync(
(int)timeout.TotalSeconds,
cancellationToken).ConfigureAwait(false);
}
-}
\ No newline at end of file
+}
diff --git a/src/JustSaying/AwsTools/QueueCreation/AmazonQueueCreator.cs b/src/JustSaying/AwsTools/QueueCreation/AmazonQueueCreator.cs
index 69c773c55..ce3ec74b1 100644
--- a/src/JustSaying/AwsTools/QueueCreation/AmazonQueueCreator.cs
+++ b/src/JustSaying/AwsTools/QueueCreation/AmazonQueueCreator.cs
@@ -33,7 +33,8 @@ await SubscribeQueueAndApplyFilterPolicyAsync(snsClient,
topicArn,
sqsClient,
queue.Uri,
- queueConfig.FilterPolicy).ConfigureAwait(false);
+ queueConfig.FilterPolicy,
+ queueConfig.RawMessageDelivery).ConfigureAwait(false);
}
else
{
@@ -46,7 +47,8 @@ await SubscribeQueueAndApplyFilterPolicyAsync(snsClient,
eventTopic.Arn,
sqsClient,
queue.Uri,
- queueConfig.FilterPolicy).ConfigureAwait(false);
+ queueConfig.FilterPolicy,
+ queueConfig.RawMessageDelivery).ConfigureAwait(false);
var sqsDetails = new SqsPolicyDetails
{
@@ -94,7 +96,8 @@ private static async Task SubscribeQueueAndApplyFilterPolicyAsync(
string topicArn,
IAmazonSQS amazonSQS,
Uri queueUrl,
- string filterPolicy)
+ string filterPolicy,
+ bool rawMessageDelivery)
{
if (amazonSimpleNotificationService == null) throw new ArgumentNullException(nameof(amazonSimpleNotificationService));
if (amazonSQS == null) throw new ArgumentNullException(nameof(amazonSQS));
@@ -110,5 +113,8 @@ private static async Task SubscribeQueueAndApplyFilterPolicyAsync(
await amazonSimpleNotificationService
.SetSubscriptionAttributesAsync(subscriptionArn, "FilterPolicy", actualFilterPolicy)
.ConfigureAwait(false);
+ await amazonSimpleNotificationService
+ .SetSubscriptionAttributesAsync(subscriptionArn, "RawMessageDelivery", rawMessageDelivery.ToString().ToLowerInvariant())
+ .ConfigureAwait(false);
}
}
diff --git a/src/JustSaying/AwsTools/QueueCreation/RedrivePolicy.cs b/src/JustSaying/AwsTools/QueueCreation/RedrivePolicy.cs
index ea6b1af25..b43e9894a 100644
--- a/src/JustSaying/AwsTools/QueueCreation/RedrivePolicy.cs
+++ b/src/JustSaying/AwsTools/QueueCreation/RedrivePolicy.cs
@@ -1,15 +1,13 @@
+using System.Text.Json;
using System.Text.Json.Serialization;
-using Newtonsoft.Json;
namespace JustSaying.AwsTools.QueueCreation;
-public class RedrivePolicy
+internal sealed class RedrivePolicy
{
- [JsonProperty("maxReceiveCount")]
[JsonPropertyName("maxReceiveCount")]
public int MaximumReceives { get; set; }
- [JsonProperty("deadLetterTargetArn")]
[JsonPropertyName("deadLetterTargetArn")]
public string DeadLetterQueue { get; set; }
@@ -19,15 +17,9 @@ public RedrivePolicy(int maximumReceives, string deadLetterQueue)
DeadLetterQueue = deadLetterQueue;
}
- protected RedrivePolicy()
- {
- }
-
- // Cannot use System.Text.Json below as no public parameterless constructor. Change for v7?
-
public override string ToString()
- => JsonConvert.SerializeObject(this);
+ => JsonSerializer.Serialize(this);
public static RedrivePolicy ConvertFromString(string policy)
- => JsonConvert.DeserializeObject(policy);
-}
\ No newline at end of file
+ => JsonSerializer.Deserialize(policy);
+}
diff --git a/src/JustSaying/AwsTools/QueueCreation/SnsWriteConfiguration.cs b/src/JustSaying/AwsTools/QueueCreation/SnsWriteConfiguration.cs
index ffd472189..5cead5cb5 100644
--- a/src/JustSaying/AwsTools/QueueCreation/SnsWriteConfiguration.cs
+++ b/src/JustSaying/AwsTools/QueueCreation/SnsWriteConfiguration.cs
@@ -1,14 +1,54 @@
+using JustSaying.AwsTools.MessageHandling;
using JustSaying.Models;
namespace JustSaying.AwsTools.QueueCreation;
+///
+/// Represents the configuration for writing messages to Amazon SNS (Simple Notification Service).
+///
public class SnsWriteConfiguration
{
+ private string _subject;
+
+ ///
+ /// Gets or sets the server-side encryption settings for the SNS topic.
+ ///
public ServerSideEncryption Encryption { get; set; }
///
- /// Extension point enabling custom error handling on a per notification basis, including ability handle raised exceptions.
+ /// Gets or sets the compression options for publishing messages.
+ ///
+ public PublishCompressionOptions CompressionOptions { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether the message should be treated as a raw message.
+ ///
+ public bool IsRawMessage { get; set; }
+
+ ///
+ /// Gets or sets the subject of the SNS message.
+ ///
+ public string Subject
+ {
+ get => _subject;
+ set
+ {
+ _subject = value;
+ SubjectSet = true;
+ }
+ }
+
+ ///
+ /// Internal property to track whether the Subject has been set.
+ ///
+ internal bool SubjectSet { get; private set; }
+
+ ///
+ /// Gets or sets a delegate for custom error handling on a per-notification basis.
///
- /// Boolean indicating whether the exception has been handled
+ ///
+ /// This is an extension point enabling custom error handling, including the ability to handle raised exceptions.
+ ///
+ /// A function that takes an Exception and a Message as parameters and returns a boolean indicating whether the exception has been handled.
public Func HandleException { get; set; }
-}
\ No newline at end of file
+}
diff --git a/src/JustSaying/AwsTools/QueueCreation/SqsBasicConfiguration.cs b/src/JustSaying/AwsTools/QueueCreation/SqsBasicConfiguration.cs
index 0e84aa3ec..c3b3c00ed 100644
--- a/src/JustSaying/AwsTools/QueueCreation/SqsBasicConfiguration.cs
+++ b/src/JustSaying/AwsTools/QueueCreation/SqsBasicConfiguration.cs
@@ -1,16 +1,19 @@
+using JustSaying.AwsTools.MessageHandling;
+using JustSaying.Fluent;
using JustSaying.Naming;
namespace JustSaying.AwsTools.QueueCreation;
public class SqsBasicConfiguration
{
- public TimeSpan MessageRetention { get; set; }
- public TimeSpan ErrorQueueRetentionPeriod { get; set; }
- public TimeSpan VisibilityTimeout { get; set; }
- public TimeSpan DeliveryDelay { get; set; }
- public int RetryCountBeforeSendingToErrorQueue { get; set; }
+ public TimeSpan MessageRetention { get; set; } = JustSayingConstants.DefaultRetentionPeriod;
+ public TimeSpan ErrorQueueRetentionPeriod { get; set; } = JustSayingConstants.MaximumRetentionPeriod;
+ public TimeSpan VisibilityTimeout { get; set; } = JustSayingConstants.DefaultVisibilityTimeout;
+ public TimeSpan DeliveryDelay { get; set; } = JustSayingConstants.MinimumDeliveryDelay;
+ public int RetryCountBeforeSendingToErrorQueue { get; set; } = JustSayingConstants.DefaultHandlerRetryCount;
public bool ErrorQueueOptOut { get; set; }
public ServerSideEncryption ServerSideEncryption { get; set; }
+ public bool IsRawMessage { get; set; }
public string QueueName { get; set; }
public void ApplyQueueNamingConvention(IQueueNamingConvention namingConvention)
@@ -18,15 +21,6 @@ public void ApplyQueueNamingConvention(IQueueNamingConvention namingConventio
QueueName = namingConvention.Apply(QueueName);
}
- public SqsBasicConfiguration()
- {
- MessageRetention = JustSayingConstants.DefaultRetentionPeriod;
- ErrorQueueRetentionPeriod = JustSayingConstants.MaximumRetentionPeriod;
- VisibilityTimeout = JustSayingConstants.DefaultVisibilityTimeout;
- RetryCountBeforeSendingToErrorQueue = JustSayingConstants.DefaultHandlerRetryCount;
- DeliveryDelay = JustSayingConstants.MinimumDeliveryDelay;
- }
-
public void Validate()
{
if (MessageRetention < JustSayingConstants.MinimumRetentionPeriod ||
diff --git a/src/JustSaying/AwsTools/QueueCreation/SqsReadConfiguration.cs b/src/JustSaying/AwsTools/QueueCreation/SqsReadConfiguration.cs
index 67ccfe989..f3f3c9b66 100644
--- a/src/JustSaying/AwsTools/QueueCreation/SqsReadConfiguration.cs
+++ b/src/JustSaying/AwsTools/QueueCreation/SqsReadConfiguration.cs
@@ -1,3 +1,4 @@
+using JustSaying.Models;
using JustSaying.Naming;
namespace JustSaying.AwsTools.QueueCreation;
@@ -20,9 +21,10 @@ public SqsReadConfiguration(SubscriptionType subscriptionType)
public Dictionary Tags { get; set; }
public string TopicSourceAccount { get; set; }
public string FilterPolicy { get; set; }
+ public bool RawMessageDelivery { get; set; }
public string SubscriptionGroupName { get; set; }
- public void ApplyTopicNamingConvention(ITopicNamingConvention namingConvention)
+ public void ApplyTopicNamingConvention(ITopicNamingConvention namingConvention) where T: Message
{
TopicName = namingConvention.Apply(TopicName);
}
@@ -48,4 +50,4 @@ protected override void OnValidating()
throw new ConfigurationErrorsException("You must provide a name for the subscription group");
}
}
-}
\ No newline at end of file
+}
diff --git a/src/JustSaying/AwsTools/QueueCreation/SqsWriteConfiguration.cs b/src/JustSaying/AwsTools/QueueCreation/SqsWriteConfiguration.cs
index d92be8c99..cfc4d0eef 100644
--- a/src/JustSaying/AwsTools/QueueCreation/SqsWriteConfiguration.cs
+++ b/src/JustSaying/AwsTools/QueueCreation/SqsWriteConfiguration.cs
@@ -1,12 +1,8 @@
+using JustSaying.AwsTools.MessageHandling;
+
namespace JustSaying.AwsTools.QueueCreation;
public class SqsWriteConfiguration : SqsBasicConfiguration
{
- public SqsWriteConfiguration()
- {
- MessageRetention = JustSayingConstants.DefaultRetentionPeriod;
- ErrorQueueRetentionPeriod = JustSayingConstants.MaximumRetentionPeriod;
- VisibilityTimeout = JustSayingConstants.DefaultVisibilityTimeout;
- RetryCountBeforeSendingToErrorQueue = JustSayingConstants.DefaultHandlerRetryCount;
- }
-}
\ No newline at end of file
+ public PublishCompressionOptions CompressionOptions { get; set; }
+}
diff --git a/src/JustSaying/Extensions/AmazonSqsClientExtensions.cs b/src/JustSaying/Extensions/AmazonSqsClientExtensions.cs
index 12e92b775..0eba033bc 100644
--- a/src/JustSaying/Extensions/AmazonSqsClientExtensions.cs
+++ b/src/JustSaying/Extensions/AmazonSqsClientExtensions.cs
@@ -25,7 +25,8 @@ public static async Task> ReceiveMessagesAsync(this IAmazonSQS cl
{
MessageSystemAttributeNames = [.. attributesToLoad],
WaitTimeSeconds = secondsWaitTime,
- MaxNumberOfMessages = maxNumOfMessages
+ MaxNumberOfMessages = maxNumOfMessages,
+ MessageAttributeNames = ["All"]
},
cancellationToken).ConfigureAwait(false);
diff --git a/src/JustSaying/Fluent/AccountAddressProvider.cs b/src/JustSaying/Fluent/AccountAddressProvider.cs
index 8523ff2c5..165a04652 100644
--- a/src/JustSaying/Fluent/AccountAddressProvider.cs
+++ b/src/JustSaying/Fluent/AccountAddressProvider.cs
@@ -106,9 +106,7 @@ public Uri GetQueueUriByConvention()
/// The for this queue.
public Uri GetQueueUri(string queueName)
{
-#pragma warning disable CS0618 // Type or member is obsolete
- var hostname = _regionEndpoint.GetEndpointForService("sqs").Hostname;
-#pragma warning restore CS0618 // Type or member is obsolete
+ var hostname = SqsEndpointHelper.GetSqsHostname(_regionEndpoint.PartitionName, _regionEndpoint.SystemName);
return new UriBuilder(Uri.UriSchemeHttps, hostname)
{
Path = $"{_accountId}/{queueName}"
diff --git a/src/JustSaying/Fluent/CompressionEncodingValidator.cs b/src/JustSaying/Fluent/CompressionEncodingValidator.cs
new file mode 100644
index 000000000..357852418
--- /dev/null
+++ b/src/JustSaying/Fluent/CompressionEncodingValidator.cs
@@ -0,0 +1,18 @@
+using JustSaying.AwsTools.MessageHandling;
+using JustSaying.Messaging.Compression;
+
+namespace JustSaying.Fluent;
+
+internal static class CompressionEncodingValidator
+{
+ public static void ValidateEncoding(MessageCompressionRegistry compressionRegistry, PublishCompressionOptions compressionOptions)
+ {
+ if (compressionOptions?.CompressionEncoding is { } compressionEncoding)
+ {
+ if (compressionRegistry.GetCompression(compressionEncoding) is null)
+ {
+ throw new InvalidOperationException($"Compression encoding '{compressionEncoding}' is not registered with the bus.");
+ }
+ }
+ }
+}
diff --git a/src/JustSaying/Fluent/PublishConfig/StaticPublicationConfiguration.cs b/src/JustSaying/Fluent/PublishConfig/StaticPublicationConfiguration.cs
index cf62dcddd..7cf07cb07 100644
--- a/src/JustSaying/Fluent/PublishConfig/StaticPublicationConfiguration.cs
+++ b/src/JustSaying/Fluent/PublishConfig/StaticPublicationConfiguration.cs
@@ -2,6 +2,8 @@
using JustSaying.AwsTools.MessageHandling;
using JustSaying.AwsTools.QueueCreation;
using JustSaying.Messaging;
+using JustSaying.Messaging.Compression;
+using JustSaying.Models;
using Microsoft.Extensions.Logging;
#pragma warning disable CS0618
@@ -23,7 +25,7 @@ public static StaticPublicationConfiguration Build(
SnsWriteConfiguration writeConfiguration,
IAmazonSimpleNotificationService snsClient,
ILoggerFactory loggerFactory,
- JustSayingBus bus)
+ JustSayingBus bus) where T : Message
{
var readConfiguration = new SqsReadConfiguration(SubscriptionType.ToTopic)
{
@@ -32,11 +34,17 @@ public static StaticPublicationConfiguration Build(
readConfiguration.ApplyTopicNamingConvention(bus.Config.TopicNamingConvention);
+ var compressionOptions = writeConfiguration.CompressionOptions ?? bus.Config.DefaultCompressionOptions;
+ var serializer = bus.MessageBodySerializerFactory.GetSerializer();
+ var subjectProvider = bus.Config.MessageSubjectProvider;
+ var subject = writeConfiguration.SubjectSet ? writeConfiguration.Subject : subjectProvider.GetSubjectForType(typeof(T));
+
var eventPublisher = new SnsMessagePublisher(
snsClient,
- bus.SerializationRegister,
+ new OutboundMessageConverter(PublishDestinationType.Topic, serializer, new MessageCompressionRegistry([new GzipMessageBodyCompression()]), compressionOptions, subject, writeConfiguration.IsRawMessage),
loggerFactory,
- bus.Config.MessageSubjectProvider)
+ null,
+ null)
{
MessageResponseLogger = bus.Config.MessageResponseLogger,
MessageBatchResponseLogger = bus.PublishBatchConfiguration?.MessageBatchResponseLogger
diff --git a/src/JustSaying/Fluent/QueueAddress.cs b/src/JustSaying/Fluent/QueueAddress.cs
index 8b3ab01e2..cceae0e79 100644
--- a/src/JustSaying/Fluent/QueueAddress.cs
+++ b/src/JustSaying/Fluent/QueueAddress.cs
@@ -1,5 +1,6 @@
using System.Text.RegularExpressions;
using Amazon;
+using Amazon.SQS;
namespace JustSaying.Fluent;
@@ -79,11 +80,7 @@ public static QueueAddress FromArn(string queueArn)
if (!Arn.TryParse(queueArn, out var arn)) throw new ArgumentException("Must be a valid ARN.", nameof(queueArn));
if (!string.Equals(arn.Service, "sqs", StringComparison.OrdinalIgnoreCase)) throw new ArgumentException("Must be an ARN for an SQS queue.", nameof(queueArn));
-#pragma warning disable CS0618 // Type or member is obsolete
- var hostname = RegionEndpoint.GetBySystemName(arn.Region)
- .GetEndpointForService("sqs")
- .Hostname;
-#pragma warning restore CS0618 // Type or member is obsolete
+ var hostname = SqsEndpointHelper.GetSqsHostname(arn.Partition, arn.Region);
var queueUrl = new UriBuilder("https", hostname)
{
diff --git a/src/JustSaying/Fluent/QueueAddressConfiguration.cs b/src/JustSaying/Fluent/QueueAddressConfiguration.cs
index b0a4d28d7..94df7441d 100644
--- a/src/JustSaying/Fluent/QueueAddressConfiguration.cs
+++ b/src/JustSaying/Fluent/QueueAddressConfiguration.cs
@@ -1,11 +1,9 @@
-using JustSaying.Messaging.Middleware;
-
namespace JustSaying.Fluent;
public sealed class QueueAddressConfiguration
{
public string SubscriptionGroupName { get; set; }
- public Action MiddlewareConfiguration { get; set; }
+ public bool RawMessageDelivery { get; set; }
public void Validate()
{
diff --git a/src/JustSaying/Fluent/QueueAddressPublicationBuilder`1.cs b/src/JustSaying/Fluent/QueueAddressPublicationBuilder`1.cs
index bbbb689a1..98c2b5446 100644
--- a/src/JustSaying/Fluent/QueueAddressPublicationBuilder`1.cs
+++ b/src/JustSaying/Fluent/QueueAddressPublicationBuilder`1.cs
@@ -1,6 +1,8 @@
using Amazon;
using JustSaying.AwsTools;
using JustSaying.AwsTools.MessageHandling;
+using JustSaying.Messaging;
+using JustSaying.Messaging.Compression;
using JustSaying.Models;
using Microsoft.Extensions.Logging;
@@ -16,6 +18,10 @@ public sealed class QueueAddressPublicationBuilder : IPublicationBuilder
where T : Message
{
private readonly QueueAddress _queueAddress;
+ private PublishCompressionOptions _compressionOptions;
+ private string _subject;
+ private bool _subjectSet;
+ private bool _isRawMessage;
///
/// Initializes a new instance of the class.
@@ -26,6 +32,40 @@ internal QueueAddressPublicationBuilder(QueueAddress queueAddress)
_queueAddress = queueAddress;
}
+ ///
+ /// Sets the compression options for publishing messages.
+ ///
+ /// The compression options to use when publishing messages.
+ /// The current instance of for method chaining.
+ /// Thrown when is null.
+ public QueueAddressPublicationBuilder WithCompression(PublishCompressionOptions compressionOptions)
+ {
+ _compressionOptions = compressionOptions ?? throw new ArgumentNullException(nameof(compressionOptions));
+ return this;
+ }
+
+ ///
+ /// Sets the subject for the message.
+ ///
+ /// The subject to set for the message.
+ /// The current instance of for method chaining.
+ public QueueAddressPublicationBuilder WithSubject(string subject)
+ {
+ _subject = subject;
+ _subjectSet = true;
+ return this;
+ }
+
+ ///
+ /// Sets the message to be published as a raw message.
+ ///
+ /// The current instance of for method chaining.
+ public QueueAddressPublicationBuilder WithRawMessages()
+ {
+ _isRawMessage = true;
+ return this;
+ }
+
///
public void Configure(JustSayingBus bus, IAwsClientFactoryProxy proxy, ILoggerFactory loggerFactory)
{
@@ -33,13 +73,20 @@ public void Configure(JustSayingBus bus, IAwsClientFactoryProxy proxy, ILoggerFa
logger.LogInformation("Adding SQS publisher for message type '{MessageType}'", typeof(T));
- bus.SerializationRegister.AddSerializer();
+ var config = bus.Config;
+ var compressionOptions = _compressionOptions ?? bus.Config.DefaultCompressionOptions;
+ var subjectProvider = bus.Config.MessageSubjectProvider;
+ var subject = _subjectSet ? _subject : subjectProvider.GetSubjectForType(typeof(T));
var eventPublisher = new SqsMessagePublisher(
_queueAddress.QueueUrl,
proxy.GetAwsClientFactory().GetSqsClient(RegionEndpoint.GetBySystemName(_queueAddress.RegionName)),
- bus.SerializationRegister,
- loggerFactory);
+ new OutboundMessageConverter(PublishDestinationType.Queue, bus.MessageBodySerializerFactory.GetSerializer(), new MessageCompressionRegistry([new GzipMessageBodyCompression()]), compressionOptions, subject, _isRawMessage),
+ loggerFactory)
+ {
+ MessageResponseLogger = config.MessageResponseLogger
+ };
+ CompressionEncodingValidator.ValidateEncoding(bus.CompressionRegistry, compressionOptions);
bus.AddMessagePublisher(eventPublisher);
@@ -48,4 +95,4 @@ public void Configure(JustSayingBus bus, IAwsClientFactoryProxy proxy, ILoggerFa
_queueAddress.QueueUrl,
typeof(T));
}
-}
\ No newline at end of file
+}
diff --git a/src/JustSaying/Fluent/QueueAddressSubscriptionBuilder`1.cs b/src/JustSaying/Fluent/QueueAddressSubscriptionBuilder`1.cs
index 2e266accc..04f76cbbd 100644
--- a/src/JustSaying/Fluent/QueueAddressSubscriptionBuilder`1.cs
+++ b/src/JustSaying/Fluent/QueueAddressSubscriptionBuilder`1.cs
@@ -2,6 +2,10 @@
using Amazon.SQS;
using JustSaying.AwsTools;
using JustSaying.AwsTools.QueueCreation;
+using JustSaying.Messaging;
+using JustSaying.Messaging.Channels.SubscriptionGroups;
+using JustSaying.Messaging.Compression;
+using JustSaying.Messaging.MessageSerialization;
using JustSaying.Messaging.Middleware;
using JustSaying.Models;
using Microsoft.Extensions.Logging;
@@ -32,6 +36,7 @@ internal QueueAddressSubscriptionBuilder(QueueAddress queueAddress)
private Action MiddlewareConfiguration { get; set; }
+ private IMessageBodySerializer MessageBodySerializer { get; set; }
///
/// Configures the SQS read configuration.
@@ -56,6 +61,12 @@ public ISubscriptionBuilder WithMiddlewareConfiguration(Action WithMessageBodySerializer(IMessageBodySerializer messageBodySerializer)
+ {
+ MessageBodySerializer = messageBodySerializer;
+ return this;
+ }
+
///
void ISubscriptionBuilder.Configure(
JustSayingBus bus,
@@ -80,7 +91,12 @@ void ISubscriptionBuilder.Configure(
attachedQueueConfig.SubscriptionGroupName ??= queue.QueueName;
attachedQueueConfig.Validate();
- bus.AddQueue(attachedQueueConfig.SubscriptionGroupName, queue);
+ var serializer = MessageBodySerializer ?? bus.MessageBodySerializerFactory.GetSerializer();
+ var compressionRegistry = bus.CompressionRegistry;
+ var messageConverter = new InboundMessageConverter(serializer, compressionRegistry, attachedQueueConfig.RawMessageDelivery);
+ var sqsSource = new SqsSource { SqsQueue = queue, MessageConverter = messageConverter };
+
+ bus.AddQueue(attachedQueueConfig.SubscriptionGroupName, sqsSource);
logger.LogInformation(
"Created SQS queue subscription for '{MessageType}' on '{QueueName}'",
diff --git a/src/JustSaying/Fluent/QueuePublicationBuilder`1.cs b/src/JustSaying/Fluent/QueuePublicationBuilder`1.cs
index 88b67771a..d8d5fc289 100644
--- a/src/JustSaying/Fluent/QueuePublicationBuilder`1.cs
+++ b/src/JustSaying/Fluent/QueuePublicationBuilder`1.cs
@@ -2,6 +2,7 @@
using JustSaying.AwsTools;
using JustSaying.AwsTools.MessageHandling;
using JustSaying.AwsTools.QueueCreation;
+using JustSaying.Messaging;
using JustSaying.Models;
using Microsoft.Extensions.Logging;
@@ -27,6 +28,8 @@ internal QueuePublicationBuilder()
///
private Action ConfigureWrites { get; set; }
+ private string QueueName { get; set; } = string.Empty;
+
///
/// Configures the SQS write configuration.
///
@@ -72,13 +75,14 @@ public QueuePublicationBuilder WithWriteConfiguration(Action
/// Configures the SQS Queue name, rather than using the naming convention.
///
- /// The name of the queue to subscribe to.
+ /// The name of the queue to subscribe to.
///
/// The current .
///
- public QueuePublicationBuilder WithName(string queueName)
+ public QueuePublicationBuilder WithQueueName(string name)
{
- return WithWriteConfiguration(r => r.WithQueueName(queueName));
+ QueueName = name ?? throw new ArgumentNullException(nameof(name));
+ return this;
}
///
@@ -95,18 +99,24 @@ void IPublicationBuilder.Configure(
var config = bus.Config;
var region = config.Region ?? throw new InvalidOperationException($"Config cannot have a blank entry for the {nameof(config.Region)} property.");
- var writeConfiguration = new SqsWriteConfiguration();
+ var writeConfiguration = new SqsWriteConfiguration
+ {
+ QueueName = QueueName
+ };
ConfigureWrites?.Invoke(writeConfiguration);
writeConfiguration.ApplyQueueNamingConvention(config.QueueNamingConvention);
- bus.SerializationRegister.AddSerializer();
-
var regionEndpoint = RegionEndpoint.GetBySystemName(region);
var sqsClient = proxy.GetAwsClientFactory().GetSqsClient(regionEndpoint);
+ var compressionRegistry = bus.CompressionRegistry;
+ var compressionOptions = writeConfiguration.CompressionOptions;
+ var subjectProvider = bus.Config.MessageSubjectProvider;
+ var subject = subjectProvider.GetSubjectForType(typeof(T));
+
var eventPublisher = new SqsMessagePublisher(
sqsClient,
- bus.SerializationRegister,
+ new OutboundMessageConverter(PublishDestinationType.Queue, bus.MessageBodySerializerFactory.GetSerializer(), compressionRegistry, compressionOptions, subject, writeConfiguration.IsRawMessage),
loggerFactory)
{
MessageResponseLogger = config.MessageResponseLogger,
diff --git a/src/JustSaying/Fluent/QueueSubscriptionBuilder`1.cs b/src/JustSaying/Fluent/QueueSubscriptionBuilder`1.cs
index 84cb978e6..0b8cc4622 100644
--- a/src/JustSaying/Fluent/QueueSubscriptionBuilder`1.cs
+++ b/src/JustSaying/Fluent/QueueSubscriptionBuilder`1.cs
@@ -1,5 +1,8 @@
using JustSaying.AwsTools;
using JustSaying.AwsTools.QueueCreation;
+using JustSaying.Messaging;
+using JustSaying.Messaging.Channels.SubscriptionGroups;
+using JustSaying.Messaging.MessageSerialization;
using JustSaying.Messaging.Middleware;
using JustSaying.Models;
using JustSaying.Naming;
@@ -184,7 +187,9 @@ void ISubscriptionBuilder.Configure(
var queue = creator.EnsureQueueExists(region, subscriptionConfig);
bus.AddStartupTask(queue.StartupTask);
- bus.AddQueue(subscriptionConfig.SubscriptionGroupName, queue.Queue);
+ var serializer = bus.MessageBodySerializerFactory.GetSerializer();
+ var compressionRegistry = bus.CompressionRegistry;
+ bus.AddQueue(subscriptionConfig.SubscriptionGroupName, new SqsSource { MessageConverter = new InboundMessageConverter(serializer, compressionRegistry, subscriptionConfig.RawMessageDelivery), SqsQueue = queue.Queue });
logger.LogInformation(
"Created SQS subscriber for message type '{MessageType}' on queue '{QueueName}'.",
diff --git a/src/JustSaying/Fluent/ServiceResolver/DefaultServiceResolver.cs b/src/JustSaying/Fluent/ServiceResolver/DefaultServiceResolver.cs
index 9b03895f6..1f157f04a 100644
--- a/src/JustSaying/Fluent/ServiceResolver/DefaultServiceResolver.cs
+++ b/src/JustSaying/Fluent/ServiceResolver/DefaultServiceResolver.cs
@@ -1,4 +1,5 @@
using JustSaying.AwsTools;
+using JustSaying.Messaging.Compression;
using JustSaying.Messaging.MessageSerialization;
using JustSaying.Messaging.Monitoring;
using JustSaying.Naming;
@@ -42,15 +43,13 @@ private object TryResolveService(Type desiredType)
{
return new NullOpMessageMonitor();
}
- else if (desiredType == typeof(IMessageSerializationFactory))
+ else if (desiredType == typeof(IMessageBodySerializationFactory))
{
return new NewtonsoftSerializationFactory();
}
- else if (desiredType == typeof(IMessageSerializationRegister))
+ else if (desiredType == typeof(MessageCompressionRegistry))
{
- return new MessageSerializationRegister(
- ResolveService(),
- ResolveService());
+ return new MessageCompressionRegistry([new GzipMessageBodyCompression()]);
}
else if (desiredType == typeof(IMessageSubjectProvider))
{
diff --git a/src/JustSaying/Fluent/ServiceResolver/ServiceBuilderServiceResolver.cs b/src/JustSaying/Fluent/ServiceResolver/ServiceBuilderServiceResolver.cs
index 8d3db633a..91a17df25 100644
--- a/src/JustSaying/Fluent/ServiceResolver/ServiceBuilderServiceResolver.cs
+++ b/src/JustSaying/Fluent/ServiceResolver/ServiceBuilderServiceResolver.cs
@@ -1,7 +1,6 @@
using System.Collections.Concurrent;
using JustSaying.AwsTools;
using JustSaying.Messaging.MessageHandling;
-using JustSaying.Messaging.MessageSerialization;
using JustSaying.Messaging.Monitoring;
using Microsoft.Extensions.Logging;
@@ -42,11 +41,6 @@ private void Build()
_serviceLookup[typeof(IMessageMonitor)] = builder.MessageMonitoring();
}
- if (builder.SerializationRegister != null)
- {
- _serviceLookup[typeof(IMessageSerializationRegister)] = builder.SerializationRegister();
- }
-
if (builder.MessageContextAccessor != null)
{
_serviceLookup[typeof(IMessageContextAccessor)] = builder.MessageContextAccessor();
diff --git a/src/JustSaying/Fluent/ServicesBuilder.cs b/src/JustSaying/Fluent/ServicesBuilder.cs
index 03bfc4cb2..49d85f110 100644
--- a/src/JustSaying/Fluent/ServicesBuilder.cs
+++ b/src/JustSaying/Fluent/ServicesBuilder.cs
@@ -36,11 +36,6 @@ internal ServicesBuilder(MessagingBusBuilder busBuilder)
///
internal Func MessageMonitoring { get; private set; }
- ///
- /// Gets or sets a delegate to a method to create the to use.
- ///
- internal Func SerializationRegister { get; private set; }
-
///
/// Gets or sets a delegate to a method to create the to use.
///
@@ -149,4 +144,4 @@ public ServicesBuilder WithMessageContextAccessor(Func
MessageContextAccessor = contextAccessor ?? throw new ArgumentNullException(nameof(contextAccessor));
return this;
}
-}
\ No newline at end of file
+}
diff --git a/src/JustSaying/Fluent/SqsEndpointHelper.cs b/src/JustSaying/Fluent/SqsEndpointHelper.cs
new file mode 100644
index 000000000..9b5d637a2
--- /dev/null
+++ b/src/JustSaying/Fluent/SqsEndpointHelper.cs
@@ -0,0 +1,15 @@
+namespace JustSaying.Fluent;
+
+internal static class SqsEndpointHelper
+{
+ public static string GetSqsHostname(string partition, string region)
+ {
+ return partition switch
+ {
+ "aws-cn" => $"sqs.{region}.amazonaws.com.cn",
+ "aws-us-gov" => $"sqs.{region}.amazonaws.com",
+ "aws" => $"sqs.{region}.amazonaws.com",
+ _ => throw new ArgumentException($"Unknown partition: {partition}", nameof(partition))
+ };
+ }
+}
diff --git a/src/JustSaying/Fluent/TopicAddressPublicationBuilder`1.cs b/src/JustSaying/Fluent/TopicAddressPublicationBuilder`1.cs
index 4c7f0ca94..28c1ce498 100644
--- a/src/JustSaying/Fluent/TopicAddressPublicationBuilder`1.cs
+++ b/src/JustSaying/Fluent/TopicAddressPublicationBuilder`1.cs
@@ -1,6 +1,7 @@
using Amazon;
using JustSaying.AwsTools;
using JustSaying.AwsTools.MessageHandling;
+using JustSaying.Messaging;
using JustSaying.Models;
using Microsoft.Extensions.Logging;
@@ -18,6 +19,9 @@ public sealed class TopicAddressPublicationBuilder : IPublicationBuilder
private readonly TopicAddress _topicAddress;
private Func _exceptionHandler;
private Func, bool> _exceptionBatchHandler;
+ private PublishCompressionOptions _compressionOptions;
+ private string _subject;
+ private bool _subjectSet;
///
/// Initializes a new instance of the class.
@@ -60,6 +64,25 @@ public TopicAddressPublicationBuilder WithExceptionHandler(Func
+ /// Sets the compression options for publishing messages.
+ ///
+ /// The compression options to use when publishing messages.
+ /// The current instance of for method chaining.
+ /// Thrown when is null.
+ public TopicAddressPublicationBuilder WithCompression(PublishCompressionOptions compressionOptions)
+ {
+ _compressionOptions = compressionOptions ?? throw new ArgumentNullException(nameof(compressionOptions));
+ return this;
+ }
+
+ public TopicAddressPublicationBuilder WithSubject(string subject)
+ {
+ _subject = subject;
+ _subjectSet = true;
+ return this;
+ }
+
///
public void Configure(JustSayingBus bus, IAwsClientFactoryProxy proxy, ILoggerFactory loggerFactory)
{
@@ -67,21 +90,23 @@ public void Configure(JustSayingBus bus, IAwsClientFactoryProxy proxy, ILoggerFa
logger.LogInformation("Adding SNS publisher for message type '{MessageType}'", typeof(T));
- var config = bus.Config;
var arn = Arn.Parse(_topicAddress.TopicArn);
- bus.SerializationRegister.AddSerializer();
+ var compressionRegistry = bus.CompressionRegistry;
+ var compressionOptions = _compressionOptions ?? bus.Config.DefaultCompressionOptions;
+ var serializer = bus.MessageBodySerializerFactory.GetSerializer();
+ var subjectProvider = bus.Config.MessageSubjectProvider;
+ var subject = _subjectSet ? _subject : subjectProvider.GetSubjectForType(typeof(T));
var eventPublisher = new SnsMessagePublisher(
_topicAddress.TopicArn,
proxy.GetAwsClientFactory().GetSnsClient(RegionEndpoint.GetBySystemName(arn.Region)),
- bus.SerializationRegister,
+ new OutboundMessageConverter(PublishDestinationType.Topic, serializer, compressionRegistry, compressionOptions, subject, true),
loggerFactory,
- config.MessageSubjectProvider,
- _exceptionHandler)
- {
- HandleBatchException = _exceptionBatchHandler,
- };
+ _exceptionHandler,
+ _exceptionBatchHandler);
+
+ CompressionEncodingValidator.ValidateEncoding(bus.CompressionRegistry, compressionOptions);
bus.AddMessagePublisher(eventPublisher);
diff --git a/src/JustSaying/Fluent/TopicPublicationBuilder`1.cs b/src/JustSaying/Fluent/TopicPublicationBuilder`1.cs
index 4b473afc0..f89f7356d 100644
--- a/src/JustSaying/Fluent/TopicPublicationBuilder`1.cs
+++ b/src/JustSaying/Fluent/TopicPublicationBuilder`1.cs
@@ -171,6 +171,8 @@ void IPublicationBuilder.Configure(
var writeConfiguration = new SnsWriteConfiguration();
ConfigureWrites?.Invoke(writeConfiguration);
+ writeConfiguration.CompressionOptions ??= bus.Config.DefaultCompressionOptions;
+ CompressionEncodingValidator.ValidateEncoding(bus.CompressionRegistry, writeConfiguration.CompressionOptions);
var client = proxy.GetAwsClientFactory().GetSnsClient(RegionEndpoint.GetBySystemName(region));
@@ -189,7 +191,5 @@ StaticPublicationConfiguration BuildConfiguration(string topicName)
bus.AddStartupTask(config.StartupTask);
bus.AddMessagePublisher(config.Publisher);
bus.AddMessageBatchPublisher(config.BatchPublisher);
-
- bus.SerializationRegister.AddSerializer();
}
}
diff --git a/src/JustSaying/Fluent/TopicSubscriptionBuilder`1.cs b/src/JustSaying/Fluent/TopicSubscriptionBuilder`1.cs
index 977828070..15cc080c0 100644
--- a/src/JustSaying/Fluent/TopicSubscriptionBuilder`1.cs
+++ b/src/JustSaying/Fluent/TopicSubscriptionBuilder`1.cs
@@ -1,5 +1,7 @@
using JustSaying.AwsTools;
using JustSaying.AwsTools.QueueCreation;
+using JustSaying.Messaging;
+using JustSaying.Messaging.Channels.SubscriptionGroups;
using JustSaying.Messaging.Middleware;
using JustSaying.Models;
using JustSaying.Naming;
@@ -41,7 +43,6 @@ internal TopicSubscriptionBuilder()
private Action MiddlewareConfiguration { get; set; }
-
///
/// Configures that the will create the topic name that should be used.
///
@@ -203,7 +204,15 @@ void ISubscriptionBuilder.Configure(
subscriptionConfig);
bus.AddStartupTask(queueWithStartup.StartupTask);
- bus.AddQueue(subscriptionConfig.SubscriptionGroupName, queueWithStartup.Queue);
+ var compressionRegistry = bus.CompressionRegistry;
+ var serializer = bus.MessageBodySerializerFactory.GetSerializer();
+
+ var sqsSource = new SqsSource
+ {
+ SqsQueue = queueWithStartup.Queue,
+ MessageConverter = new InboundMessageConverter(serializer, compressionRegistry, subscriptionConfig.RawMessageDelivery)
+ };
+ bus.AddQueue(subscriptionConfig.SubscriptionGroupName, sqsSource);
logger.LogInformation(
"Created SQS topic subscription on topic '{TopicName}' and queue '{QueueName}'.",
diff --git a/src/JustSaying/IMessagingConfig.cs b/src/JustSaying/IMessagingConfig.cs
index ea029a05f..e6e559209 100644
--- a/src/JustSaying/IMessagingConfig.cs
+++ b/src/JustSaying/IMessagingConfig.cs
@@ -1,3 +1,4 @@
+using JustSaying.AwsTools.MessageHandling;
using JustSaying.Messaging.MessageSerialization;
using JustSaying.Naming;
@@ -9,5 +10,6 @@ public interface IMessagingConfig : IPublishConfiguration
IMessageSubjectProvider MessageSubjectProvider { get; set; }
ITopicNamingConvention TopicNamingConvention { get; set; }
IQueueNamingConvention QueueNamingConvention { get; set; }
+ PublishCompressionOptions DefaultCompressionOptions { get; set; }
void Validate();
}
diff --git a/src/JustSaying/JustSaying.csproj b/src/JustSaying/JustSaying.csproj
index edbd7e93b..11e263690 100644
--- a/src/JustSaying/JustSaying.csproj
+++ b/src/JustSaying/JustSaying.csproj
@@ -10,6 +10,8 @@
+
+
@@ -23,4 +25,12 @@
+
+
+
+
+
+
+
+
diff --git a/src/JustSaying/JustSayingBus.cs b/src/JustSaying/JustSayingBus.cs
index 27de3d998..7a415a619 100644
--- a/src/JustSaying/JustSayingBus.cs
+++ b/src/JustSaying/JustSayingBus.cs
@@ -1,10 +1,10 @@
using System.Collections.Concurrent;
-using JustSaying.AwsTools.MessageHandling;
using JustSaying.AwsTools.MessageHandling.Dispatch;
using JustSaying.Extensions;
using JustSaying.Messaging;
using JustSaying.Messaging.Channels.Receive;
using JustSaying.Messaging.Channels.SubscriptionGroups;
+using JustSaying.Messaging.Compression;
using JustSaying.Messaging.Interrogation;
using JustSaying.Messaging.MessageSerialization;
using JustSaying.Messaging.Monitoring;
@@ -36,33 +36,25 @@ public sealed class JustSayingBus : IMessagingBus, IMessagePublisher, IMessageBa
private readonly IMessageMonitor _monitor;
private ISubscriptionGroup SubscriptionGroups { get; set; }
- public IMessageSerializationRegister SerializationRegister { get; }
internal MiddlewareMap MiddlewareMap { get; }
+ internal MessageCompressionRegistry CompressionRegistry { get; }
+ internal IMessageBodySerializationFactory MessageBodySerializerFactory { get; set; }
public Task Completion { get; private set; }
- public JustSayingBus(
+ internal JustSayingBus(
IMessagingConfig config,
- IMessageSerializationRegister serializationRegister,
+ IMessageBodySerializationFactory serializationFactory,
ILoggerFactory loggerFactory,
IMessageMonitor monitor)
- : this(config, serializationRegister, null, loggerFactory, monitor, config as IPublishBatchConfiguration)
+ : this(config, serializationFactory, null, loggerFactory, monitor, config as IPublishBatchConfiguration)
{
}
- public JustSayingBus(
+ internal JustSayingBus(
IMessagingConfig config,
- IMessageSerializationRegister serializationRegister,
- IMessageReceivePauseSignal messageReceivePauseSignal,
- ILoggerFactory loggerFactory,
- IMessageMonitor monitor) : this(config, serializationRegister, messageReceivePauseSignal, loggerFactory, monitor, config as IPublishBatchConfiguration)
- {
- }
-
- public JustSayingBus(
- IMessagingConfig config,
- IMessageSerializationRegister serializationRegister,
+ IMessageBodySerializationFactory serializationFactory,
IMessageReceivePauseSignal messageReceivePauseSignal,
ILoggerFactory loggerFactory,
IMessageMonitor monitor,
@@ -89,8 +81,9 @@ public JustSayingBus(
}
}
- SerializationRegister = serializationRegister;
MiddlewareMap = new MiddlewareMap();
+ CompressionRegistry = new MessageCompressionRegistry([new GzipMessageBodyCompression()]);
+ MessageBodySerializerFactory = serializationFactory;
_publishersByType = [];
_batchPublishersByType = [];
@@ -98,7 +91,17 @@ public JustSayingBus(
_defaultSubscriptionGroupSettings = new SubscriptionGroupSettingsBuilder();
}
- public void AddQueue(string subscriptionGroup, ISqsQueue queue)
+ internal JustSayingBus(
+ IMessagingConfig config,
+ IMessageBodySerializationFactory serializationFactory,
+ IMessageReceivePauseSignal messageReceivePauseSignal,
+ ILoggerFactory loggerFactory,
+ IMessageMonitor monitor) : this(config, serializationFactory, loggerFactory, monitor)
+ {
+ _messageReceivePauseSignal = messageReceivePauseSignal;
+ }
+
+ internal void AddQueue(string subscriptionGroup, SqsSource queue)
{
if (string.IsNullOrWhiteSpace(subscriptionGroup))
{
@@ -134,7 +137,6 @@ public void SetGroupSettings(
public void AddMessageMiddleware(string queueName, HandleMessageMiddleware middleware)
where T : Message
{
- SerializationRegister.AddSerializer();
MiddlewareMap.Add(queueName, middleware);
}
@@ -206,7 +208,6 @@ public async Task StartAsync(CancellationToken stoppingToken)
private async Task RunImplAsync(CancellationToken stoppingToken)
{
var dispatcher = new MessageDispatcher(
- SerializationRegister,
_monitor,
MiddlewareMap,
_loggerFactory);
diff --git a/src/JustSaying/Messaging/Channels/Context/IQueueMessageContext.cs b/src/JustSaying/Messaging/Channels/Context/IQueueMessageContext.cs
index 2a76eafc6..ccd728404 100644
--- a/src/JustSaying/Messaging/Channels/Context/IQueueMessageContext.cs
+++ b/src/JustSaying/Messaging/Channels/Context/IQueueMessageContext.cs
@@ -1,4 +1,5 @@
using Amazon.SQS.Model;
+using JustSaying.Messaging.MessageSerialization;
namespace JustSaying.Messaging.Channels.Context;
@@ -22,4 +23,6 @@ public interface IQueueMessageContext : IMessageVisibilityUpdater, IMessageDelet
/// Gets the name of the queue that this message was received from.
///
string QueueName { get; }
-}
\ No newline at end of file
+
+ IInboundMessageConverter MessageConverter { get; }
+}
diff --git a/src/JustSaying/Messaging/Channels/Context/QueueMessageContext.cs b/src/JustSaying/Messaging/Channels/Context/QueueMessageContext.cs
index 71bfbdad3..3ebdcce11 100644
--- a/src/JustSaying/Messaging/Channels/Context/QueueMessageContext.cs
+++ b/src/JustSaying/Messaging/Channels/Context/QueueMessageContext.cs
@@ -1,5 +1,6 @@
using Amazon.SQS.Model;
using JustSaying.AwsTools.MessageHandling;
+using JustSaying.Messaging.MessageSerialization;
namespace JustSaying.Messaging.Channels.Context;
@@ -13,10 +14,12 @@ public sealed class QueueMessageContext : IQueueMessageContext
///
/// The to be handled.
/// The the message was read from.
- internal QueueMessageContext(Message message, SqsQueueReader queueReader)
+ ///
+ internal QueueMessageContext(Message message, SqsQueueReader queueReader, IInboundMessageConverter messageConverter)
{
Message = message ?? throw new ArgumentNullException(nameof(message));
_queueReader = queueReader ?? throw new ArgumentNullException(nameof(queueReader));
+ MessageConverter = messageConverter;
}
///
@@ -28,6 +31,8 @@ internal QueueMessageContext(Message message, SqsQueueReader queueReader)
///
public string QueueName => _queueReader.QueueName;
+ public IInboundMessageConverter MessageConverter { get; }
+
///
public async Task UpdateMessageVisibilityTimeout(TimeSpan visibilityTimeout, CancellationToken cancellationToken)
{
@@ -39,4 +44,4 @@ public async Task DeleteMessage(CancellationToken cancellationToken)
{
await _queueReader.DeleteMessageAsync(Message.ReceiptHandle, cancellationToken).ConfigureAwait(false);
}
-}
\ No newline at end of file
+}
diff --git a/src/JustSaying/Messaging/Channels/Receive/MessageReceiveBuffer.cs b/src/JustSaying/Messaging/Channels/Receive/MessageReceiveBuffer.cs
index 5d53c24ea..eba4a9a62 100644
--- a/src/JustSaying/Messaging/Channels/Receive/MessageReceiveBuffer.cs
+++ b/src/JustSaying/Messaging/Channels/Receive/MessageReceiveBuffer.cs
@@ -1,8 +1,10 @@
using System.Threading.Channels;
using Amazon.SQS;
using Amazon.SQS.Model;
+using JustSaying.AwsTools;
using JustSaying.AwsTools.MessageHandling;
using JustSaying.Messaging.Channels.Context;
+using JustSaying.Messaging.Channels.SubscriptionGroups;
using JustSaying.Messaging.Interrogation;
using JustSaying.Messaging.Middleware;
using JustSaying.Messaging.Middleware.Receive;
@@ -37,7 +39,7 @@ public MessageReceiveBuffer(
int bufferSize,
TimeSpan readTimeout,
TimeSpan sqsWaitTime,
- ISqsQueue sqsQueue,
+ SqsSource sqsSource,
MiddlewareBase> sqsMiddleware,
IMessageReceivePauseSignal messageReceivePauseSignal,
IMessageMonitor monitor,
@@ -47,8 +49,8 @@ public MessageReceiveBuffer(
_bufferSize = bufferSize;
_readTimeout = readTimeout;
_sqsWaitTime = sqsWaitTime;
- if (sqsQueue == null) throw new ArgumentNullException(nameof(sqsQueue));
- _sqsQueueReader = new SqsQueueReader(sqsQueue);
+ if (sqsSource == null) throw new ArgumentNullException(nameof(sqsSource));
+ _sqsQueueReader = new SqsQueueReader(sqsSource.SqsQueue, sqsSource.MessageConverter);
_sqsMiddleware = sqsMiddleware ?? throw new ArgumentNullException(nameof(sqsMiddleware));
_messageReceivePauseSignal = messageReceivePauseSignal;
_monitor = monitor ?? throw new ArgumentNullException(nameof(monitor));
@@ -142,8 +144,6 @@ private async Task> GetMessagesAsync(int count, CancellationToken
RegionName = _sqsQueueReader.RegionSystemName,
};
- _requestMessageAttributeNames.Add("content");
-
messages = await _sqsMiddleware.RunAsync(context,
async ct =>
await _sqsQueueReader
diff --git a/src/JustSaying/Messaging/Channels/SubscriptionGroups/SqsSource.cs b/src/JustSaying/Messaging/Channels/SubscriptionGroups/SqsSource.cs
new file mode 100644
index 000000000..9c3799a26
--- /dev/null
+++ b/src/JustSaying/Messaging/Channels/SubscriptionGroups/SqsSource.cs
@@ -0,0 +1,9 @@
+using JustSaying.AwsTools.MessageHandling;
+
+namespace JustSaying.Messaging.Channels.SubscriptionGroups;
+
+public sealed class SqsSource
+{
+ public ISqsQueue SqsQueue { get; set; }
+ public IInboundMessageConverter MessageConverter { get; set; }
+}
diff --git a/src/JustSaying/Messaging/Channels/SubscriptionGroups/SubscriptionGroupConfigBuilder.cs b/src/JustSaying/Messaging/Channels/SubscriptionGroups/SubscriptionGroupConfigBuilder.cs
index 0107620c4..b906288ee 100644
--- a/src/JustSaying/Messaging/Channels/SubscriptionGroups/SubscriptionGroupConfigBuilder.cs
+++ b/src/JustSaying/Messaging/Channels/SubscriptionGroups/SubscriptionGroupConfigBuilder.cs
@@ -15,7 +15,7 @@ namespace JustSaying.Messaging.Channels.SubscriptionGroups;
/// The name of the subscription group.
public class SubscriptionGroupConfigBuilder(string groupName)
{
- private readonly List _sqsQueues = [];
+ private readonly List _sqsSources = [];
private readonly string _groupName = groupName ?? throw new ArgumentNullException(nameof(groupName));
private int? _bufferSize;
@@ -30,10 +30,10 @@ public class SubscriptionGroupConfigBuilder(string groupName)
///
/// The queue to be consumed, assumed to already be created and ready.
/// This builder object.
- public SubscriptionGroupConfigBuilder AddQueue(ISqsQueue sqsQueue)
+ internal SubscriptionGroupConfigBuilder AddQueue(SqsSource sqsQueue)
{
if (sqsQueue == null) throw new ArgumentNullException(nameof(sqsQueue));
- _sqsQueues.Add(sqsQueue);
+ _sqsSources.Add(sqsQueue);
return this;
}
@@ -42,10 +42,10 @@ public SubscriptionGroupConfigBuilder AddQueue(ISqsQueue sqsQueue)
///
/// The queues to be consumed, assumed to already be created and ready.
/// This builder object.
- public SubscriptionGroupConfigBuilder AddQueues(IEnumerable sqsQueues)
+ internal SubscriptionGroupConfigBuilder AddQueues(IEnumerable sqsQueues)
{
if (sqsQueues == null) throw new ArgumentNullException(nameof(sqsQueues));
- _sqsQueues.AddRange(sqsQueues);
+ _sqsSources.AddRange(sqsQueues);
return this;
}
@@ -138,7 +138,7 @@ public SubscriptionGroupSettings Build(SubscriptionGroupSettingsBuilder defaults
_receiveMessagesWaitTime ?? defaults.ReceiveMessagesWaitTime,
_multiplexerCapacity ?? defaults.MultiplexerCapacity,
_prefetch ?? defaults.Prefetch,
- _sqsQueues);
+ _sqsSources);
settings.Validate();
diff --git a/src/JustSaying/Messaging/Channels/SubscriptionGroups/SubscriptionGroupFactory.cs b/src/JustSaying/Messaging/Channels/SubscriptionGroups/SubscriptionGroupFactory.cs
index bb3dcc5c3..88141aa3b 100644
--- a/src/JustSaying/Messaging/Channels/SubscriptionGroups/SubscriptionGroupFactory.cs
+++ b/src/JustSaying/Messaging/Channels/SubscriptionGroups/SubscriptionGroupFactory.cs
@@ -15,7 +15,7 @@ namespace JustSaying.Messaging.Channels.SubscriptionGroups;
///
/// Builds 's from the various components required.
///
-public class SubscriptionGroupFactory : ISubscriptionGroupFactory
+internal sealed class SubscriptionGroupFactory : ISubscriptionGroupFactory
{
private readonly IMessageDispatcher _messageDispatcher;
private readonly IMessageReceivePauseSignal _messageReceivePauseSignal;
@@ -29,7 +29,7 @@ public class SubscriptionGroupFactory : ISubscriptionGroupFactory
/// The to use to dispatch messages.
/// The used by the .
/// The to use.
- public SubscriptionGroupFactory(
+ private SubscriptionGroupFactory(
IMessageDispatcher messageDispatcher,
IMessageMonitor monitor,
ILoggerFactory loggerFactory)
@@ -111,7 +111,7 @@ private List CreateBuffers(
var logger = _loggerFactory.CreateLogger();
- foreach (ISqsQueue queue in subscriptionGroupSettings.Queues)
+ foreach (SqsSource queue in subscriptionGroupSettings.QueueSources)
{
var buffer = new MessageReceiveBuffer(
subscriptionGroupSettings.Prefetch,
diff --git a/src/JustSaying/Messaging/Channels/SubscriptionGroups/SubscriptionGroupSettings.cs b/src/JustSaying/Messaging/Channels/SubscriptionGroups/SubscriptionGroupSettings.cs
index 7e7bfc5cc..c6ab469a8 100644
--- a/src/JustSaying/Messaging/Channels/SubscriptionGroups/SubscriptionGroupSettings.cs
+++ b/src/JustSaying/Messaging/Channels/SubscriptionGroups/SubscriptionGroupSettings.cs
@@ -16,7 +16,7 @@ internal SubscriptionGroupSettings(
TimeSpan receiveMessagesWaitTime,
int multiplexerCapacity,
int prefetch,
- IReadOnlyCollection queues)
+ IReadOnlyCollection queueSources)
{
ConcurrencyLimit = concurrencyLimit;
BufferSize = bufferSize;
@@ -24,7 +24,7 @@ internal SubscriptionGroupSettings(
ReceiveMessagesWaitTime = receiveMessagesWaitTime;
MultiplexerCapacity = multiplexerCapacity;
Prefetch = prefetch;
- Queues = queues;
+ QueueSources = queueSources;
Name = name;
}
@@ -67,5 +67,5 @@ internal SubscriptionGroupSettings(
///
/// A collection of to read messages from.
///
- public IReadOnlyCollection Queues { get; }
+ public IReadOnlyCollection QueueSources { get; }
}
diff --git a/src/JustSaying/Messaging/Compression/ContentEncodings.cs b/src/JustSaying/Messaging/Compression/ContentEncodings.cs
new file mode 100644
index 000000000..075371799
--- /dev/null
+++ b/src/JustSaying/Messaging/Compression/ContentEncodings.cs
@@ -0,0 +1,17 @@
+namespace JustSaying.Messaging.Compression;
+
+///
+/// Provides constant values for various content encodings used in message body compression.
+///
+///
+/// This class contains predefined string constants representing different content encoding schemes.
+/// These constants can be used to ensure consistency and avoid typos when specifying
+/// content encodings throughout the application.
+///
+public static class ContentEncodings
+{
+ ///
+ /// Represents the gzip,base64 content encoding.
+ ///
+ public const string GzipBase64 = "gzip,base64";
+}
diff --git a/src/JustSaying/Messaging/Compression/GzipMessageBodyCompression.cs b/src/JustSaying/Messaging/Compression/GzipMessageBodyCompression.cs
new file mode 100644
index 000000000..de48bfb94
--- /dev/null
+++ b/src/JustSaying/Messaging/Compression/GzipMessageBodyCompression.cs
@@ -0,0 +1,48 @@
+using System.IO.Compression;
+using System.Text;
+
+namespace JustSaying.Messaging.Compression;
+
+///
+/// Implements GZIP compression and Base64 encoding for message bodies.
+///
+public sealed class GzipMessageBodyCompression : IMessageBodyCompression
+{
+ ///
+ /// Gets the content encoding identifier for GZIP compression with Base64 encoding.
+ ///
+ public string ContentEncoding => ContentEncodings.GzipBase64;
+
+ ///
+ /// Gets the content encoding identifier for GZIP compression with Base64 encoding.
+ ///
+ public string Compress(string messageBody)
+ {
+ var contentBytes = Encoding.UTF8.GetBytes(messageBody);
+ using var compressedStream = new MemoryStream();
+ using (var gZipStream = new GZipStream(compressedStream, CompressionMode.Compress))
+ {
+ gZipStream.Write(contentBytes, 0, contentBytes.Length);
+ }
+
+ return Convert.ToBase64String(compressedStream.ToArray());
+ }
+
+ ///
+ /// Decodes the Base64 string and decompresses the message body using GZIP.
+ ///
+ /// The Base64 encoded and compressed message body to decompress.
+ /// The decompressed message body as a string.
+ public string Decompress(string messageBody)
+ {
+ var compressedBytes = Convert.FromBase64String(messageBody);
+ using var inputStream = new MemoryStream(compressedBytes);
+ using var outputStream = new MemoryStream();
+ using (var gZipStream = new GZipStream(inputStream, CompressionMode.Decompress))
+ {
+ gZipStream.CopyTo(outputStream);
+ }
+
+ return Encoding.UTF8.GetString(outputStream.ToArray());
+ }
+}
diff --git a/src/JustSaying/Messaging/Compression/IMessageBodyCompression.cs b/src/JustSaying/Messaging/Compression/IMessageBodyCompression.cs
new file mode 100644
index 000000000..c53b1840d
--- /dev/null
+++ b/src/JustSaying/Messaging/Compression/IMessageBodyCompression.cs
@@ -0,0 +1,26 @@
+namespace JustSaying.Messaging.Compression;
+
+///
+/// Defines the contract for message body compression operations.
+///
+public interface IMessageBodyCompression
+{
+ ///
+ /// Gets the content encoding identifier for this compression method.
+ ///
+ string ContentEncoding { get; }
+
+ ///
+ /// Compresses the given message body.
+ ///
+ /// The message body to compress.
+ /// The compressed message body as a string.
+ string Compress(string messageBody);
+
+ ///
+ /// Decompresses the given message body.
+ ///
+ /// The compressed message body to decompress.
+ /// The decompressed message body as a string.
+ string Decompress(string messageBody);
+}
diff --git a/src/JustSaying/Messaging/Compression/MessageCompressionRegistry.cs b/src/JustSaying/Messaging/Compression/MessageCompressionRegistry.cs
new file mode 100644
index 000000000..1c200c7be
--- /dev/null
+++ b/src/JustSaying/Messaging/Compression/MessageCompressionRegistry.cs
@@ -0,0 +1,28 @@
+namespace JustSaying.Messaging.Compression;
+
+///
+/// Implements a registry for message compression methods.
+///
+public sealed class MessageCompressionRegistry
+{
+ private readonly IList _compressions;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// A list of available compression methods.
+ public MessageCompressionRegistry(IList compressions = null)
+ {
+ _compressions = compressions ?? [];
+ }
+
+ ///
+ /// Retrieves the appropriate compression method based on the content encoding.
+ ///
+ /// The content encoding identifier.
+ /// An instance for the specified encoding, or null if not found.
+ public IMessageBodyCompression GetCompression(string contentEncoding)
+ {
+ return _compressions.FirstOrDefault(x => string.Equals(x.ContentEncoding, contentEncoding, StringComparison.OrdinalIgnoreCase));
+ }
+}
diff --git a/src/JustSaying/Messaging/MessageHandling/MessageAttributes.cs b/src/JustSaying/Messaging/MessageHandling/MessageAttributes.cs
index aea001e35..15b6a6c66 100644
--- a/src/JustSaying/Messaging/MessageHandling/MessageAttributes.cs
+++ b/src/JustSaying/Messaging/MessageHandling/MessageAttributes.cs
@@ -16,4 +16,11 @@ public MessageAttributes()
public MessageAttributeValue Get(string value)
=> _attributes.TryGetValue(value, out MessageAttributeValue result) ? result : null;
+
+ ///
+ /// Gets all available attribute keys.
+ ///
+ /// An of strings representing all attribute keys.
+ public IReadOnlyCollection GetKeys()
+ => _attributes.Keys;
}
diff --git a/src/JustSaying/Messaging/MessageSerialization/GenericMessageSubjectProvider.cs b/src/JustSaying/Messaging/MessageSerialization/GenericMessageSubjectProvider.cs
index 0be4d9174..b3e9e9b48 100644
--- a/src/JustSaying/Messaging/MessageSerialization/GenericMessageSubjectProvider.cs
+++ b/src/JustSaying/Messaging/MessageSerialization/GenericMessageSubjectProvider.cs
@@ -1,4 +1,3 @@
-using System.Reflection;
using System.Text.RegularExpressions;
using JustSaying.Extensions;
@@ -15,7 +14,7 @@ public class GenericMessageSubjectProvider : IMessageSubjectProvider
private static IEnumerable Flatten(Type type)
{
yield return type;
- foreach (var inner in type.GetTypeInfo().GetGenericArguments().SelectMany(Flatten))
+ foreach (var inner in type.GetGenericArguments().SelectMany(Flatten))
{
yield return inner;
}
diff --git a/src/JustSaying/Messaging/MessageSerialization/IMessageSerialisationRegister.cs b/src/JustSaying/Messaging/MessageSerialization/IMessageSerialisationRegister.cs
deleted file mode 100644
index f20f2dd7e..000000000
--- a/src/JustSaying/Messaging/MessageSerialization/IMessageSerialisationRegister.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-using JustSaying.Messaging.MessageHandling;
-using JustSaying.Models;
-
-namespace JustSaying.Messaging.MessageSerialization;
-
-public interface IMessageSerializationRegister
-{
- ///
- /// Deserializes a message.
- ///
- /// Message must always have Subject and Message properties
- /// The and
- /// returned from the body of the SQS message.
- MessageWithAttributes DeserializeMessage(string body);
-
- ///
- /// Serializes a message for publishing
- ///
- ///
- /// If set to false, then message will be wrapped in extra object with Subject and Message fields, e.g.:
- /// new { Subject = message.GetType().Name, Message = serializedMessage };
- ///
- /// AWS SNS service adds these automatically, so for publishing to topics don't add these properties
- ///
- /// The serialized message for publishing.
- string Serialize(Message message, bool serializeForSnsPublishing);
-
- ///
- /// Register a serializer for the given type, if one does not already exist.
- ///
- /// The type to register a serializer for.
- void AddSerializer() where T : Message;
-}
\ No newline at end of file
diff --git a/src/JustSaying/Messaging/MessageSerialization/IMessageSerialiser.cs b/src/JustSaying/Messaging/MessageSerialization/IMessageSerialiser.cs
index d0f7b10a2..57ff5d149 100644
--- a/src/JustSaying/Messaging/MessageSerialization/IMessageSerialiser.cs
+++ b/src/JustSaying/Messaging/MessageSerialization/IMessageSerialiser.cs
@@ -1,25 +1,23 @@
-using JustSaying.Messaging.MessageHandling;
using JustSaying.Models;
namespace JustSaying.Messaging.MessageSerialization;
-public interface IMessageSerializer
+///
+/// Defines the contract for serializing and deserializing message bodies.
+///
+public interface IMessageBodySerializer
{
- string GetMessageSubject(string sqsMessage);
-
- MessageAttributes GetMessageAttributes(string message);
-
- Message Deserialize(string message, Type type);
+ ///
+ /// Serializes a message into a string representation.
+ ///
+ /// The message to serialize.
+ /// A string representation of the serialized message.
+ string Serialize(Message message);
///
- /// Serializes a message for publishing
+ /// Deserializes a string representation back into a message object.
///
- ///
- /// If set to false, then message will be wrapped in extra object with Subject and Message fields, e.g.:
- /// new { Subject = subject, Message = serializedMessage };
- ///
- /// AWS SNS service adds these automatically, so for publishing to topics don't add these properties
- ///
- ///
- string Serialize(Message message, bool serializeForSnsPublishing, string subject);
-}
\ No newline at end of file
+ /// The string representation of the message to deserialize.
+ /// The deserialized message object.
+ Message Deserialize(string message);
+}
diff --git a/src/JustSaying/Messaging/MessageSerialization/IMessageSerializationFactory.cs b/src/JustSaying/Messaging/MessageSerialization/IMessageSerializationFactory.cs
index cad232cea..6bcdbc314 100644
--- a/src/JustSaying/Messaging/MessageSerialization/IMessageSerializationFactory.cs
+++ b/src/JustSaying/Messaging/MessageSerialization/IMessageSerializationFactory.cs
@@ -2,7 +2,15 @@
namespace JustSaying.Messaging.MessageSerialization;
-public interface IMessageSerializationFactory
+///
+/// Defines a factory for creating message body serializers.
+///
+public interface IMessageBodySerializationFactory
{
- IMessageSerializer GetSerializer() where T : Message;
-}
\ No newline at end of file
+ ///
+ /// Gets a serializer for messages of type .
+ ///
+ /// The type of message for which to get a serializer. Must inherit from .
+ /// An capable of serializing and deserializing messages of type .
+ IMessageBodySerializer GetSerializer() where T : Message;
+}
diff --git a/src/JustSaying/Messaging/MessageSerialization/MessageWithAttributes.cs b/src/JustSaying/Messaging/MessageSerialization/InboundMessage.cs
similarity index 71%
rename from src/JustSaying/Messaging/MessageSerialization/MessageWithAttributes.cs
rename to src/JustSaying/Messaging/MessageSerialization/InboundMessage.cs
index d57fdaac1..19493fc45 100644
--- a/src/JustSaying/Messaging/MessageSerialization/MessageWithAttributes.cs
+++ b/src/JustSaying/Messaging/MessageSerialization/InboundMessage.cs
@@ -6,7 +6,7 @@ namespace JustSaying.Messaging.MessageSerialization;
///
/// Represents a deserialized message with attributes.
///
-public class MessageWithAttributes(Message message, MessageAttributes messageAttributes)
+public sealed class InboundMessage(Message message, MessageAttributes messageAttributes)
{
///
/// Gets the message that was extracted from a message body.
@@ -17,4 +17,10 @@ public class MessageWithAttributes(Message message, MessageAttributes messageAtt
/// Gets the attributes that were extracted from a message body.
///
public MessageAttributes MessageAttributes { get; } = messageAttributes;
+
+ public void Deconstruct(out Message message, out MessageAttributes attributes)
+ {
+ message = Message;
+ attributes = MessageAttributes;
+ }
}
diff --git a/src/JustSaying/Messaging/MessageSerialization/MessageAttributeParser.cs b/src/JustSaying/Messaging/MessageSerialization/MessageAttributeParser.cs
deleted file mode 100644
index c47cf9b94..000000000
--- a/src/JustSaying/Messaging/MessageSerialization/MessageAttributeParser.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-namespace JustSaying.Messaging.MessageSerialization;
-
-internal static class MessageAttributeParser
-{
- public static MessageAttributeValue Parse(string dataType, string dataValue)
- {
- // Check for a prefix instead of an exact match as SQS supports custom-type labels, or example, "Binary.gif".
- // See https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-message-metadata.html#sqs-message-attributes.
- bool isBinary = dataType?.StartsWith("Binary", StringComparison.Ordinal) is true;
-
- return new()
- {
- DataType = dataType,
- StringValue = !isBinary ? dataValue : null,
- BinaryValue = isBinary ? Convert.FromBase64String(dataValue) : null
- };
- }
-}
diff --git a/src/JustSaying/Messaging/MessageSerialization/MessageSerializationRegister.cs b/src/JustSaying/Messaging/MessageSerialization/MessageSerializationRegister.cs
deleted file mode 100644
index 3fa3fb4b9..000000000
--- a/src/JustSaying/Messaging/MessageSerialization/MessageSerializationRegister.cs
+++ /dev/null
@@ -1,74 +0,0 @@
-using System.Collections.Concurrent;
-using JustSaying.Models;
-
-namespace JustSaying.Messaging.MessageSerialization;
-
-public class MessageSerializationRegister(
- IMessageSubjectProvider messageSubjectProvider,
- IMessageSerializationFactory serializationFactory) : IMessageSerializationRegister
-{
- private readonly IMessageSubjectProvider _messageSubjectProvider = messageSubjectProvider ?? throw new ArgumentNullException(nameof(messageSubjectProvider));
- private readonly IMessageSerializationFactory _serializationFactory = serializationFactory;
- private readonly ConcurrentDictionary> _typeSerializersBySubject = new(StringComparer.OrdinalIgnoreCase);
- private readonly HashSet _messageSerializers = new();
-
- public void AddSerializer() where T : Message
- {
- string key = _messageSubjectProvider.GetSubjectForType(typeof(T));
-
- var typeSerializer = _typeSerializersBySubject.GetOrAdd(key,
- _ => new Lazy(
- () => new TypeSerializer(typeof(T), _serializationFactory.GetSerializer())
- )
- ).Value;
-
- _messageSerializers.Add(typeSerializer.Serializer);
- }
-
- public MessageWithAttributes DeserializeMessage(string body)
- {
- // TODO Can we remove this loop rather than try each serializer?
- foreach (var messageSerializer in _messageSerializers)
- {
- string messageSubject = messageSerializer.GetMessageSubject(body); // Custom serializer pulls this from cloud event type
-
- if (string.IsNullOrWhiteSpace(messageSubject))
- {
- continue;
- }
-
- if (!_typeSerializersBySubject.TryGetValue(messageSubject, out var lazyTypeSerializer))
- {
- continue;
- }
-
- TypeSerializer typeSerializer = lazyTypeSerializer.Value;
- var attributes = typeSerializer.Serializer.GetMessageAttributes(body);
- var message = typeSerializer.Serializer.Deserialize(body, typeSerializer.Type);
- return new MessageWithAttributes(message, attributes);
- }
-
- var exception = new MessageFormatNotSupportedException("Message can not be handled - type undetermined.");
-
- // Put the message's body into the exception data so anyone catching
- // it can inspect it for other purposes, such as for logging.
- exception.Data["MessageBody"] = body;
-
- throw exception;
- }
-
- public string Serialize(Message message, bool serializeForSnsPublishing)
- {
- var messageType = message.GetType();
- string subject = _messageSubjectProvider.GetSubjectForType(messageType);
-
- if (!_typeSerializersBySubject.TryGetValue(subject, out var lazyTypeSerializer))
- {
- throw new MessageFormatNotSupportedException($"Failed to serialize message of type {messageType} because it is not registered for serialization.");
- }
-
- var typeSerializer = lazyTypeSerializer.Value;
- IMessageSerializer messageSerializer = typeSerializer.Serializer;
- return messageSerializer.Serialize(message, serializeForSnsPublishing, subject);
- }
-}
diff --git a/src/JustSaying/Messaging/MessageSerialization/NewtonsoftMessageBodySerializer`1.cs b/src/JustSaying/Messaging/MessageSerialization/NewtonsoftMessageBodySerializer`1.cs
new file mode 100644
index 000000000..53485b2fe
--- /dev/null
+++ b/src/JustSaying/Messaging/MessageSerialization/NewtonsoftMessageBodySerializer`1.cs
@@ -0,0 +1,61 @@
+using JustSaying.Models;
+using Newtonsoft.Json;
+
+namespace JustSaying.Messaging.MessageSerialization;
+
+///
+/// Provides serialization and deserialization functionality for messages of type using Newtonsoft.Json.
+///
+/// The type of message to be serialized or deserialized. Must inherit from .
+public sealed class NewtonsoftMessageBodySerializer : IMessageBodySerializer where T: Message
+{
+ private readonly JsonSerializerSettings _settings;
+
+ ///
+ /// Initializes a new instance of the class with default JSON serializer settings.
+ ///
+ ///
+ /// Default settings include:
+ ///
+ /// - Ignoring null values when serializing.
+ /// - Using a for enum serialization.
+ ///
+ ///
+ public NewtonsoftMessageBodySerializer()
+ {
+ _settings = new JsonSerializerSettings
+ {
+ NullValueHandling = NullValueHandling.Ignore,
+ Converters = [new Newtonsoft.Json.Converters.StringEnumConverter()]
+ };
+ }
+
+ ///
+ /// Initializes a new instance of the class with custom JSON serializer settings.
+ ///
+ /// The custom to use for serialization and deserialization.
+ public NewtonsoftMessageBodySerializer(JsonSerializerSettings settings)
+ {
+ _settings = settings;
+ }
+
+ ///
+ /// Serializes a message to its JSON string representation.
+ ///
+ /// The message to serialize.
+ /// A JSON string representation of the message.
+ public string Serialize(Message message)
+ {
+ return JsonConvert.SerializeObject(message, _settings);
+ }
+
+ ///
+ /// Deserializes a JSON string to a message of type .
+ ///
+ /// The JSON string to deserialize.
+ /// A deserialized message of type .
+ public Message Deserialize(string message)
+ {
+ return JsonConvert.DeserializeObject(message, _settings);
+ }
+}
diff --git a/src/JustSaying/Messaging/MessageSerialization/NewtonsoftSerializationFactory.cs b/src/JustSaying/Messaging/MessageSerialization/NewtonsoftSerializationFactory.cs
index da7ebbe97..9c71b418a 100644
--- a/src/JustSaying/Messaging/MessageSerialization/NewtonsoftSerializationFactory.cs
+++ b/src/JustSaying/Messaging/MessageSerialization/NewtonsoftSerializationFactory.cs
@@ -1,16 +1,12 @@
+using System.Collections.Concurrent;
using JustSaying.Models;
using Newtonsoft.Json;
namespace JustSaying.Messaging.MessageSerialization;
-public class NewtonsoftSerializationFactory(JsonSerializerSettings settings) : IMessageSerializationFactory
+public sealed class NewtonsoftSerializationFactory(JsonSerializerSettings settings = null) : IMessageBodySerializationFactory
{
- private readonly NewtonsoftSerializer _serializer = new(settings);
+ private readonly ConcurrentDictionary _cache = new();
- public NewtonsoftSerializationFactory()
- : this(null)
- {
- }
-
- public IMessageSerializer GetSerializer() where T : Message => _serializer;
+ public IMessageBodySerializer GetSerializer() where T : Message => _cache.GetOrAdd(typeof(T), _ => new NewtonsoftMessageBodySerializer(settings));
}
diff --git a/src/JustSaying/Messaging/MessageSerialization/NewtonsoftSerializer.cs b/src/JustSaying/Messaging/MessageSerialization/NewtonsoftSerializer.cs
deleted file mode 100644
index 8ceeece1c..000000000
--- a/src/JustSaying/Messaging/MessageSerialization/NewtonsoftSerializer.cs
+++ /dev/null
@@ -1,88 +0,0 @@
-using JustSaying.Messaging.MessageHandling;
-using JustSaying.Models;
-using Newtonsoft.Json;
-using Newtonsoft.Json.Linq;
-
-namespace JustSaying.Messaging.MessageSerialization;
-
-public class NewtonsoftSerializer : IMessageSerializer
-{
- private readonly JsonSerializerSettings _settings;
-
- public NewtonsoftSerializer()
- : this(null)
- {
- }
-
- public NewtonsoftSerializer(JsonSerializerSettings settings)
- {
- settings ??= new JsonSerializerSettings
- {
- NullValueHandling = NullValueHandling.Ignore,
- Converters = [new Newtonsoft.Json.Converters.StringEnumConverter()]
- };
-
- _settings = settings;
- }
-
- public Message Deserialize(string message, Type type)
- {
- var document = JObject.Parse(message);
- string json = document["Message"].ToString();
-
- return (Message)JsonConvert.DeserializeObject(json, type, _settings);
- }
-
- public string Serialize(Message message, bool serializeForSnsPublishing, string subject)
- {
- var json = JsonConvert.SerializeObject(message, _settings);
-
- // AWS SNS service will add Subject and Message properties automatically,
- // so just return plain message
- if (serializeForSnsPublishing)
- {
- return json;
- }
-
- // For direct publishing to SQS, add Subject and Message properties manually
- var context = new { Subject = subject, Message = json };
- return JsonConvert.SerializeObject(context, _settings);
- }
-
- public MessageAttributes GetMessageAttributes(string message)
- {
- var props = JObject.Parse(message).Value("MessageAttributes")?.Properties();
- if (props == null)
- {
- return new MessageAttributes();
- }
-
- var attributes = new Dictionary();
-
- foreach (var property in props)
- {
- if (property.Value is not { } propertyValue)
- {
- continue;
- }
-
- var dataType = propertyValue["Type"].ToString();
- var dataValue = propertyValue["Value"].ToString();
-
- attributes.Add(property.Name, MessageAttributeParser.Parse(dataType, dataValue));
- }
-
- return new MessageAttributes(attributes);
- }
-
- public string GetMessageSubject(string sqsMessage)
- {
- if (string.IsNullOrWhiteSpace(sqsMessage))
- {
- return string.Empty;
- }
-
- var body = JObject.Parse(sqsMessage);
- return body.Value("Subject") ?? string.Empty;
- }
-}
diff --git a/src/JustSaying/Messaging/MessageSerialization/OutboundMessage.cs b/src/JustSaying/Messaging/MessageSerialization/OutboundMessage.cs
new file mode 100644
index 000000000..16f808c4a
--- /dev/null
+++ b/src/JustSaying/Messaging/MessageSerialization/OutboundMessage.cs
@@ -0,0 +1,22 @@
+namespace JustSaying.Messaging.MessageSerialization;
+
+public sealed class OutboundMessage
+{
+ public OutboundMessage(string body, Dictionary messageAttributes, string subject)
+ {
+ Body = body;
+ MessageAttributes = messageAttributes;
+ Subject = subject;
+ }
+
+ public string Body { get; }
+ public Dictionary MessageAttributes { get; }
+ public string Subject { get; }
+
+ public void Deconstruct(out string body, out Dictionary attributes, out string subject)
+ {
+ body = Body;
+ attributes = MessageAttributes;
+ subject = Subject;
+ }
+}
diff --git a/src/JustSaying/Messaging/MessageSerialization/SystemTextJsonMessageBodySerializer.cs b/src/JustSaying/Messaging/MessageSerialization/SystemTextJsonMessageBodySerializer.cs
new file mode 100644
index 000000000..3d5505313
--- /dev/null
+++ b/src/JustSaying/Messaging/MessageSerialization/SystemTextJsonMessageBodySerializer.cs
@@ -0,0 +1,26 @@
+namespace JustSaying.Messaging.MessageSerialization;
+
+using System.Text.Json;
+using System.Text.Json.Serialization;
+
+public static class SystemTextJsonMessageBodySerializer
+{
+ ///
+ /// Gets the default JSON serializer options used by derived serializers.
+ ///
+ ///
+ /// These options include:
+ ///
+ /// - Ignoring null values when writing JSON.
+ /// - Using a for enum serialization.
+ ///
+ ///
+ public static JsonSerializerOptions DefaultJsonSerializerOptions { get; } = new()
+ {
+ DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
+ Converters =
+ {
+ new JsonStringEnumConverter(),
+ },
+ };
+}
diff --git a/src/JustSaying/Messaging/MessageSerialization/SystemTextJsonMessageBodySerializer`1.cs b/src/JustSaying/Messaging/MessageSerialization/SystemTextJsonMessageBodySerializer`1.cs
new file mode 100644
index 000000000..324fa772b
--- /dev/null
+++ b/src/JustSaying/Messaging/MessageSerialization/SystemTextJsonMessageBodySerializer`1.cs
@@ -0,0 +1,42 @@
+using System.Text.Json;
+using JustSaying.Models;
+
+namespace JustSaying.Messaging.MessageSerialization;
+
+///
+/// Provides serialization and deserialization functionality for messages of type using System.Text.Json.
+///
+/// The type of message to be serialized or deserialized. Must inherit from .
+public sealed class SystemTextJsonMessageBodySerializer : IMessageBodySerializer where T: Message
+{
+ private readonly JsonSerializerOptions _options;
+
+ ///
+ /// Initializes a new instance of the class with custom JSON serializer options.
+ ///
+ /// The custom to use for serialization and deserialization.
+ public SystemTextJsonMessageBodySerializer(JsonSerializerOptions options)
+ {
+ _options = options;
+ }
+
+ ///
+ /// Serializes a message to its JSON string representation.
+ ///
+ /// The message to serialize.
+ /// A JSON string representation of the message.
+ public string Serialize(Message message)
+ {
+ return JsonSerializer.Serialize(message, message.GetType(), _options);
+ }
+
+ ///
+ /// Deserializes a JSON string to a message of type .
+ ///
+ /// The JSON string to deserialize.
+ /// A deserialized message of type .
+ public Message Deserialize(string messageBody)
+ {
+ return JsonSerializer.Deserialize(messageBody, _options);
+ }
+}
diff --git a/src/JustSaying/Messaging/MessageSerialization/SystemTextJsonSerializationFactory.cs b/src/JustSaying/Messaging/MessageSerialization/SystemTextJsonSerializationFactory.cs
index 023957b78..090b4844d 100644
--- a/src/JustSaying/Messaging/MessageSerialization/SystemTextJsonSerializationFactory.cs
+++ b/src/JustSaying/Messaging/MessageSerialization/SystemTextJsonSerializationFactory.cs
@@ -1,16 +1,12 @@
+using System.Collections.Concurrent;
using System.Text.Json;
using JustSaying.Models;
namespace JustSaying.Messaging.MessageSerialization;
-public class SystemTextJsonSerializationFactory(JsonSerializerOptions options) : IMessageSerializationFactory
+public sealed class SystemTextJsonSerializationFactory(JsonSerializerOptions options) : IMessageBodySerializationFactory
{
- private readonly SystemTextJsonSerializer _serializer = new(options);
+ private readonly ConcurrentDictionary _cache = new();
- public SystemTextJsonSerializationFactory()
- : this(null)
- {
- }
-
- public IMessageSerializer GetSerializer() where T : Message => _serializer;
+ public IMessageBodySerializer GetSerializer() where T : Message => _cache.GetOrAdd(typeof(T), _ => new SystemTextJsonMessageBodySerializer(options));
}
diff --git a/src/JustSaying/Messaging/MessageSerialization/SystemTextJsonSerializer.cs b/src/JustSaying/Messaging/MessageSerialization/SystemTextJsonSerializer.cs
deleted file mode 100644
index 7a2d04daa..000000000
--- a/src/JustSaying/Messaging/MessageSerialization/SystemTextJsonSerializer.cs
+++ /dev/null
@@ -1,106 +0,0 @@
-using System.Text.Json;
-using System.Text.Json.Serialization;
-using JustSaying.Messaging.MessageHandling;
-using JustSaying.Models;
-
-namespace JustSaying.Messaging.MessageSerialization;
-
-///
-/// A class representing an implementation of for the System.Text.Json serializer.
-///
-public class SystemTextJsonSerializer : IMessageSerializer
-{
- private static readonly JsonSerializerOptions DefaultJsonSerializerOptions = new()
- {
-#if NET8_0_OR_GREATER
- DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
-#else
- IgnoreNullValues = true,
-#endif
- Converters =
- {
- new JsonStringEnumConverter(),
- },
- };
-
- private readonly JsonSerializerOptions _options;
-
- ///
- /// Initializes a new instance of the class.
- ///
- public SystemTextJsonSerializer()
- : this(null)
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The optional to use.
- public SystemTextJsonSerializer(JsonSerializerOptions options)
- {
- _options = options ?? DefaultJsonSerializerOptions;
- }
-
- ///
- public string GetMessageSubject(string sqsMessage)
- {
- using var body = JsonDocument.Parse(sqsMessage);
- string subject = string.Empty;
-
- if (body.RootElement.TryGetProperty("Subject", out var value))
- {
- subject = value.GetString() ?? string.Empty;
- }
-
- return subject;
- }
-
- public MessageAttributes GetMessageAttributes(string message)
- {
- var jsonDocument = JsonDocument.Parse(message);
-
- if (!jsonDocument.RootElement.TryGetProperty("MessageAttributes", out var attributesElement))
- {
- return new MessageAttributes();
- }
-
- var attributes = new Dictionary();
- foreach (var property in attributesElement.EnumerateObject())
- {
- var dataType = property.Value.GetProperty("Type").GetString();
- var dataValue = property.Value.GetProperty("Value").GetString();
-
- attributes.Add(property.Name, MessageAttributeParser.Parse(dataType, dataValue));
- }
-
- return new MessageAttributes(attributes);
- }
-
- ///
- public Message Deserialize(string message, Type type)
- {
- using var document = JsonDocument.Parse(message);
- JsonElement element = document.RootElement.GetProperty("Message");
- string json = element.ToString();
-
- return (Message)JsonSerializer.Deserialize(json, type, _options);
- }
-
- ///
- public string Serialize(Message message, bool serializeForSnsPublishing, string subject)
- {
- string json = JsonSerializer.Serialize(message, message.GetType(), _options);
-
- // AWS SNS service will add Subject and Message properties automatically,
- // so just return plain message
- if (serializeForSnsPublishing)
- {
- return json;
- }
-
- // For direct publishing to SQS, add Subject and Message properties manually
- var context = new { Subject = subject, Message = json };
- return JsonSerializer.Serialize(context, _options);
- }
-}
diff --git a/src/JustSaying/Messaging/MessageSerialization/TypeSerializer.cs b/src/JustSaying/Messaging/MessageSerialization/TypeSerializer.cs
deleted file mode 100644
index 6f116d7b9..000000000
--- a/src/JustSaying/Messaging/MessageSerialization/TypeSerializer.cs
+++ /dev/null
@@ -1,7 +0,0 @@
-namespace JustSaying.Messaging.MessageSerialization;
-
-public class TypeSerializer(Type type, IMessageSerializer serializer)
-{
- public Type Type { get; private set; } = type;
- public IMessageSerializer Serializer { get; private set; } = serializer;
-}
diff --git a/src/JustSaying/Messaging/Middleware/ErrorHandling/ErrorHandlerMiddleware.cs b/src/JustSaying/Messaging/Middleware/ErrorHandling/ErrorHandlerMiddleware.cs
index 1970a07c1..44d5dc7df 100644
--- a/src/JustSaying/Messaging/Middleware/ErrorHandling/ErrorHandlerMiddleware.cs
+++ b/src/JustSaying/Messaging/Middleware/ErrorHandling/ErrorHandlerMiddleware.cs
@@ -22,6 +22,11 @@ protected override async Task RunInnerAsync(HandleMessageContext context,
{
return await func(stoppingToken).ConfigureAwait(false);
}
+ catch (OperationCanceledException)
+ {
+ // Do not log OperationCanceledException
+ return false;
+ }
catch (Exception e)
{
_monitor.HandleException(context.MessageType);
diff --git a/src/JustSaying/Messaging/Middleware/Handle/HandlerMiddlewareBuilder.cs b/src/JustSaying/Messaging/Middleware/Handle/HandlerMiddlewareBuilder.cs
index 77c07c11b..7cbaafe9d 100644
--- a/src/JustSaying/Messaging/Middleware/Handle/HandlerMiddlewareBuilder.cs
+++ b/src/JustSaying/Messaging/Middleware/Handle/HandlerMiddlewareBuilder.cs
@@ -108,7 +108,6 @@ public HandlerMiddlewareBuilder UseHandler() where TMessage : Message
/// An that customises
/// the pipeline.
///
-
public HandlerMiddlewareBuilder Configure(
Action configure)
{
diff --git a/src/JustSaying/Messaging/PublishMetadata.cs b/src/JustSaying/Messaging/PublishMetadata.cs
index cde53e33a..b1b499fbf 100644
--- a/src/JustSaying/Messaging/PublishMetadata.cs
+++ b/src/JustSaying/Messaging/PublishMetadata.cs
@@ -16,7 +16,7 @@ public PublishMetadata AddMessageAttribute(string key, IReadOnlyCollection
DataType = "Binary"
};
- MessageAttributes[key] = mav;
+ AddMessageAttribute(key, mav);
return this;
}
diff --git a/src/JustSaying/MessagingBusBuilder.cs b/src/JustSaying/MessagingBusBuilder.cs
index 138bbe85e..eb2c11c77 100644
--- a/src/JustSaying/MessagingBusBuilder.cs
+++ b/src/JustSaying/MessagingBusBuilder.cs
@@ -277,11 +277,11 @@ public IMessagingBus BuildSubscribers()
private JustSayingBus CreateBus(IMessagingConfig config, ILoggerFactory loggerFactory, IPublishBatchConfiguration publishBatchConfiguration = null)
{
- IMessageSerializationRegister register = ServiceResolver.ResolveService();
+ IMessageBodySerializationFactory serializationFactory = ServiceResolver.ResolveService();
IMessageReceivePauseSignal messageReceivePauseSignal = ServiceResolver.ResolveService();
IMessageMonitor monitor = ServiceResolver.ResolveOptionalService() ?? new NullOpMessageMonitor();
- return new JustSayingBus(config, register, messageReceivePauseSignal, loggerFactory, monitor, publishBatchConfiguration);
+ return new JustSayingBus(config, serializationFactory, messageReceivePauseSignal, loggerFactory, monitor, publishBatchConfiguration);
}
private IAwsClientFactoryProxy CreateFactoryProxy()
diff --git a/src/JustSaying/MessagingConfig.cs b/src/JustSaying/MessagingConfig.cs
index f7a1404b5..bec14ea19 100644
--- a/src/JustSaying/MessagingConfig.cs
+++ b/src/JustSaying/MessagingConfig.cs
@@ -16,6 +16,7 @@ public MessagingConfig()
MessageSubjectProvider = new NonGenericMessageSubjectProvider();
TopicNamingConvention = new DefaultNamingConventions();
QueueNamingConvention = new DefaultNamingConventions();
+ DefaultCompressionOptions = new PublishCompressionOptions();
}
public int PublishFailureReAttempts { get; set; }
@@ -27,6 +28,7 @@ public MessagingConfig()
public IMessageSubjectProvider MessageSubjectProvider { get; set; }
public ITopicNamingConvention TopicNamingConvention { get; set; }
public IQueueNamingConvention QueueNamingConvention { get; set; }
+ public PublishCompressionOptions DefaultCompressionOptions { get; set; }
public virtual void Validate()
{
diff --git a/src/JustSaying/Naming/DefaultNamingConventions.cs b/src/JustSaying/Naming/DefaultNamingConventions.cs
index 8eb9fbd89..e89245021 100644
--- a/src/JustSaying/Naming/DefaultNamingConventions.cs
+++ b/src/JustSaying/Naming/DefaultNamingConventions.cs
@@ -51,7 +51,7 @@ private static string GetTypeFriendlyName(Type type)
return friendlyName;
}
- if (type.GetTypeInfo().IsGenericType)
+ if (type.IsGenericType)
{
var indexOfBacktick = friendlyName.IndexOf('`');
diff --git a/src/JustSaying/PublicAPI/PublicAPI.Shipped.txt b/src/JustSaying/PublicAPI/PublicAPI.Shipped.txt
new file mode 100644
index 000000000..329b99311
--- /dev/null
+++ b/src/JustSaying/PublicAPI/PublicAPI.Shipped.txt
@@ -0,0 +1,735 @@
+abstract JustSaying.AwsTools.MessageHandling.SqsQueueByNameBase.GetCreateQueueAttributes(JustSaying.AwsTools.QueueCreation.SqsBasicConfiguration queueConfig) -> System.Collections.Generic.Dictionary
+abstract JustSaying.Messaging.Middleware.MiddlewareBase.RunInnerAsync(TContext context, System.Func> func, System.Threading.CancellationToken stoppingToken) -> System.Threading.Tasks.Task
+const JustSaying.AwsTools.JustSayingConstants.AttributeArn = "QueueArn" -> string
+const JustSaying.AwsTools.JustSayingConstants.AttributeDeliveryDelay = "DelaySeconds" -> string
+const JustSaying.AwsTools.JustSayingConstants.AttributeEncryptionKeyId = "KmsMasterKeyId" -> string
+const JustSaying.AwsTools.JustSayingConstants.AttributeEncryptionKeyReusePeriodSecondId = "KmsDataKeyReusePeriodSeconds" -> string
+const JustSaying.AwsTools.JustSayingConstants.AttributePolicy = "Policy" -> string
+const JustSaying.AwsTools.JustSayingConstants.AttributeRedrivePolicy = "RedrivePolicy" -> string
+const JustSaying.AwsTools.JustSayingConstants.AttributeRetentionPeriod = "MessageRetentionPeriod" -> string
+const JustSaying.AwsTools.JustSayingConstants.AttributeVisibilityTimeout = "VisibilityTimeout" -> string
+JustSaying.AwsTools.AwsClientFactoryProxy
+JustSaying.AwsTools.AwsClientFactoryProxy.AwsClientFactoryProxy() -> void
+JustSaying.AwsTools.AwsClientFactoryProxy.AwsClientFactoryProxy(System.Func awsClientFactoryFunc) -> void
+JustSaying.AwsTools.AwsClientFactoryProxy.AwsClientFactoryProxy(System.Lazy factory) -> void
+JustSaying.AwsTools.AwsClientFactoryProxy.GetAwsClientFactory() -> JustSaying.AwsTools.IAwsClientFactory
+JustSaying.AwsTools.AwsClientFactoryProxy.SetAwsClientFactory(System.Func func) -> void
+JustSaying.AwsTools.DefaultAwsClientFactory
+JustSaying.AwsTools.DefaultAwsClientFactory.DefaultAwsClientFactory() -> void
+JustSaying.AwsTools.DefaultAwsClientFactory.DefaultAwsClientFactory(Amazon.Runtime.AWSCredentials customCredentials) -> void
+JustSaying.AwsTools.DefaultAwsClientFactory.GetSnsClient(Amazon.RegionEndpoint region) -> Amazon.SimpleNotificationService.IAmazonSimpleNotificationService
+JustSaying.AwsTools.DefaultAwsClientFactory.GetSqsClient(Amazon.RegionEndpoint region) -> Amazon.SQS.IAmazonSQS
+JustSaying.AwsTools.DefaultAwsClientFactory.ServiceUri.get -> System.Uri
+JustSaying.AwsTools.DefaultAwsClientFactory.ServiceUri.set -> void
+JustSaying.AwsTools.ErrorQueue
+JustSaying.AwsTools.ErrorQueue.ErrorQueue(Amazon.RegionEndpoint region, string sourceQueueName, Amazon.SQS.IAmazonSQS client, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) -> void
+JustSaying.AwsTools.IAwsClientFactory
+JustSaying.AwsTools.IAwsClientFactory.GetSnsClient(Amazon.RegionEndpoint region) -> Amazon.SimpleNotificationService.IAmazonSimpleNotificationService
+JustSaying.AwsTools.IAwsClientFactory.GetSqsClient(Amazon.RegionEndpoint region) -> Amazon.SQS.IAmazonSQS
+JustSaying.AwsTools.IAwsClientFactoryProxy
+JustSaying.AwsTools.IAwsClientFactoryProxy.GetAwsClientFactory() -> JustSaying.AwsTools.IAwsClientFactory
+JustSaying.AwsTools.IAwsClientFactoryProxy.SetAwsClientFactory(System.Func func) -> void
+JustSaying.AwsTools.JustSayingConstants
+JustSaying.AwsTools.MessageHandling.Dispatch.IMessageDispatcher
+JustSaying.AwsTools.MessageHandling.Dispatch.IMessageDispatcher.DispatchMessageAsync(JustSaying.Messaging.Channels.Context.IQueueMessageContext messageContext, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task
+JustSaying.AwsTools.MessageHandling.Dispatch.MessageDispatcher
+JustSaying.AwsTools.MessageHandling.Dispatch.MessageDispatcher.DispatchMessageAsync(JustSaying.Messaging.Channels.Context.IQueueMessageContext messageContext, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task
+JustSaying.AwsTools.MessageHandling.Dispatch.MessageDispatcher.MessageDispatcher(JustSaying.Messaging.MessageSerialization.IMessageSerializationRegister serializationRegister, JustSaying.Messaging.Monitoring.IMessageMonitor messagingMonitor, JustSaying.AwsTools.MessageHandling.Dispatch.MiddlewareMap middlewareMap, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) -> void
+JustSaying.AwsTools.MessageHandling.Dispatch.MiddlewareMap
+JustSaying.AwsTools.MessageHandling.Dispatch.MiddlewareMap.Add(string queueName, JustSaying.Messaging.Middleware.MiddlewareBase middleware) -> JustSaying.AwsTools.MessageHandling.Dispatch.MiddlewareMap
+JustSaying.AwsTools.MessageHandling.Dispatch.MiddlewareMap.Contains(string queueName, System.Type messageType) -> bool
+JustSaying.AwsTools.MessageHandling.Dispatch.MiddlewareMap.Get(string queueName, System.Type messageType) -> JustSaying.Messaging.Middleware.MiddlewareBase
+JustSaying.AwsTools.MessageHandling.Dispatch.MiddlewareMap.Interrogate() -> JustSaying.Messaging.Interrogation.InterrogationResult
+JustSaying.AwsTools.MessageHandling.Dispatch.MiddlewareMap.MiddlewareMap() -> void
+JustSaying.AwsTools.MessageHandling.Dispatch.MiddlewareMap.Types.get -> System.Collections.Generic.IEnumerable
+JustSaying.AwsTools.MessageHandling.ISqsQueue
+JustSaying.AwsTools.MessageHandling.ISqsQueue.Arn.get -> string
+JustSaying.AwsTools.MessageHandling.ISqsQueue.ChangeMessageVisibilityAsync(string queueUrl, string receiptHandle, int visibilityTimeoutInSeconds, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task
+JustSaying.AwsTools.MessageHandling.ISqsQueue.DeleteMessageAsync(string queueUrl, string receiptHandle, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task
+JustSaying.AwsTools.MessageHandling.ISqsQueue.QueueName.get -> string
+JustSaying.AwsTools.MessageHandling.ISqsQueue.ReceiveMessagesAsync(string queueUrl, int maxNumOfMessages, int secondsWaitTime, System.Collections.Generic.IList attributesToLoad, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task>
+JustSaying.AwsTools.MessageHandling.ISqsQueue.RegionSystemName.get -> string
+JustSaying.AwsTools.MessageHandling.ISqsQueue.TagQueueAsync(string queueUrl, System.Collections.Generic.Dictionary tags, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task
+JustSaying.AwsTools.MessageHandling.ISqsQueue.Uri.get -> System.Uri
+JustSaying.AwsTools.MessageHandling.MessageResponse
+JustSaying.AwsTools.MessageHandling.MessageResponse.HttpStatusCode.get -> System.Net.HttpStatusCode?
+JustSaying.AwsTools.MessageHandling.MessageResponse.HttpStatusCode.set -> void
+JustSaying.AwsTools.MessageHandling.MessageResponse.MessageId.get -> string
+JustSaying.AwsTools.MessageHandling.MessageResponse.MessageId.set -> void
+JustSaying.AwsTools.MessageHandling.MessageResponse.MessageResponse() -> void
+JustSaying.AwsTools.MessageHandling.MessageResponse.ResponseMetadata.get -> Amazon.Runtime.ResponseMetadata
+JustSaying.AwsTools.MessageHandling.MessageResponse.ResponseMetadata.set -> void
+JustSaying.AwsTools.MessageHandling.PublishException
+JustSaying.AwsTools.MessageHandling.PublishException.PublishException() -> void
+JustSaying.AwsTools.MessageHandling.PublishException.PublishException(string message) -> void
+JustSaying.AwsTools.MessageHandling.PublishException.PublishException(string message, System.Exception inner) -> void
+JustSaying.AwsTools.MessageHandling.QueueWithAsyncStartup
+JustSaying.AwsTools.MessageHandling.QueueWithAsyncStartup.Queue.get -> JustSaying.AwsTools.MessageHandling.ISqsQueue
+JustSaying.AwsTools.MessageHandling.QueueWithAsyncStartup.QueueWithAsyncStartup(JustSaying.AwsTools.MessageHandling.ISqsQueue queue) -> void
+JustSaying.AwsTools.MessageHandling.QueueWithAsyncStartup.QueueWithAsyncStartup(System.Func startupTask, JustSaying.AwsTools.MessageHandling.ISqsQueue queue) -> void
+JustSaying.AwsTools.MessageHandling.QueueWithAsyncStartup.StartupTask.get -> System.Func
+JustSaying.AwsTools.MessageHandling.SnsMessagePublisher
+JustSaying.AwsTools.MessageHandling.SnsMessagePublisher.Arn.get -> string
+JustSaying.AwsTools.MessageHandling.SnsMessagePublisher.Client.get -> Amazon.SimpleNotificationService.IAmazonSimpleNotificationService
+JustSaying.AwsTools.MessageHandling.SnsMessagePublisher.MessageResponseLogger.get -> System.Action
+JustSaying.AwsTools.MessageHandling.SnsMessagePublisher.MessageResponseLogger.set -> void
+JustSaying.AwsTools.MessageHandling.SnsMessagePublisher.PublishAsync(JustSaying.Models.Message message, JustSaying.Messaging.PublishMetadata metadata, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task
+JustSaying.AwsTools.MessageHandling.SnsMessagePublisher.PublishAsync(JustSaying.Models.Message message, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task
+JustSaying.AwsTools.MessageHandling.SnsMessagePublisher.SnsMessagePublisher(Amazon.SimpleNotificationService.IAmazonSimpleNotificationService client, JustSaying.Messaging.MessageSerialization.IMessageSerializationRegister serializationRegister, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory, JustSaying.Messaging.MessageSerialization.IMessageSubjectProvider messageSubjectProvider, System.Func handleException = null) -> void
+JustSaying.AwsTools.MessageHandling.SnsMessagePublisher.SnsMessagePublisher(string topicArn, Amazon.SimpleNotificationService.IAmazonSimpleNotificationService client, JustSaying.Messaging.MessageSerialization.IMessageSerializationRegister serializationRegister, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory, JustSaying.Messaging.MessageSerialization.IMessageSubjectProvider messageSubjectProvider, System.Func handleException = null) -> void
+JustSaying.AwsTools.MessageHandling.SnsMessagePublisher.StartAsync(System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task
+JustSaying.AwsTools.MessageHandling.SnsTopicByName
+JustSaying.AwsTools.MessageHandling.SnsTopicByName.ApplyTagsAsync(System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task
+JustSaying.AwsTools.MessageHandling.SnsTopicByName.Arn.get -> string
+JustSaying.AwsTools.MessageHandling.SnsTopicByName.CreateAsync(System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task
+JustSaying.AwsTools.MessageHandling.SnsTopicByName.CreateWithEncryptionAsync(JustSaying.AwsTools.QueueCreation.ServerSideEncryption config, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task
+JustSaying.AwsTools.MessageHandling.SnsTopicByName.EnsurePolicyIsUpdatedAsync(System.Collections.Generic.IReadOnlyCollection additionalSubscriberAccounts) -> System.Threading.Tasks.Task
+JustSaying.AwsTools.MessageHandling.SnsTopicByName.ExistsAsync(System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task
+JustSaying.AwsTools.MessageHandling.SnsTopicByName.Interrogate() -> JustSaying.Messaging.Interrogation.InterrogationResult
+JustSaying.AwsTools.MessageHandling.SnsTopicByName.SnsTopicByName(string topicName, Amazon.SimpleNotificationService.IAmazonSimpleNotificationService client, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) -> void
+JustSaying.AwsTools.MessageHandling.SnsTopicByName.Tags.get -> System.Collections.Generic.IDictionary
+JustSaying.AwsTools.MessageHandling.SnsTopicByName.Tags.set -> void
+JustSaying.AwsTools.MessageHandling.SnsTopicByName.TopicName.get -> string
+JustSaying.AwsTools.MessageHandling.SqsMessagePublisher
+JustSaying.AwsTools.MessageHandling.SqsMessagePublisher.GetMessageInContext(JustSaying.Models.Message message) -> string
+JustSaying.AwsTools.MessageHandling.SqsMessagePublisher.Interrogate() -> JustSaying.Messaging.Interrogation.InterrogationResult
+JustSaying.AwsTools.MessageHandling.SqsMessagePublisher.MessageResponseLogger.get -> System.Action
+JustSaying.AwsTools.MessageHandling.SqsMessagePublisher.MessageResponseLogger.set -> void
+JustSaying.AwsTools.MessageHandling.SqsMessagePublisher.PublishAsync(JustSaying.Models.Message message, JustSaying.Messaging.PublishMetadata metadata, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task
+JustSaying.AwsTools.MessageHandling.SqsMessagePublisher.PublishAsync(JustSaying.Models.Message message, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task
+JustSaying.AwsTools.MessageHandling.SqsMessagePublisher.QueueUrl.get -> System.Uri
+JustSaying.AwsTools.MessageHandling.SqsMessagePublisher.SqsMessagePublisher(Amazon.SQS.IAmazonSQS client, JustSaying.Messaging.MessageSerialization.IMessageSerializationRegister serializationRegister, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) -> void
+JustSaying.AwsTools.MessageHandling.SqsMessagePublisher.SqsMessagePublisher(System.Uri queueUrl, Amazon.SQS.IAmazonSQS client, JustSaying.Messaging.MessageSerialization.IMessageSerializationRegister serializationRegister, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) -> void
+JustSaying.AwsTools.MessageHandling.SqsMessagePublisher.StartAsync(System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task
+JustSaying.AwsTools.MessageHandling.SqsQueueByName
+JustSaying.AwsTools.MessageHandling.SqsQueueByName.EnsureQueueAndErrorQueueExistAndAllAttributesAreUpdatedAsync(JustSaying.AwsTools.QueueCreation.SqsReadConfiguration queueConfig, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task
+JustSaying.AwsTools.MessageHandling.SqsQueueByName.SqsQueueByName(Amazon.RegionEndpoint region, string queueName, Amazon.SQS.IAmazonSQS client, int retryCountBeforeSendingToErrorQueue, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) -> void
+JustSaying.AwsTools.MessageHandling.SqsQueueByNameBase
+JustSaying.AwsTools.MessageHandling.SqsQueueByNameBase.Arn.get -> string
+JustSaying.AwsTools.MessageHandling.SqsQueueByNameBase.ChangeMessageVisibilityAsync(string queueUrl, string receiptHandle, int visibilityTimeoutInSeconds, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task
+JustSaying.AwsTools.MessageHandling.SqsQueueByNameBase.Client.get -> Amazon.SQS.IAmazonSQS
+JustSaying.AwsTools.MessageHandling.SqsQueueByNameBase.DeleteMessageAsync(string queueUrl, string receiptHandle, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task
+JustSaying.AwsTools.MessageHandling.SqsQueueByNameBase.Logger.get -> Microsoft.Extensions.Logging.ILogger
+JustSaying.AwsTools.MessageHandling.SqsQueueByNameBase.QueueName.get -> string
+JustSaying.AwsTools.MessageHandling.SqsQueueByNameBase.ReceiveMessagesAsync(string queueUrl, int maxNumOfMessages, int secondsWaitTime, System.Collections.Generic.IList attributesToLoad, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task>
+JustSaying.AwsTools.MessageHandling.SqsQueueByNameBase.RegionSystemName.get -> string
+JustSaying.AwsTools.MessageHandling.SqsQueueByNameBase.SqsQueueByNameBase(Amazon.RegionEndpoint region, string queueName, Amazon.SQS.IAmazonSQS client, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) -> void
+JustSaying.AwsTools.MessageHandling.SqsQueueByNameBase.TagQueueAsync(string queueUrl, System.Collections.Generic.Dictionary tags, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task
+JustSaying.AwsTools.MessageHandling.SqsQueueByNameBase.Uri.get -> System.Uri
+JustSaying.AwsTools.QueueCreation.AmazonQueueCreator
+JustSaying.AwsTools.QueueCreation.AmazonQueueCreator.AmazonQueueCreator(JustSaying.AwsTools.IAwsClientFactoryProxy awsClientFactory, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) -> void
+JustSaying.AwsTools.QueueCreation.AmazonQueueCreator.EnsureQueueExists(string region, JustSaying.AwsTools.QueueCreation.SqsReadConfiguration queueConfig) -> JustSaying.AwsTools.MessageHandling.QueueWithAsyncStartup
+JustSaying.AwsTools.QueueCreation.AmazonQueueCreator.EnsureTopicExistsWithQueueSubscribed(string region, JustSaying.AwsTools.QueueCreation.SqsReadConfiguration queueConfig) -> JustSaying.AwsTools.MessageHandling.QueueWithAsyncStartup
+JustSaying.AwsTools.QueueCreation.ConfigurationErrorsException
+JustSaying.AwsTools.QueueCreation.ConfigurationErrorsException.ConfigurationErrorsException() -> void
+JustSaying.AwsTools.QueueCreation.ConfigurationErrorsException.ConfigurationErrorsException(string message) -> void
+JustSaying.AwsTools.QueueCreation.ConfigurationErrorsException.ConfigurationErrorsException(string message, System.Exception inner) -> void
+JustSaying.AwsTools.QueueCreation.IVerifyAmazonQueues
+JustSaying.AwsTools.QueueCreation.IVerifyAmazonQueues.EnsureQueueExists(string region, JustSaying.AwsTools.QueueCreation.SqsReadConfiguration queueConfig) -> JustSaying.AwsTools.MessageHandling.QueueWithAsyncStartup
+JustSaying.AwsTools.QueueCreation.IVerifyAmazonQueues.EnsureTopicExistsWithQueueSubscribed(string region, JustSaying.AwsTools.QueueCreation.SqsReadConfiguration queueConfig) -> JustSaying.AwsTools.MessageHandling.QueueWithAsyncStartup
+JustSaying.AwsTools.QueueCreation.ServerSideEncryption
+JustSaying.AwsTools.QueueCreation.ServerSideEncryption.KmsDataKeyReusePeriod.get -> System.TimeSpan
+JustSaying.AwsTools.QueueCreation.ServerSideEncryption.KmsDataKeyReusePeriod.set -> void
+JustSaying.AwsTools.QueueCreation.ServerSideEncryption.KmsMasterKeyId.get -> string
+JustSaying.AwsTools.QueueCreation.ServerSideEncryption.KmsMasterKeyId.set -> void
+JustSaying.AwsTools.QueueCreation.ServerSideEncryption.ServerSideEncryption() -> void
+JustSaying.AwsTools.QueueCreation.SnsWriteConfiguration
+JustSaying.AwsTools.QueueCreation.SnsWriteConfiguration.Encryption.get -> JustSaying.AwsTools.QueueCreation.ServerSideEncryption
+JustSaying.AwsTools.QueueCreation.SnsWriteConfiguration.Encryption.set -> void
+JustSaying.AwsTools.QueueCreation.SnsWriteConfiguration.HandleException.get -> System.Func
+JustSaying.AwsTools.QueueCreation.SnsWriteConfiguration.HandleException.set -> void
+JustSaying.AwsTools.QueueCreation.SnsWriteConfiguration.SnsWriteConfiguration() -> void
+JustSaying.AwsTools.QueueCreation.SqsBasicConfiguration
+JustSaying.AwsTools.QueueCreation.SqsBasicConfiguration.ApplyQueueNamingConvention(JustSaying.Naming.IQueueNamingConvention namingConvention) -> void
+JustSaying.AwsTools.QueueCreation.SqsBasicConfiguration.DeliveryDelay.get -> System.TimeSpan
+JustSaying.AwsTools.QueueCreation.SqsBasicConfiguration.DeliveryDelay.set -> void
+JustSaying.AwsTools.QueueCreation.SqsBasicConfiguration.ErrorQueueOptOut.get -> bool
+JustSaying.AwsTools.QueueCreation.SqsBasicConfiguration.ErrorQueueOptOut.set -> void
+JustSaying.AwsTools.QueueCreation.SqsBasicConfiguration.ErrorQueueRetentionPeriod.get -> System.TimeSpan
+JustSaying.AwsTools.QueueCreation.SqsBasicConfiguration.ErrorQueueRetentionPeriod.set -> void
+JustSaying.AwsTools.QueueCreation.SqsBasicConfiguration.MessageRetention.get -> System.TimeSpan
+JustSaying.AwsTools.QueueCreation.SqsBasicConfiguration.MessageRetention.set -> void
+JustSaying.AwsTools.QueueCreation.SqsBasicConfiguration.QueueName.get -> string
+JustSaying.AwsTools.QueueCreation.SqsBasicConfiguration.QueueName.set -> void
+JustSaying.AwsTools.QueueCreation.SqsBasicConfiguration.RetryCountBeforeSendingToErrorQueue.get -> int
+JustSaying.AwsTools.QueueCreation.SqsBasicConfiguration.RetryCountBeforeSendingToErrorQueue.set -> void
+JustSaying.AwsTools.QueueCreation.SqsBasicConfiguration.ServerSideEncryption.get -> JustSaying.AwsTools.QueueCreation.ServerSideEncryption
+JustSaying.AwsTools.QueueCreation.SqsBasicConfiguration.ServerSideEncryption.set -> void
+JustSaying.AwsTools.QueueCreation.SqsBasicConfiguration.SqsBasicConfiguration() -> void
+JustSaying.AwsTools.QueueCreation.SqsBasicConfiguration.Validate() -> void
+JustSaying.AwsTools.QueueCreation.SqsBasicConfiguration.VisibilityTimeout.get -> System.TimeSpan
+JustSaying.AwsTools.QueueCreation.SqsBasicConfiguration.VisibilityTimeout.set -> void
+JustSaying.AwsTools.QueueCreation.SqsReadConfiguration
+JustSaying.AwsTools.QueueCreation.SqsReadConfiguration.ApplyTopicNamingConvention(JustSaying.Naming.ITopicNamingConvention namingConvention) -> void
+JustSaying.AwsTools.QueueCreation.SqsReadConfiguration.FilterPolicy.get -> string
+JustSaying.AwsTools.QueueCreation.SqsReadConfiguration.FilterPolicy.set -> void
+JustSaying.AwsTools.QueueCreation.SqsReadConfiguration.PublishEndpoint.get -> string
+JustSaying.AwsTools.QueueCreation.SqsReadConfiguration.PublishEndpoint.set -> void
+JustSaying.AwsTools.QueueCreation.SqsReadConfiguration.SqsReadConfiguration(JustSaying.AwsTools.QueueCreation.SubscriptionType subscriptionType) -> void
+JustSaying.AwsTools.QueueCreation.SqsReadConfiguration.SubscriptionGroupName.get -> string
+JustSaying.AwsTools.QueueCreation.SqsReadConfiguration.SubscriptionGroupName.set -> void
+JustSaying.AwsTools.QueueCreation.SqsReadConfiguration.SubscriptionType.get -> JustSaying.AwsTools.QueueCreation.SubscriptionType
+JustSaying.AwsTools.QueueCreation.SqsReadConfiguration.Tags.get -> System.Collections.Generic.Dictionary
+JustSaying.AwsTools.QueueCreation.SqsReadConfiguration.Tags.set -> void
+JustSaying.AwsTools.QueueCreation.SqsReadConfiguration.TopicName.get -> string
+JustSaying.AwsTools.QueueCreation.SqsReadConfiguration.TopicName.set -> void
+JustSaying.AwsTools.QueueCreation.SqsReadConfiguration.TopicSourceAccount.get -> string
+JustSaying.AwsTools.QueueCreation.SqsReadConfiguration.TopicSourceAccount.set -> void
+JustSaying.AwsTools.QueueCreation.SqsWriteConfiguration
+JustSaying.AwsTools.QueueCreation.SqsWriteConfiguration.SqsWriteConfiguration() -> void
+JustSaying.AwsTools.QueueCreation.SubscriptionType
+JustSaying.AwsTools.QueueCreation.SubscriptionType.PointToPoint = 1 -> JustSaying.AwsTools.QueueCreation.SubscriptionType
+JustSaying.AwsTools.QueueCreation.SubscriptionType.ToTopic = 0 -> JustSaying.AwsTools.QueueCreation.SubscriptionType
+JustSaying.Extensions.ChannelExtensions
+JustSaying.Fluent.AccountAddressProvider
+JustSaying.Fluent.AccountAddressProvider.AccountAddressProvider(string accountId, Amazon.RegionEndpoint regionEndpoint) -> void
+JustSaying.Fluent.AccountAddressProvider.AccountAddressProvider(string accountId, Amazon.RegionEndpoint regionEndpoint, JustSaying.Naming.IQueueNamingConvention queueNamingConvention, JustSaying.Naming.ITopicNamingConvention topicNamingConvention) -> void
+JustSaying.Fluent.AccountAddressProvider.AccountAddressProvider(string accountId, string regionName) -> void
+JustSaying.Fluent.AccountAddressProvider.AccountAddressProvider(string accountId, string regionName, JustSaying.Naming.IQueueNamingConvention queueNamingConvention, JustSaying.Naming.ITopicNamingConvention topicNamingConvention) -> void
+JustSaying.Fluent.AccountAddressProvider.GetQueueUri(string queueName) -> System.Uri
+JustSaying.Fluent.AccountAddressProvider.GetQueueUriByConvention() -> System.Uri
+JustSaying.Fluent.AccountAddressProvider.GetTopicArn(string topicName) -> string
+JustSaying.Fluent.AccountAddressProvider.GetTopicArnByConvention() -> string
+JustSaying.Fluent.AwsClientFactoryBuilder
+JustSaying.Fluent.AwsClientFactoryBuilder.Build() -> JustSaying.AwsTools.IAwsClientFactory
+JustSaying.Fluent.AwsClientFactoryBuilder.BusBuilder.get -> JustSaying.MessagingBusBuilder
+JustSaying.Fluent.AwsClientFactoryBuilder.WithAnonymousCredentials() -> JustSaying.Fluent.AwsClientFactoryBuilder
+JustSaying.Fluent.AwsClientFactoryBuilder.WithBasicCredentials(string accessKey, string secretKey) -> JustSaying.Fluent.AwsClientFactoryBuilder
+JustSaying.Fluent.AwsClientFactoryBuilder.WithClientFactory(System.Func clientFactory) -> JustSaying.Fluent.AwsClientFactoryBuilder
+JustSaying.Fluent.AwsClientFactoryBuilder.WithCredentials(Amazon.Runtime.AWSCredentials credentials) -> JustSaying.Fluent.AwsClientFactoryBuilder
+JustSaying.Fluent.AwsClientFactoryBuilder.WithServiceUri(System.Uri uri) -> JustSaying.Fluent.AwsClientFactoryBuilder
+JustSaying.Fluent.AwsClientFactoryBuilder.WithServiceUrl(string url) -> JustSaying.Fluent.AwsClientFactoryBuilder
+JustSaying.Fluent.AwsClientFactoryBuilder.WithSessionCredentials(string accessKeyId, string secretAccessKey, string token) -> JustSaying.Fluent.AwsClientFactoryBuilder
+JustSaying.Fluent.IMessageBusConfigurationContributor
+JustSaying.Fluent.IMessageBusConfigurationContributor.Configure(JustSaying.MessagingBusBuilder builder) -> void
+JustSaying.Fluent.IServiceResolver
+JustSaying.Fluent.IServiceResolver.ResolveOptionalService() -> T
+JustSaying.Fluent.IServiceResolver.ResolveService() -> T
+JustSaying.Fluent.ISubscriptionBuilder
+JustSaying.Fluent.ISubscriptionBuilder.Configure(JustSaying.JustSayingBus bus, JustSaying.IHandlerResolver handlerResolver, JustSaying.Fluent.IServiceResolver serviceResolver, JustSaying.AwsTools.QueueCreation.IVerifyAmazonQueues creator, JustSaying.AwsTools.IAwsClientFactoryProxy awsClientFactoryProxy, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) -> void
+JustSaying.Fluent.ISubscriptionBuilder.WithMiddlewareConfiguration(System.Action middlewareConfiguration) -> JustSaying.Fluent.ISubscriptionBuilder
+JustSaying.Fluent.MessagingConfigurationBuilder
+JustSaying.Fluent.MessagingConfigurationBuilder.Build() -> JustSaying.IMessagingConfig
+JustSaying.Fluent.MessagingConfigurationBuilder.BusBuilder.get -> JustSaying.MessagingBusBuilder
+JustSaying.Fluent.MessagingConfigurationBuilder.WithAdditionalSubscriberAccount(string accountId) -> JustSaying.Fluent.MessagingConfigurationBuilder
+JustSaying.Fluent.MessagingConfigurationBuilder.WithAdditionalSubscriberAccounts(params string[] regions) -> JustSaying.Fluent.MessagingConfigurationBuilder
+JustSaying.Fluent.MessagingConfigurationBuilder.WithAdditionalSubscriberAccounts(System.Collections.Generic.IEnumerable accountIds) -> JustSaying.Fluent.MessagingConfigurationBuilder
+JustSaying.Fluent.MessagingConfigurationBuilder.WithMessageResponseLogger(System.Action logger) -> JustSaying.Fluent.MessagingConfigurationBuilder
+JustSaying.Fluent.MessagingConfigurationBuilder.WithMessageSubjectProvider(JustSaying.Messaging.MessageSerialization.IMessageSubjectProvider subjectProvider) -> JustSaying.Fluent.MessagingConfigurationBuilder
+JustSaying.Fluent.MessagingConfigurationBuilder.WithPublishFailureBackoff(System.TimeSpan value) -> JustSaying.Fluent.MessagingConfigurationBuilder
+JustSaying.Fluent.MessagingConfigurationBuilder.WithPublishFailureReattempts(int value) -> JustSaying.Fluent.MessagingConfigurationBuilder
+JustSaying.Fluent.MessagingConfigurationBuilder.WithQueueNamingConvention(JustSaying.Naming.IQueueNamingConvention namingConvention) -> JustSaying.Fluent.MessagingConfigurationBuilder
+JustSaying.Fluent.MessagingConfigurationBuilder.WithQueueNamingConvention() -> JustSaying.Fluent.MessagingConfigurationBuilder
+JustSaying.Fluent.MessagingConfigurationBuilder.WithRegion(Amazon.RegionEndpoint region) -> JustSaying.Fluent.MessagingConfigurationBuilder
+JustSaying.Fluent.MessagingConfigurationBuilder.WithRegion(string region) -> JustSaying.Fluent.MessagingConfigurationBuilder
+JustSaying.Fluent.MessagingConfigurationBuilder.WithTopicNamingConvention(JustSaying.Naming.ITopicNamingConvention namingConvention) -> JustSaying.Fluent.MessagingConfigurationBuilder
+JustSaying.Fluent.MessagingConfigurationBuilder.WithTopicNamingConvention() -> JustSaying.Fluent.MessagingConfigurationBuilder
+JustSaying.Fluent.PublicationsBuilder
+JustSaying.Fluent.PublicationsBuilder.WithQueue() -> JustSaying.Fluent.PublicationsBuilder
+JustSaying.Fluent.PublicationsBuilder.WithQueue(System.Action> configure) -> JustSaying.Fluent.PublicationsBuilder
+JustSaying.Fluent.PublicationsBuilder.WithQueueArn(string queueArn) -> JustSaying.Fluent.PublicationsBuilder
+JustSaying.Fluent.PublicationsBuilder.WithQueueUri(System.Uri queueUrl) -> JustSaying.Fluent.PublicationsBuilder
+JustSaying.Fluent.PublicationsBuilder.WithQueueUrl(string queueUrl) -> JustSaying.Fluent.PublicationsBuilder
+JustSaying.Fluent.PublicationsBuilder.WithTopic() -> JustSaying.Fluent.PublicationsBuilder
+JustSaying.Fluent.PublicationsBuilder.WithTopic(System.Action> configure) -> JustSaying.Fluent.PublicationsBuilder
+JustSaying.Fluent.PublicationsBuilder.WithTopicArn(string topicArn, System.Action> configure = null) -> JustSaying.Fluent.PublicationsBuilder
+JustSaying.Fluent.QueueAddressConfiguration
+JustSaying.Fluent.QueueAddressConfiguration.MiddlewareConfiguration.get -> System.Action
+JustSaying.Fluent.QueueAddressConfiguration.MiddlewareConfiguration.set -> void
+JustSaying.Fluent.QueueAddressConfiguration.QueueAddressConfiguration() -> void
+JustSaying.Fluent.QueueAddressConfiguration.SubscriptionGroupName.get -> string
+JustSaying.Fluent.QueueAddressConfiguration.SubscriptionGroupName.set -> void
+JustSaying.Fluent.QueueAddressConfiguration.Validate() -> void
+JustSaying.Fluent.QueueAddressPublicationBuilder
+JustSaying.Fluent.QueueAddressPublicationBuilder.Configure(JustSaying.JustSayingBus bus, JustSaying.AwsTools.IAwsClientFactoryProxy proxy, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) -> void
+JustSaying.Fluent.QueueAddressSubscriptionBuilder
+JustSaying.Fluent.QueueAddressSubscriptionBuilder.WithMiddlewareConfiguration(System.Action middlewareConfiguration) -> JustSaying.Fluent.ISubscriptionBuilder
+JustSaying.Fluent.QueueAddressSubscriptionBuilder.WithReadConfiguration(System.Action configure) -> JustSaying.Fluent.QueueAddressSubscriptionBuilder
+JustSaying.Fluent.QueuePublicationBuilder
+JustSaying.Fluent.QueuePublicationBuilder.WithWriteConfiguration(System.Action configure) -> JustSaying.Fluent.QueuePublicationBuilder
+JustSaying.Fluent.QueuePublicationBuilder.WithWriteConfiguration(System.Action configure) -> JustSaying.Fluent.QueuePublicationBuilder
+JustSaying.Fluent.QueueSubscriptionBuilder
+JustSaying.Fluent.QueueSubscriptionBuilder.WithDefaultQueue() -> JustSaying.Fluent.QueueSubscriptionBuilder
+JustSaying.Fluent.QueueSubscriptionBuilder.WithMiddlewareConfiguration(System.Action middlewareConfiguration) -> JustSaying.Fluent.ISubscriptionBuilder
+JustSaying.Fluent.QueueSubscriptionBuilder.WithQueueName(string name) -> JustSaying.Fluent.QueueSubscriptionBuilder
+JustSaying.Fluent.QueueSubscriptionBuilder.WithReadConfiguration(System.Action configure) -> JustSaying.Fluent.QueueSubscriptionBuilder
+JustSaying.Fluent.QueueSubscriptionBuilder.WithReadConfiguration(System.Action configure) -> JustSaying.Fluent.QueueSubscriptionBuilder
+JustSaying.Fluent.QueueSubscriptionBuilder.WithTag(string key) -> JustSaying.Fluent.QueueSubscriptionBuilder
+JustSaying.Fluent.QueueSubscriptionBuilder.WithTag(string key, string value) -> JustSaying.Fluent.QueueSubscriptionBuilder
+JustSaying.Fluent.ServicesBuilder
+JustSaying.Fluent.ServicesBuilder.WithHandlerResolver(JustSaying.IHandlerResolver handlerResolver) -> JustSaying.Fluent.ServicesBuilder
+JustSaying.Fluent.ServicesBuilder.WithHandlerResolver(System.Func handlerResolver) -> JustSaying.Fluent.ServicesBuilder
+JustSaying.Fluent.ServicesBuilder.WithLoggerFactory(Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) -> JustSaying.Fluent.ServicesBuilder
+JustSaying.Fluent.ServicesBuilder.WithLoggerFactory(System.Func loggerFactory) -> JustSaying.Fluent.ServicesBuilder
+JustSaying.Fluent.ServicesBuilder.WithMessageContextAccessor(System.Func contextAccessor) -> JustSaying.Fluent.ServicesBuilder
+JustSaying.Fluent.ServicesBuilder.WithMessageMonitoring(System.Func monitoring) -> JustSaying.Fluent.ServicesBuilder
+JustSaying.Fluent.SnsWriteConfigurationBuilder
+JustSaying.Fluent.SnsWriteConfigurationBuilder.SnsWriteConfigurationBuilder() -> void
+JustSaying.Fluent.SnsWriteConfigurationBuilder.WithErrorHandler(System.Func handler) -> JustSaying.Fluent.SnsWriteConfigurationBuilder
+JustSaying.Fluent.SqsConfigurationBuilder
+JustSaying.Fluent.SqsConfigurationBuilder.WithEncryption(JustSaying.AwsTools.QueueCreation.ServerSideEncryption encryption) -> TBuilder
+JustSaying.Fluent.SqsConfigurationBuilder.WithEncryption(string masterKeyId) -> TBuilder
+JustSaying.Fluent.SqsConfigurationBuilder.WithErrorQueue() -> TBuilder
+JustSaying.Fluent.SqsConfigurationBuilder.WithErrorQueueOptOut(bool value) -> TBuilder
+JustSaying.Fluent.SqsConfigurationBuilder.WithMessageRetention(System.TimeSpan value) -> TBuilder
+JustSaying.Fluent.SqsConfigurationBuilder.WithNoErrorQueue() -> TBuilder
+JustSaying.Fluent.SqsConfigurationBuilder.WithVisibilityTimeout(System.TimeSpan value) -> TBuilder
+JustSaying.Fluent.SqsReadConfigurationBuilder
+JustSaying.Fluent.SqsReadConfigurationBuilder.SqsReadConfigurationBuilder() -> void
+JustSaying.Fluent.SqsReadConfigurationBuilder.WithSubscriptionGroup(string subscriptionGroupName) -> JustSaying.Fluent.SqsReadConfigurationBuilder
+JustSaying.Fluent.SqsReadConfigurationBuilder.WithTopicSourceAccount(string id) -> JustSaying.Fluent.SqsReadConfigurationBuilder
+JustSaying.Fluent.SqsWriteConfigurationBuilder
+JustSaying.Fluent.SqsWriteConfigurationBuilder.SqsWriteConfigurationBuilder() -> void
+JustSaying.Fluent.SqsWriteConfigurationBuilder.WithQueueName(string name) -> JustSaying.Fluent.SqsWriteConfigurationBuilder
+JustSaying.Fluent.SubscriptionsBuilder
+JustSaying.Fluent.SubscriptionsBuilder.ForQueue() -> JustSaying.Fluent.SubscriptionsBuilder
+JustSaying.Fluent.SubscriptionsBuilder.ForQueue(System.Action> configure) -> JustSaying.Fluent.SubscriptionsBuilder
+JustSaying.Fluent.SubscriptionsBuilder.ForQueueArn(string queueArn, System.Action> configure = null) -> JustSaying.Fluent.SubscriptionsBuilder
+JustSaying.Fluent.SubscriptionsBuilder.ForQueueUri(System.Uri queueUrl, string regionName = null, System.Action> configure = null) -> JustSaying.Fluent.SubscriptionsBuilder
+JustSaying.Fluent.SubscriptionsBuilder.ForQueueUrl(string queueUrl, string regionName = null, System.Action> configure = null) -> JustSaying.Fluent.SubscriptionsBuilder
+JustSaying.Fluent.SubscriptionsBuilder.ForTopic() -> JustSaying.Fluent.SubscriptionsBuilder
+JustSaying.Fluent.SubscriptionsBuilder.ForTopic(string topicNameOverride, System.Action> configure) -> JustSaying.Fluent.SubscriptionsBuilder
+JustSaying.Fluent.SubscriptionsBuilder.ForTopic(System.Action> configure) -> JustSaying.Fluent.SubscriptionsBuilder
+JustSaying.Fluent.SubscriptionsBuilder.WithDefaults(System.Action configure) -> JustSaying.Fluent.SubscriptionsBuilder
+JustSaying.Fluent.SubscriptionsBuilder.WithSubscriptionGroup(string groupName, System.Action action) -> JustSaying.Fluent.SubscriptionsBuilder
+JustSaying.Fluent.TopicAddressPublicationBuilder
+JustSaying.Fluent.TopicAddressPublicationBuilder.Configure(JustSaying.JustSayingBus bus, JustSaying.AwsTools.IAwsClientFactoryProxy proxy, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) -> void
+JustSaying.Fluent.TopicAddressPublicationBuilder.WithExceptionHandler(System.Func exceptionHandler) -> JustSaying.Fluent.TopicAddressPublicationBuilder
+JustSaying.Fluent.TopicPublicationBuilder
+JustSaying.Fluent.TopicPublicationBuilder.TopicNameCustomizer.get -> System.Func
+JustSaying.Fluent.TopicPublicationBuilder.TopicNameCustomizer.set -> void
+JustSaying.Fluent.TopicPublicationBuilder.WithTag(string key) -> JustSaying.Fluent.TopicPublicationBuilder
+JustSaying.Fluent.TopicPublicationBuilder.WithTag(string key, string value) -> JustSaying.Fluent.TopicPublicationBuilder
+JustSaying.Fluent.TopicPublicationBuilder.WithTopicName(string name) -> JustSaying.Fluent.TopicPublicationBuilder
+JustSaying.Fluent.TopicPublicationBuilder.WithTopicName(System.Func topicNameCustomizer) -> JustSaying.Fluent.TopicPublicationBuilder
+JustSaying.Fluent.TopicPublicationBuilder.WithWriteConfiguration(System.Action configure) -> JustSaying.Fluent.TopicPublicationBuilder
+JustSaying.Fluent.TopicPublicationBuilder.WithWriteConfiguration(System.Action configure) -> JustSaying.Fluent.TopicPublicationBuilder
+JustSaying.Fluent.TopicSubscriptionBuilder
+JustSaying.Fluent.TopicSubscriptionBuilder.IntoDefaultTopic() -> JustSaying.Fluent.TopicSubscriptionBuilder
+JustSaying.Fluent.TopicSubscriptionBuilder.WithMiddlewareConfiguration(System.Action middlewareConfiguration) -> JustSaying.Fluent.ISubscriptionBuilder
+JustSaying.Fluent.TopicSubscriptionBuilder.WithQueueName(string name) -> JustSaying.Fluent.TopicSubscriptionBuilder
+JustSaying.Fluent.TopicSubscriptionBuilder.WithReadConfiguration(System.Action configure) -> JustSaying.Fluent.TopicSubscriptionBuilder
+JustSaying.Fluent.TopicSubscriptionBuilder.WithReadConfiguration(System.Action configure) -> JustSaying.Fluent.TopicSubscriptionBuilder
+JustSaying.Fluent.TopicSubscriptionBuilder.WithTag(string key) -> JustSaying.Fluent.TopicSubscriptionBuilder
+JustSaying.Fluent.TopicSubscriptionBuilder.WithTag(string key, string value) -> JustSaying.Fluent.TopicSubscriptionBuilder
+JustSaying.Fluent.TopicSubscriptionBuilder.WithTopicName(string name) -> JustSaying.Fluent.TopicSubscriptionBuilder
+JustSaying.HandlerNotRegisteredWithContainerException
+JustSaying.HandlerNotRegisteredWithContainerException.HandlerNotRegisteredWithContainerException() -> void
+JustSaying.HandlerNotRegisteredWithContainerException.HandlerNotRegisteredWithContainerException(string message) -> void
+JustSaying.HandlerNotRegisteredWithContainerException.HandlerNotRegisteredWithContainerException(string message, System.Exception inner) -> void
+JustSaying.HandlerResolutionContext
+JustSaying.HandlerResolutionContext.HandlerResolutionContext(string queueName) -> void
+JustSaying.HandlerResolutionContext.QueueName.get -> string
+JustSaying.IHandlerResolver
+JustSaying.IHandlerResolver.ResolveHandler(JustSaying.HandlerResolutionContext context) -> JustSaying.Messaging.MessageHandling.IHandlerAsync
+JustSaying.IMessagingBus
+JustSaying.IMessagingConfig
+JustSaying.IMessagingConfig.MessageSubjectProvider.get -> JustSaying.Messaging.MessageSerialization.IMessageSubjectProvider
+JustSaying.IMessagingConfig.MessageSubjectProvider.set -> void
+JustSaying.IMessagingConfig.QueueNamingConvention.get -> JustSaying.Naming.IQueueNamingConvention
+JustSaying.IMessagingConfig.QueueNamingConvention.set -> void
+JustSaying.IMessagingConfig.Region.get -> string
+JustSaying.IMessagingConfig.Region.set -> void
+JustSaying.IMessagingConfig.TopicNamingConvention.get -> JustSaying.Naming.ITopicNamingConvention
+JustSaying.IMessagingConfig.TopicNamingConvention.set -> void
+JustSaying.IMessagingConfig.Validate() -> void
+JustSaying.IPublishConfiguration
+JustSaying.IPublishConfiguration.AdditionalSubscriberAccounts.get -> System.Collections.Generic.IReadOnlyCollection
+JustSaying.IPublishConfiguration.AdditionalSubscriberAccounts.set -> void
+JustSaying.IPublishConfiguration.MessageResponseLogger.get -> System.Action
+JustSaying.IPublishConfiguration.MessageResponseLogger.set -> void
+JustSaying.IPublishConfiguration.PublishFailureBackoff.get -> System.TimeSpan
+JustSaying.IPublishConfiguration.PublishFailureBackoff.set -> void
+JustSaying.IPublishConfiguration.PublishFailureReAttempts.get -> int
+JustSaying.IPublishConfiguration.PublishFailureReAttempts.set -> void
+JustSaying.IStartable
+JustSaying.IStartable.StartAsync(System.Threading.CancellationToken stoppingToken) -> System.Threading.Tasks.Task
+JustSaying.JustSayingBus
+JustSaying.JustSayingBus.AddMessageMiddleware(string queueName, JustSaying.Messaging.Middleware.MiddlewareBase middleware) -> void
+JustSaying.JustSayingBus.AddMessagePublisher(JustSaying.Messaging.IMessagePublisher messagePublisher) -> void
+JustSaying.JustSayingBus.AddQueue(string subscriptionGroup, JustSaying.AwsTools.MessageHandling.ISqsQueue queue) -> void
+JustSaying.JustSayingBus.Completion.get -> System.Threading.Tasks.Task
+JustSaying.JustSayingBus.Config.get -> JustSaying.IMessagingConfig
+JustSaying.JustSayingBus.Dispose() -> void
+JustSaying.JustSayingBus.Interrogate() -> JustSaying.Messaging.Interrogation.InterrogationResult
+JustSaying.JustSayingBus.JustSayingBus(JustSaying.IMessagingConfig config, JustSaying.Messaging.MessageSerialization.IMessageSerializationRegister serializationRegister, JustSaying.Messaging.Channels.Receive.IMessageReceivePauseSignal messageReceivePauseSignal, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory, JustSaying.Messaging.Monitoring.IMessageMonitor monitor) -> void
+JustSaying.JustSayingBus.JustSayingBus(JustSaying.IMessagingConfig config, JustSaying.Messaging.MessageSerialization.IMessageSerializationRegister serializationRegister, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory, JustSaying.Messaging.Monitoring.IMessageMonitor monitor) -> void
+JustSaying.JustSayingBus.PublishAsync(JustSaying.Models.Message message, JustSaying.Messaging.PublishMetadata metadata, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task
+JustSaying.JustSayingBus.PublishAsync(JustSaying.Models.Message message, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task
+JustSaying.JustSayingBus.SerializationRegister.get -> JustSaying.Messaging.MessageSerialization.IMessageSerializationRegister
+JustSaying.JustSayingBus.SetGroupSettings(JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupSettingsBuilder defaults, System.Collections.Generic.IDictionary settings) -> void
+JustSaying.JustSayingBus.StartAsync(System.Threading.CancellationToken stoppingToken) -> System.Threading.Tasks.Task
+JustSaying.Messaging.Channels.Context.IMessageDeleter
+JustSaying.Messaging.Channels.Context.IMessageDeleter.DeleteMessage(System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task
+JustSaying.Messaging.Channels.Context.IMessageVisibilityUpdater
+JustSaying.Messaging.Channels.Context.IMessageVisibilityUpdater.UpdateMessageVisibilityTimeout(System.TimeSpan visibilityTimeout, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task
+JustSaying.Messaging.Channels.Context.IQueueMessageContext
+JustSaying.Messaging.Channels.Context.IQueueMessageContext.Message.get -> Amazon.SQS.Model.Message
+JustSaying.Messaging.Channels.Context.IQueueMessageContext.QueueName.get -> string
+JustSaying.Messaging.Channels.Context.IQueueMessageContext.QueueUri.get -> System.Uri
+JustSaying.Messaging.Channels.Context.QueueMessageContext
+JustSaying.Messaging.Channels.Context.QueueMessageContext.DeleteMessage(System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task
+JustSaying.Messaging.Channels.Context.QueueMessageContext.Message.get -> Amazon.SQS.Model.Message
+JustSaying.Messaging.Channels.Context.QueueMessageContext.QueueName.get -> string
+JustSaying.Messaging.Channels.Context.QueueMessageContext.QueueUri.get -> System.Uri
+JustSaying.Messaging.Channels.Context.QueueMessageContext.UpdateMessageVisibilityTimeout(System.TimeSpan visibilityTimeout, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task
+JustSaying.Messaging.Channels.Receive.IMessageReceivePauseSignal
+JustSaying.Messaging.Channels.Receive.IMessageReceivePauseSignal.IsPaused.get -> bool
+JustSaying.Messaging.Channels.Receive.IMessageReceivePauseSignal.Pause() -> void
+JustSaying.Messaging.Channels.Receive.IMessageReceivePauseSignal.Resume() -> void
+JustSaying.Messaging.Channels.Receive.MessageReceivePauseSignal
+JustSaying.Messaging.Channels.Receive.MessageReceivePauseSignal.IsPaused.get -> bool
+JustSaying.Messaging.Channels.Receive.MessageReceivePauseSignal.MessageReceivePauseSignal() -> void
+JustSaying.Messaging.Channels.Receive.MessageReceivePauseSignal.Pause() -> void
+JustSaying.Messaging.Channels.Receive.MessageReceivePauseSignal.Resume() -> void
+JustSaying.Messaging.Channels.SubscriptionGroups.ISubscriptionGroup
+JustSaying.Messaging.Channels.SubscriptionGroups.ISubscriptionGroup.RunAsync(System.Threading.CancellationToken stoppingToken) -> System.Threading.Tasks.Task
+JustSaying.Messaging.Channels.SubscriptionGroups.ISubscriptionGroupFactory
+JustSaying.Messaging.Channels.SubscriptionGroups.ISubscriptionGroupFactory.Create(JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupSettingsBuilder defaults, System.Collections.Generic.IDictionary subscriptionGroupSettings) -> JustSaying.Messaging.Channels.SubscriptionGroups.ISubscriptionGroup
+JustSaying.Messaging.Channels.SubscriptionGroups.ISubscriptionGroupSettings
+JustSaying.Messaging.Channels.SubscriptionGroups.ISubscriptionGroupSettings.BufferSize.get -> int
+JustSaying.Messaging.Channels.SubscriptionGroups.ISubscriptionGroupSettings.ConcurrencyLimit.get -> int
+JustSaying.Messaging.Channels.SubscriptionGroups.ISubscriptionGroupSettings.MultiplexerCapacity.get -> int
+JustSaying.Messaging.Channels.SubscriptionGroups.ISubscriptionGroupSettings.Prefetch.get -> int
+JustSaying.Messaging.Channels.SubscriptionGroups.ISubscriptionGroupSettings.ReceiveBufferReadTimeout.get -> System.TimeSpan
+JustSaying.Messaging.Channels.SubscriptionGroups.ISubscriptionGroupSettings.ReceiveMessagesWaitTime.get -> System.TimeSpan
+JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupCollection
+JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupCollection.Interrogate() -> JustSaying.Messaging.Interrogation.InterrogationResult
+JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupCollection.RunAsync(System.Threading.CancellationToken stoppingToken) -> System.Threading.Tasks.Task
+JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupCollection.SubscriptionGroupCollection(System.Collections.Generic.IList subscriptionGroups, Microsoft.Extensions.Logging.ILogger logger) -> void
+JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupConfigBuilder
+JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupConfigBuilder.AddQueue(JustSaying.AwsTools.MessageHandling.ISqsQueue sqsQueue) -> JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupConfigBuilder
+JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupConfigBuilder.AddQueues(System.Collections.Generic.IEnumerable sqsQueues) -> JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupConfigBuilder
+JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupConfigBuilder.Build(JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupSettingsBuilder defaults) -> JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupSettings
+JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupConfigBuilder.SubscriptionGroupConfigBuilder(string groupName) -> void
+JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupConfigBuilder.WithBufferSize(int bufferSize) -> JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupConfigBuilder
+JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupConfigBuilder.WithConcurrencyLimit(int concurrencyLimit) -> JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupConfigBuilder
+JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupConfigBuilder.WithMultiplexerCapacity(int multiplexerCapacity) -> JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupConfigBuilder
+JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupConfigBuilder.WithPrefetch(int prefetch) -> JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupConfigBuilder
+JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupConfigBuilder.WithReceiveBufferReadTimeout(System.TimeSpan receiveBufferReadTimeout) -> JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupConfigBuilder
+JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupConfigBuilder.WithReceiveMessagesWaitTime(System.TimeSpan waitTime) -> JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupConfigBuilder
+JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupFactory
+JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupFactory.Create(JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupSettingsBuilder defaults, System.Collections.Generic.IDictionary subscriptionGroupSettings) -> JustSaying.Messaging.Channels.SubscriptionGroups.ISubscriptionGroup
+JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupFactory.SubscriptionGroupFactory(JustSaying.AwsTools.MessageHandling.Dispatch.IMessageDispatcher messageDispatcher, JustSaying.Messaging.Channels.Receive.IMessageReceivePauseSignal messageReceivePauseSignal, JustSaying.Messaging.Monitoring.IMessageMonitor monitor, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) -> void
+JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupFactory.SubscriptionGroupFactory(JustSaying.AwsTools.MessageHandling.Dispatch.IMessageDispatcher messageDispatcher, JustSaying.Messaging.Monitoring.IMessageMonitor monitor, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) -> void
+JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupSettings
+JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupSettings.BufferSize.get -> int
+JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupSettings.ConcurrencyLimit.get -> int
+JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupSettings.MultiplexerCapacity.get -> int
+JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupSettings.Name.get -> string
+JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupSettings.Prefetch.get -> int
+JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupSettings.Queues.get -> System.Collections.Generic.IReadOnlyCollection
+JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupSettings.ReceiveBufferReadTimeout.get -> System.TimeSpan
+JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupSettings.ReceiveMessagesWaitTime.get -> System.TimeSpan
+JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupSettingsBuilder
+JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupSettingsBuilder.BufferSize.get -> int
+JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupSettingsBuilder.ConcurrencyLimit.get -> int
+JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupSettingsBuilder.MultiplexerCapacity.get -> int
+JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupSettingsBuilder.Prefetch.get -> int
+JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupSettingsBuilder.ReceiveBufferReadTimeout.get -> System.TimeSpan
+JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupSettingsBuilder.ReceiveMessagesWaitTime.get -> System.TimeSpan
+JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupSettingsBuilder.SqsMiddleware.get -> JustSaying.Messaging.Middleware.MiddlewareBase>
+JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupSettingsBuilder.SubscriptionGroupSettingsBuilder() -> void
+JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupSettingsBuilder.WithCustomMiddleware(JustSaying.Messaging.Middleware.MiddlewareBase> middleware) -> JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupSettingsBuilder
+JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupSettingsBuilder.WithDefaultBufferSize(int bufferSize) -> JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupSettingsBuilder
+JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupSettingsBuilder.WithDefaultConcurrencyLimit(int concurrencyLimit) -> JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupSettingsBuilder
+JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupSettingsBuilder.WithDefaultMultiplexerCapacity(int multiplexerCapacity) -> JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupSettingsBuilder
+JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupSettingsBuilder.WithDefaultPrefetch(int prefetch) -> JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupSettingsBuilder
+JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupSettingsBuilder.WithDefaultReceiveBufferReadTimeout(System.TimeSpan receiveBufferReadTimeout) -> JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupSettingsBuilder
+JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupSettingsBuilder.WithDefaultReceiveMessagesWaitTime(System.TimeSpan waitTime) -> JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupSettingsBuilder
+JustSaying.Messaging.Channels.SubscriptionGroups.SubscriptionGroupSettingsValidation
+JustSaying.Messaging.IMessagePublisher
+JustSaying.Messaging.IMessagePublisher.PublishAsync(JustSaying.Models.Message message, JustSaying.Messaging.PublishMetadata metadata, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task
+JustSaying.Messaging.IMessagePublisher.PublishAsync(JustSaying.Models.Message message, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task
+JustSaying.Messaging.Interrogation.IInterrogable
+JustSaying.Messaging.Interrogation.IInterrogable.Interrogate() -> JustSaying.Messaging.Interrogation.InterrogationResult
+JustSaying.Messaging.Interrogation.InterrogationResult
+JustSaying.Messaging.Interrogation.InterrogationResult.Data.get -> object
+JustSaying.Messaging.Interrogation.InterrogationResult.InterrogationResult(object data) -> void
+JustSaying.Messaging.MessageAttributeValue
+JustSaying.Messaging.MessageAttributeValue.BinaryValue.get -> System.Collections.Generic.IReadOnlyCollection
+JustSaying.Messaging.MessageAttributeValue.BinaryValue.set -> void
+JustSaying.Messaging.MessageAttributeValue.DataType.get -> string
+JustSaying.Messaging.MessageAttributeValue.DataType.set -> void
+JustSaying.Messaging.MessageAttributeValue.MessageAttributeValue() -> void
+JustSaying.Messaging.MessageAttributeValue.StringValue.get -> string
+JustSaying.Messaging.MessageAttributeValue.StringValue.set -> void
+JustSaying.Messaging.MessageHandling.IHandlerAsync
+JustSaying.Messaging.MessageHandling.IHandlerAsync.Handle(T message) -> System.Threading.Tasks.Task
+JustSaying.Messaging.MessageHandling.IMessageContextAccessor
+JustSaying.Messaging.MessageHandling.IMessageContextAccessor.MessageContext.get -> JustSaying.Messaging.MessageHandling.MessageContext
+JustSaying.Messaging.MessageHandling.IMessageContextAccessor.MessageContext.set -> void
+JustSaying.Messaging.MessageHandling.IMessageContextReader
+JustSaying.Messaging.MessageHandling.IMessageContextReader.MessageContext.get -> JustSaying.Messaging.MessageHandling.MessageContext
+JustSaying.Messaging.MessageHandling.IMessageLockAsync
+JustSaying.Messaging.MessageHandling.IMessageLockAsync.ReleaseLockAsync(string key) -> System.Threading.Tasks.Task
+JustSaying.Messaging.MessageHandling.IMessageLockAsync.TryAcquireLockAsync(string key, System.TimeSpan howLong) -> System.Threading.Tasks.Task
+JustSaying.Messaging.MessageHandling.IMessageLockAsync.TryAcquireLockPermanentlyAsync(string key) -> System.Threading.Tasks.Task
+JustSaying.Messaging.MessageHandling.ListHandler
+JustSaying.Messaging.MessageHandling.ListHandler.Handle(T message) -> System.Threading.Tasks.Task
+JustSaying.Messaging.MessageHandling.ListHandler.ListHandler(System.Collections.Generic.IEnumerable> handlers) -> void
+JustSaying.Messaging.MessageHandling.MessageAttributes
+JustSaying.Messaging.MessageHandling.MessageAttributes.Get(string value) -> JustSaying.Messaging.MessageAttributeValue
+JustSaying.Messaging.MessageHandling.MessageAttributes.MessageAttributes() -> void
+JustSaying.Messaging.MessageHandling.MessageAttributes.MessageAttributes(System.Collections.Generic.Dictionary attributes) -> void
+JustSaying.Messaging.MessageHandling.MessageContext
+JustSaying.Messaging.MessageHandling.MessageContext.Message.get -> Amazon.SQS.Model.Message
+JustSaying.Messaging.MessageHandling.MessageContext.MessageAttributes.get -> JustSaying.Messaging.MessageHandling.MessageAttributes
+JustSaying.Messaging.MessageHandling.MessageContext.MessageContext(Amazon.SQS.Model.Message message, System.Uri queueUri, JustSaying.Messaging.MessageHandling.MessageAttributes messageAttributes) -> void
+JustSaying.Messaging.MessageHandling.MessageContext.QueueUri.get -> System.Uri
+JustSaying.Messaging.MessageHandling.MessageContextAccessor
+JustSaying.Messaging.MessageHandling.MessageContextAccessor.MessageContext.get -> JustSaying.Messaging.MessageHandling.MessageContext
+JustSaying.Messaging.MessageHandling.MessageContextAccessor.MessageContext.set -> void
+JustSaying.Messaging.MessageHandling.MessageContextAccessor.MessageContextAccessor() -> void
+JustSaying.Messaging.MessageHandling.MessageLockResponse
+JustSaying.Messaging.MessageHandling.MessageLockResponse.DoIHaveExclusiveLock.get -> bool
+JustSaying.Messaging.MessageHandling.MessageLockResponse.DoIHaveExclusiveLock.set -> void
+JustSaying.Messaging.MessageHandling.MessageLockResponse.ExpiryAt.get -> System.DateTimeOffset
+JustSaying.Messaging.MessageHandling.MessageLockResponse.ExpiryAt.set -> void
+JustSaying.Messaging.MessageHandling.MessageLockResponse.ExpiryAtTicks.get -> long
+JustSaying.Messaging.MessageHandling.MessageLockResponse.ExpiryAtTicks.set -> void
+JustSaying.Messaging.MessageHandling.MessageLockResponse.IsMessagePermanentlyLocked.get -> bool
+JustSaying.Messaging.MessageHandling.MessageLockResponse.IsMessagePermanentlyLocked.set -> void
+JustSaying.Messaging.MessageHandling.MessageLockResponse.MessageLockResponse() -> void
+JustSaying.Messaging.MessageProcessingStrategies.IMessageBackoffStrategy
+JustSaying.Messaging.MessageProcessingStrategies.IMessageBackoffStrategy.GetBackoffDuration(JustSaying.Models.Message message, int approximateReceiveCount, System.Exception lastException = null) -> System.TimeSpan
+JustSaying.Messaging.MessageProcessingStrategies.MessageDefaults
+JustSaying.Messaging.MessagePublisherExtensions
+JustSaying.Messaging.MessageSerialization.GenericMessageSubjectProvider
+JustSaying.Messaging.MessageSerialization.GenericMessageSubjectProvider.GenericMessageSubjectProvider() -> void
+JustSaying.Messaging.MessageSerialization.GenericMessageSubjectProvider.GetSubjectForType(System.Type messageType) -> string
+JustSaying.Messaging.MessageSerialization.IMessageSerializationFactory
+JustSaying.Messaging.MessageSerialization.IMessageSerializationFactory.GetSerializer() -> JustSaying.Messaging.MessageSerialization.IMessageSerializer
+JustSaying.Messaging.MessageSerialization.IMessageSerializationRegister
+JustSaying.Messaging.MessageSerialization.IMessageSerializationRegister.AddSerializer() -> void
+JustSaying.Messaging.MessageSerialization.IMessageSerializationRegister.DeserializeMessage(string body) -> JustSaying.Messaging.MessageSerialization.MessageWithAttributes
+JustSaying.Messaging.MessageSerialization.IMessageSerializationRegister.Serialize(JustSaying.Models.Message message, bool serializeForSnsPublishing) -> string
+JustSaying.Messaging.MessageSerialization.IMessageSerializer
+JustSaying.Messaging.MessageSerialization.IMessageSerializer.Deserialize(string message, System.Type type) -> JustSaying.Models.Message
+JustSaying.Messaging.MessageSerialization.IMessageSerializer.GetMessageAttributes(string message) -> JustSaying.Messaging.MessageHandling.MessageAttributes
+JustSaying.Messaging.MessageSerialization.IMessageSerializer.GetMessageSubject(string sqsMessage) -> string
+JustSaying.Messaging.MessageSerialization.IMessageSerializer.Serialize(JustSaying.Models.Message message, bool serializeForSnsPublishing, string subject) -> string
+JustSaying.Messaging.MessageSerialization.IMessageSubjectProvider
+JustSaying.Messaging.MessageSerialization.IMessageSubjectProvider.GetSubjectForType(System.Type messageType) -> string
+JustSaying.Messaging.MessageSerialization.MessageFormatNotSupportedException
+JustSaying.Messaging.MessageSerialization.MessageFormatNotSupportedException.MessageFormatNotSupportedException() -> void
+JustSaying.Messaging.MessageSerialization.MessageFormatNotSupportedException.MessageFormatNotSupportedException(string message) -> void
+JustSaying.Messaging.MessageSerialization.MessageFormatNotSupportedException.MessageFormatNotSupportedException(string message, System.Exception innerException) -> void
+JustSaying.Messaging.MessageSerialization.MessageSerializationRegister
+JustSaying.Messaging.MessageSerialization.MessageSerializationRegister.AddSerializer() -> void
+JustSaying.Messaging.MessageSerialization.MessageSerializationRegister.DeserializeMessage(string body) -> JustSaying.Messaging.MessageSerialization.MessageWithAttributes
+JustSaying.Messaging.MessageSerialization.MessageSerializationRegister.MessageSerializationRegister(JustSaying.Messaging.MessageSerialization.IMessageSubjectProvider messageSubjectProvider, JustSaying.Messaging.MessageSerialization.IMessageSerializationFactory serializationFactory) -> void
+JustSaying.Messaging.MessageSerialization.MessageSerializationRegister.Serialize(JustSaying.Models.Message message, bool serializeForSnsPublishing) -> string
+JustSaying.Messaging.MessageSerialization.MessageWithAttributes
+JustSaying.Messaging.MessageSerialization.MessageWithAttributes.Message.get -> JustSaying.Models.Message
+JustSaying.Messaging.MessageSerialization.MessageWithAttributes.MessageAttributes.get -> JustSaying.Messaging.MessageHandling.MessageAttributes
+JustSaying.Messaging.MessageSerialization.MessageWithAttributes.MessageWithAttributes(JustSaying.Models.Message message, JustSaying.Messaging.MessageHandling.MessageAttributes messageAttributes) -> void
+JustSaying.Messaging.MessageSerialization.NewtonsoftSerializationFactory
+JustSaying.Messaging.MessageSerialization.NewtonsoftSerializationFactory.GetSerializer() -> JustSaying.Messaging.MessageSerialization.IMessageSerializer
+JustSaying.Messaging.MessageSerialization.NewtonsoftSerializationFactory.NewtonsoftSerializationFactory() -> void
+JustSaying.Messaging.MessageSerialization.NewtonsoftSerializationFactory.NewtonsoftSerializationFactory(Newtonsoft.Json.JsonSerializerSettings settings) -> void
+JustSaying.Messaging.MessageSerialization.NewtonsoftSerializer
+JustSaying.Messaging.MessageSerialization.NewtonsoftSerializer.Deserialize(string message, System.Type type) -> JustSaying.Models.Message
+JustSaying.Messaging.MessageSerialization.NewtonsoftSerializer.GetMessageAttributes(string message) -> JustSaying.Messaging.MessageHandling.MessageAttributes
+JustSaying.Messaging.MessageSerialization.NewtonsoftSerializer.GetMessageSubject(string sqsMessage) -> string
+JustSaying.Messaging.MessageSerialization.NewtonsoftSerializer.NewtonsoftSerializer() -> void
+JustSaying.Messaging.MessageSerialization.NewtonsoftSerializer.NewtonsoftSerializer(Newtonsoft.Json.JsonSerializerSettings settings) -> void
+JustSaying.Messaging.MessageSerialization.NewtonsoftSerializer.Serialize(JustSaying.Models.Message message, bool serializeForSnsPublishing, string subject) -> string
+JustSaying.Messaging.MessageSerialization.NonGenericMessageSubjectProvider
+JustSaying.Messaging.MessageSerialization.NonGenericMessageSubjectProvider.GetSubjectForType(System.Type messageType) -> string
+JustSaying.Messaging.MessageSerialization.NonGenericMessageSubjectProvider.NonGenericMessageSubjectProvider() -> void
+JustSaying.Messaging.MessageSerialization.SystemTextJsonSerializationFactory
+JustSaying.Messaging.MessageSerialization.SystemTextJsonSerializationFactory.GetSerializer() -> JustSaying.Messaging.MessageSerialization.IMessageSerializer
+JustSaying.Messaging.MessageSerialization.SystemTextJsonSerializationFactory.SystemTextJsonSerializationFactory(System.Text.Json.JsonSerializerOptions options) -> void
+JustSaying.Messaging.MessageSerialization.SystemTextJsonSerializer
+JustSaying.Messaging.MessageSerialization.SystemTextJsonSerializer.Deserialize(string message, System.Type type) -> JustSaying.Models.Message
+JustSaying.Messaging.MessageSerialization.SystemTextJsonSerializer.GetMessageAttributes(string message) -> JustSaying.Messaging.MessageHandling.MessageAttributes
+JustSaying.Messaging.MessageSerialization.SystemTextJsonSerializer.GetMessageSubject(string sqsMessage) -> string
+JustSaying.Messaging.MessageSerialization.SystemTextJsonSerializer.Serialize(JustSaying.Models.Message message, bool serializeForSnsPublishing, string subject) -> string
+JustSaying.Messaging.MessageSerialization.SystemTextJsonSerializer.SystemTextJsonSerializer() -> void
+JustSaying.Messaging.MessageSerialization.SystemTextJsonSerializer.SystemTextJsonSerializer(System.Text.Json.JsonSerializerOptions options) -> void
+JustSaying.Messaging.MessageSerialization.TypeSerializer
+JustSaying.Messaging.MessageSerialization.TypeSerializer.Serializer.get -> JustSaying.Messaging.MessageSerialization.IMessageSerializer
+JustSaying.Messaging.MessageSerialization.TypeSerializer.Type.get -> System.Type
+JustSaying.Messaging.MessageSerialization.TypeSerializer.TypeSerializer(System.Type type, JustSaying.Messaging.MessageSerialization.IMessageSerializer serializer) -> void
+JustSaying.Messaging.Middleware.Backoff.BackoffMiddleware
+JustSaying.Messaging.Middleware.Backoff.BackoffMiddleware.BackoffMiddleware(JustSaying.Messaging.MessageProcessingStrategies.IMessageBackoffStrategy backoffStrategy, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory, JustSaying.Messaging.Monitoring.IMessageMonitor monitor) -> void
+JustSaying.Messaging.Middleware.Backoff.BackoffMiddlewareBuilderExtensions
+JustSaying.Messaging.Middleware.ErrorHandling.ErrorHandlerMiddleware
+JustSaying.Messaging.Middleware.ErrorHandling.ErrorHandlerMiddleware.ErrorHandlerMiddleware(JustSaying.Messaging.Monitoring.IMessageMonitor monitor) -> void
+JustSaying.Messaging.Middleware.ErrorHandling.ErrorHandlerMiddlewareBuilderExtensions
+JustSaying.Messaging.Middleware.ExactlyOnceHandlerMiddlewareBuilderExtensions
+JustSaying.Messaging.Middleware.ExactlyOnceMiddleware
+JustSaying.Messaging.Middleware.ExactlyOnceMiddleware.ExactlyOnceMiddleware(JustSaying.Messaging.MessageHandling.IMessageLockAsync messageLock, System.TimeSpan timeout, string handlerName, Microsoft.Extensions.Logging.ILogger logger) -> void
+JustSaying.Messaging.Middleware.HandleMessageContext
+JustSaying.Messaging.Middleware.HandleMessageContext.HandledException.get -> System.Exception
+JustSaying.Messaging.Middleware.HandleMessageContext.HandleMessageContext(string queueName, Amazon.SQS.Model.Message rawMessage, JustSaying.Models.Message message, System.Type messageType, JustSaying.Messaging.Channels.Context.IMessageVisibilityUpdater visibilityUpdater, JustSaying.Messaging.Channels.Context.IMessageDeleter messageDeleter, System.Uri queueUri, JustSaying.Messaging.MessageHandling.MessageAttributes messageAttributes) -> void
+JustSaying.Messaging.Middleware.HandleMessageContext.Message.get -> JustSaying.Models.Message
+JustSaying.Messaging.Middleware.HandleMessageContext.MessageAttributes.get -> JustSaying.Messaging.MessageHandling.MessageAttributes
+JustSaying.Messaging.Middleware.HandleMessageContext.MessageDeleter.get -> JustSaying.Messaging.Channels.Context.IMessageDeleter
+JustSaying.Messaging.Middleware.HandleMessageContext.MessageType.get -> System.Type
+JustSaying.Messaging.Middleware.HandleMessageContext.QueueName.get -> string
+JustSaying.Messaging.Middleware.HandleMessageContext.QueueUri.get -> System.Uri
+JustSaying.Messaging.Middleware.HandleMessageContext.RawMessage.get -> Amazon.SQS.Model.Message
+JustSaying.Messaging.Middleware.HandleMessageContext.SetException(System.Exception e) -> void
+JustSaying.Messaging.Middleware.HandleMessageContext.VisibilityUpdater.get -> JustSaying.Messaging.Channels.Context.IMessageVisibilityUpdater
+JustSaying.Messaging.Middleware.HandleMessageContextExtensions
+JustSaying.Messaging.Middleware.HandlerInvocationMiddleware