diff --git a/src/contrib/cluster/Akka.Cluster.Sharding.Tests/AutomaticallyHandledExtractorMessagesSpec.cs b/src/contrib/cluster/Akka.Cluster.Sharding.Tests/AutomaticallyHandledExtractorMessagesSpec.cs index 0822d3fc3b6..1ea53fe3f43 100644 --- a/src/contrib/cluster/Akka.Cluster.Sharding.Tests/AutomaticallyHandledExtractorMessagesSpec.cs +++ b/src/contrib/cluster/Akka.Cluster.Sharding.Tests/AutomaticallyHandledExtractorMessagesSpec.cs @@ -13,16 +13,28 @@ namespace Akka.Cluster.Sharding.Tests; public class AutomaticallyHandledExtractorMessagesSpec { + public sealed record MyWrappedMessage(string EntityId, string Message); + // custom IMessageExtractor public class MyMessageExtractor : IMessageExtractor { public string? EntityId(object message) => message switch { string s => s, + MyWrappedMessage wrapped => wrapped.EntityId, _ => null }; - public object? EntityMessage(object message) => message; + public object? EntityMessage(object message) + { + switch (message) + { + case MyWrappedMessage wrapped: + return wrapped.Message; + default: + return message; + } + } public string? ShardId(object message) => message switch { @@ -35,65 +47,47 @@ public string ShardId(string entityId, object? messageHint = null) return entityId; } } - -#pragma warning disable CS0618 // Type or member is obsolete - private ExtractEntityId ExtractEntityId = message => - { - if (message is string s) - return (s, s); - return Option<(string, object)>.None; - }; - private ExtractShardId ExtractShardId = message => - { - if (message is string s) - return s; - return null!; - }; -#pragma warning restore CS0618 // Type or member is obsolete + public static readonly TheoryData<(object shardingInput, object realMsg, string entityId, string shardId)> + Messages = new() + { + // (new ShardRegion.StartEntity("foo"), new ShardRegion.StartEntity("foo"), "foo", "foo"), + (new ShardingEnvelope("bar", "baz"), "baz", "bar", "bar"), ("bar", "bar", "bar", "bar"), + }; - public static readonly TheoryData<(object shardingInput, object realMsg, string entityId, string shardId)> Messages = new() - { - // (new ShardRegion.StartEntity("foo"), new ShardRegion.StartEntity("foo"), "foo", "foo"), - (new ShardingEnvelope("bar", "baz"), "baz", "bar", "bar"), - ("bar", "bar", "bar", "bar"), - }; - [Theory] [MemberData(nameof(Messages))] - public void ShouldAutomaticallyHandleMessagesInCustomIMessageExtractor((object shardingInput, object realMsg, string entityId, string shardId) data) + public void ShouldAutomaticallyHandleMessagesInCustomIMessageExtractor( + (object shardingInput, object realMsg, string entityId, string shardId) data) { // arrange var extractor = new ExtractorAdapter(new MyMessageExtractor()); - + // act var entityId = extractor.EntityId(data.shardingInput); var entityMessage = extractor.EntityMessage(data.shardingInput); var shardId = extractor.ShardId(entityId!, data.shardingInput); - + // assert entityId.Should().Be(data.entityId); entityMessage.Should().Be(data.realMsg); shardId.Should().Be(data.shardId); } - - // NOTE: so the old delegates are hopeless and will simply not work - you HAVE to handle the messages yourself there - // need to repeat of the previous test but using the deprecated delegate methods and the adapter - // [Theory] - // [MemberData(nameof(Messages))] - // public void ShouldAutomaticallyHandleMessagesInCustomIMessageExtractorUsingDelegates((object shardingInput, object realMsg, string entityId, string shardId) data) - // { - // // arrange - // var extractor = new ExtractorAdapter(new DeprecatedHandlerExtractorAdapter(ExtractEntityId, ExtractShardId)); - // - // // act - // var entityId = extractor.EntityId(data.shardingInput); - // var entityMessage = extractor.EntityMessage(data.shardingInput); - // var shardId = extractor.ShardId(entityId!, data.shardingInput); - // - // // assert - // entityId.Should().Be(data.entityId); - // entityMessage.Should().Be(data.realMsg); - // shardId.Should().Be(data.shardId); - // } -} + + [Fact] + public void ShouldUnwrapMessageInsideShardingEnvelope() + { + // arrange + var extractor = new ExtractorAdapter(new MyMessageExtractor()); + var myMessage = new MyWrappedMessage("entity1", "hello"); + var envelope = new ShardingEnvelope("entity1", myMessage); + + // act + var entityId = extractor.EntityId(envelope); + var entityMessage = extractor.EntityMessage(envelope); + + // assert + entityId.Should().Be("entity1"); + entityMessage.Should().Be("hello"); + } +} \ No newline at end of file diff --git a/src/contrib/cluster/Akka.Cluster.Sharding/ClusterSharding.cs b/src/contrib/cluster/Akka.Cluster.Sharding/ClusterSharding.cs index da5dc3f8ad3..7aa69a729fd 100644 --- a/src/contrib/cluster/Akka.Cluster.Sharding/ClusterSharding.cs +++ b/src/contrib/cluster/Akka.Cluster.Sharding/ClusterSharding.cs @@ -76,7 +76,7 @@ public ExtractorAdapter(IMessageExtractor underlying) { return message switch { - ShardingEnvelope se => se.Message, + ShardingEnvelope se => _underlying.EntityMessage(se.Message), _ => _underlying.EntityMessage(message) }; } diff --git a/src/contrib/cluster/Akka.Cluster.Sharding/ShardedDaemonProcess.cs b/src/contrib/cluster/Akka.Cluster.Sharding/ShardedDaemonProcess.cs index 39a0f4aa64c..9d8b3230d31 100644 --- a/src/contrib/cluster/Akka.Cluster.Sharding/ShardedDaemonProcess.cs +++ b/src/contrib/cluster/Akka.Cluster.Sharding/ShardedDaemonProcess.cs @@ -78,7 +78,9 @@ public MessageExtractor(int maxNumberOfShards) } public override string? EntityId(object message) => (message as ShardingEnvelope)?.EntityId; - public override object? EntityMessage(object message) => (message as ShardingEnvelope)?.Message; + + // Due to https://github.com/akkadotnet/akka.net/issues/7470 we will want to return the underlying content too + public override object? EntityMessage(object message) => (message as ShardingEnvelope)?.Message ?? message; public override string ShardId(string entityId, object? messageHint = null) {