From 6e3fc588695666670abfdc8390a07bda3294704d Mon Sep 17 00:00:00 2001 From: maliming Date: Thu, 29 Sep 2022 16:48:24 +0800 Subject: [PATCH 1/3] Support custom subscriptions response. --- .../DaprEndpointRouteBuilderExtensions.cs | 4 +++- src/Dapr.AspNetCore/SubscribeOptions.cs | 9 ++++++++ src/Dapr.AspNetCore/Subscription.cs | 23 +++++++++++++++---- .../Startup.cs | 14 ++++++++++- .../SubscribeEndpointTest.cs | 7 ++++-- 5 files changed, 48 insertions(+), 9 deletions(-) diff --git a/src/Dapr.AspNetCore/DaprEndpointRouteBuilderExtensions.cs b/src/Dapr.AspNetCore/DaprEndpointRouteBuilderExtensions.cs index 2ad7ac749..df66ea832 100644 --- a/src/Dapr.AspNetCore/DaprEndpointRouteBuilderExtensions.cs +++ b/src/Dapr.AspNetCore/DaprEndpointRouteBuilderExtensions.cs @@ -160,8 +160,10 @@ private static IEndpointConventionBuilder CreateSubscribeEndPoint(IEndpointRoute return subscription; }) - .OrderBy(e => (e.PubsubName, e.Topic)); + .OrderBy(e => (e.PubsubName, e.Topic)) + .ToList(); + await options?.SubscriptionsCallback(subscriptions); await context.Response.WriteAsync(JsonSerializer.Serialize(subscriptions, new JsonSerializerOptions { diff --git a/src/Dapr.AspNetCore/SubscribeOptions.cs b/src/Dapr.AspNetCore/SubscribeOptions.cs index eff8a66cc..a4897d582 100644 --- a/src/Dapr.AspNetCore/SubscribeOptions.cs +++ b/src/Dapr.AspNetCore/SubscribeOptions.cs @@ -11,6 +11,10 @@ // limitations under the License. // ------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + namespace Dapr { /// @@ -22,5 +26,10 @@ public class SubscribeOptions /// Gets or Sets a value which indicates whether to enable or disable processing raw messages. /// public bool EnableRawPayload { get; set; } + + /// + /// An optional delegate used to configure the subscriptions. + /// + public Func, Task> SubscriptionsCallback { get; set; } } } diff --git a/src/Dapr.AspNetCore/Subscription.cs b/src/Dapr.AspNetCore/Subscription.cs index 1c3177b9f..cea23fea4 100644 --- a/src/Dapr.AspNetCore/Subscription.cs +++ b/src/Dapr.AspNetCore/Subscription.cs @@ -18,7 +18,7 @@ namespace Dapr /// /// This class defines subscribe endpoint response /// - internal class Subscription + public class Subscription { /// /// Gets or sets the topic name. @@ -44,7 +44,7 @@ internal class Subscription /// Gets or sets the metadata. /// public Metadata Metadata { get; set; } - + /// /// Gets or sets the deadletter topic. /// @@ -54,10 +54,17 @@ internal class Subscription /// /// This class defines the metadata for subscribe endpoint. /// - internal class Metadata : Dictionary + public class Metadata : Dictionary { + /// + /// Initializes a new instance of the Metadata class. + /// public Metadata() { } + /// + /// Initializes a new instance of the Metadata class. + /// + /// public Metadata(IDictionary dictionary) : base(dictionary) { } /// @@ -66,7 +73,10 @@ public Metadata(IDictionary dictionary) : base(dictionary) { } internal const string RawPayload = "rawPayload"; } - internal class Routes + /// + /// This class defines the routes for subscribe endpoint. + /// + public class Routes { /// /// Gets or sets the default route @@ -79,7 +89,10 @@ internal class Routes public List Rules { get; set; } } - internal class Rule + /// + /// This class defines the rule for subscribe endpoint. + /// + public class Rule { /// /// Gets or sets the CEL expression to match this route. diff --git a/test/Dapr.AspNetCore.IntegrationTest.App/Startup.cs b/test/Dapr.AspNetCore.IntegrationTest.App/Startup.cs index e776fa463..31960ef1d 100644 --- a/test/Dapr.AspNetCore.IntegrationTest.App/Startup.cs +++ b/test/Dapr.AspNetCore.IntegrationTest.App/Startup.cs @@ -59,7 +59,19 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) app.UseEndpoints(endpoints => { - endpoints.MapSubscribeHandler(); + endpoints.MapSubscribeHandler(new SubscribeOptions() + { + SubscriptionsCallback = subscriptions => + { + subscriptions.Add(new Subscription() + { + PubsubName = "dynamic-pubsub", + Topic = "dynamic-topic", + Route = "/dynamic-route" + }); + return Task.CompletedTask; + } + }); endpoints.MapControllers(); endpoints.MapPost("/topic-a", context => Task.CompletedTask).WithTopic("testpubsub", "A").WithTopic("testpubsub", "A.1"); diff --git a/test/Dapr.AspNetCore.IntegrationTest/SubscribeEndpointTest.cs b/test/Dapr.AspNetCore.IntegrationTest/SubscribeEndpointTest.cs index e40e04644..760f6ef30 100644 --- a/test/Dapr.AspNetCore.IntegrationTest/SubscribeEndpointTest.cs +++ b/test/Dapr.AspNetCore.IntegrationTest/SubscribeEndpointTest.cs @@ -11,6 +11,8 @@ // limitations under the License. // ------------------------------------------------------------------------ +using System; + namespace Dapr.AspNetCore.IntegrationTest { using System.Collections.Generic; @@ -39,7 +41,7 @@ public async Task SubscribeEndpoint_ReportsTopics() var json = await JsonSerializer.DeserializeAsync(stream); json.ValueKind.Should().Be(JsonValueKind.Array); - json.GetArrayLength().Should().Be(18); + json.GetArrayLength().Should().Be(19); var subscriptions = new List<(string PubsubName, string Topic, string Route, string rawPayload, string match, string metadata, string DeadLetterTopic)>(); @@ -61,7 +63,7 @@ public async Task SubscribeEndpoint_ReportsTopics() { rawPayload = rawPayloadJson.GetString(); } - + foreach (var originalMetadataProperty in metadata.EnumerateObject().OrderBy(c=>c.Name)) { if (!originalMetadataProperty.Name.Equals("rawPayload")) @@ -117,6 +119,7 @@ public async Task SubscribeEndpoint_ReportsTopics() subscriptions.Should().Contain(("pubsub", "metadata.1", "multiMetadataTopicAttr", "true", string.Empty, "n1=v1", string.Empty)); subscriptions.Should().Contain(("pubsub", "splitMetadataTopicBuilder", "splitMetadataTopics", string.Empty, string.Empty, "n1=v1;n2=v1", string.Empty)); subscriptions.Should().Contain(("pubsub", "metadataseparatorbyemptytring", "topicmetadataseparatorattrbyemptytring", string.Empty, string.Empty, "n1=v1,", string.Empty)); + subscriptions.Should().Contain(("dynamic-pubsub", "dynamic-topic", "/dynamic-route", string.Empty, string.Empty, String.Empty, string.Empty)); // Test priority route sorting var eTopic = subscriptions.FindAll(e => e.Topic == "E"); eTopic.Count.Should().Be(3); From 90aabfcf453b917577c779d785d37b44cc52678a Mon Sep 17 00:00:00 2001 From: maliming Date: Mon, 7 Nov 2022 14:45:03 +0800 Subject: [PATCH 2/3] Update DaprEndpointRouteBuilderExtensions.cs --- src/Dapr.AspNetCore/DaprEndpointRouteBuilderExtensions.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Dapr.AspNetCore/DaprEndpointRouteBuilderExtensions.cs b/src/Dapr.AspNetCore/DaprEndpointRouteBuilderExtensions.cs index df66ea832..e17a1cf71 100644 --- a/src/Dapr.AspNetCore/DaprEndpointRouteBuilderExtensions.cs +++ b/src/Dapr.AspNetCore/DaprEndpointRouteBuilderExtensions.cs @@ -163,7 +163,11 @@ private static IEndpointConventionBuilder CreateSubscribeEndPoint(IEndpointRoute .OrderBy(e => (e.PubsubName, e.Topic)) .ToList(); - await options?.SubscriptionsCallback(subscriptions); + if (options != null && options.SubscriptionsCallback != null) + { + await options.SubscriptionsCallback(subscriptions); + } + await context.Response.WriteAsync(JsonSerializer.Serialize(subscriptions, new JsonSerializerOptions { From 3eb9c186f8b7b63e5ca0aacec9987edebd034c8e Mon Sep 17 00:00:00 2001 From: maliming Date: Wed, 19 Apr 2023 09:04:03 +0800 Subject: [PATCH 3/3] Fix `SubscribeEndpoint_ReportsTopics` unit test. --- src/Dapr.AspNetCore/Subscription.cs | 5 ++++- .../SubscribeEndpointTest.cs | 16 ++++++++-------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/Dapr.AspNetCore/Subscription.cs b/src/Dapr.AspNetCore/Subscription.cs index d65f27466..c3d1cca18 100644 --- a/src/Dapr.AspNetCore/Subscription.cs +++ b/src/Dapr.AspNetCore/Subscription.cs @@ -110,7 +110,10 @@ public class Rule public string Path { get; set; } } - internal class DaprTopicBulkSubscribe + /// + /// This class defines the bulk subscribe options for subscribe endpoint. + /// + public class DaprTopicBulkSubscribe { /// /// Gets or sets whether bulk subscribe option is enabled for a topic. diff --git a/test/Dapr.AspNetCore.IntegrationTest/SubscribeEndpointTest.cs b/test/Dapr.AspNetCore.IntegrationTest/SubscribeEndpointTest.cs index a71358fce..01159114d 100644 --- a/test/Dapr.AspNetCore.IntegrationTest/SubscribeEndpointTest.cs +++ b/test/Dapr.AspNetCore.IntegrationTest/SubscribeEndpointTest.cs @@ -44,7 +44,7 @@ public async Task SubscribeEndpoint_ReportsTopics() json.ValueKind.Should().Be(JsonValueKind.Array); json.GetArrayLength().Should().Be(19); - var subscriptions = new List<(string PubsubName, string Topic, string Route, string rawPayload, + var subscriptions = new List<(string PubsubName, string Topic, string Route, string rawPayload, string match, string metadata, string DeadLetterTopic, string bulkSubscribeMetadata)>(); foreach (var element in json.EnumerateArray()) @@ -88,7 +88,7 @@ public async Task SubscribeEndpoint_ReportsTopics() if (element.TryGetProperty("route", out JsonElement route)) { - subscriptions.Add((pubsubName, topic, route.GetString(), rawPayload, string.Empty, + subscriptions.Add((pubsubName, topic, route.GetString(), rawPayload, string.Empty, originalMetadataString, deadLetterTopic, bulkSubscribeMetadata)); } else if (element.TryGetProperty("routes", out JsonElement routes)) @@ -99,13 +99,13 @@ public async Task SubscribeEndpoint_ReportsTopics() { var match = rule.GetProperty("match").GetString(); var path = rule.GetProperty("path").GetString(); - subscriptions.Add((pubsubName, topic, path, rawPayload, match, + subscriptions.Add((pubsubName, topic, path, rawPayload, match, originalMetadataString, deadLetterTopic, bulkSubscribeMetadata)); } } if (routes.TryGetProperty("default", out JsonElement defaultProperty)) { - subscriptions.Add((pubsubName, topic, defaultProperty.GetString(), rawPayload, + subscriptions.Add((pubsubName, topic, defaultProperty.GetString(), rawPayload, string.Empty, originalMetadataString, deadLetterTopic, bulkSubscribeMetadata)); } } @@ -121,19 +121,19 @@ public async Task SubscribeEndpoint_ReportsTopics() subscriptions.Should().Contain(("pubsub", "E", "E", string.Empty, string.Empty, string.Empty, string.Empty, String.Empty)); subscriptions.Should().Contain(("pubsub", "E", "E-Critical", string.Empty, "event.type == \"critical\"", string.Empty, string.Empty, String.Empty)); subscriptions.Should().Contain(("pubsub", "E", "E-Important", string.Empty, "event.type == \"important\"", string.Empty, string.Empty, String.Empty)); - subscriptions.Should().Contain(("pubsub", "F", "multiTopicAttr", string.Empty, string.Empty, string.Empty, string.Empty, + subscriptions.Should().Contain(("pubsub", "F", "multiTopicAttr", string.Empty, string.Empty, string.Empty, string.Empty, "{\"enabled\":true,\"maxMessagesCount\":100,\"maxAwaitDurationMs\":1000}")); subscriptions.Should().Contain(("pubsub", "F.1", "multiTopicAttr", "true", string.Empty, string.Empty, string.Empty, String.Empty)); - subscriptions.Should().Contain(("pubsub", "G", "G", string.Empty, string.Empty, string.Empty, "deadLetterTopicName", + subscriptions.Should().Contain(("pubsub", "G", "G", string.Empty, string.Empty, string.Empty, "deadLetterTopicName", "{\"enabled\":true,\"maxMessagesCount\":300,\"maxAwaitDurationMs\":1000}")); subscriptions.Should().Contain(("pubsub", "splitTopicBuilder", "splitTopics", string.Empty, string.Empty, string.Empty, string.Empty, String.Empty)); subscriptions.Should().Contain(("pubsub", "splitTopicAttr", "splitTopics", "true", string.Empty, string.Empty, string.Empty, String.Empty)); subscriptions.Should().Contain(("pubsub", "metadata", "multiMetadataTopicAttr", string.Empty, string.Empty, "n1=v1;n2=v2,v3", string.Empty, String.Empty)); - subscriptions.Should().Contain(("pubsub", "metadata.1", "multiMetadataTopicAttr", "true", string.Empty, "n1=v1", string.Empty, + subscriptions.Should().Contain(("pubsub", "metadata.1", "multiMetadataTopicAttr", "true", string.Empty, "n1=v1", string.Empty, "{\"enabled\":true,\"maxMessagesCount\":500,\"maxAwaitDurationMs\":2000}")); subscriptions.Should().Contain(("pubsub", "splitMetadataTopicBuilder", "splitMetadataTopics", string.Empty, string.Empty, "n1=v1;n2=v1", string.Empty, String.Empty)); subscriptions.Should().Contain(("pubsub", "metadataseparatorbyemptytring", "topicmetadataseparatorattrbyemptytring", string.Empty, string.Empty, "n1=v1,", string.Empty, String.Empty)); - subscriptions.Should().Contain(("dynamic-pubsub", "dynamic-topic", "/dynamic-route", string.Empty, string.Empty, String.Empty, string.Empty)); + subscriptions.Should().Contain(("dynamic-pubsub", "dynamic-topic", "/dynamic-route", string.Empty, string.Empty, string.Empty, string.Empty, string.Empty)); // Test priority route sorting var eTopic = subscriptions.FindAll(e => e.Topic == "E"); eTopic.Count.Should().Be(3);