diff --git a/src/Dapr.AspNetCore/DaprEndpointRouteBuilderExtensions.cs b/src/Dapr.AspNetCore/DaprEndpointRouteBuilderExtensions.cs index a901be071..5d66e7245 100644 --- a/src/Dapr.AspNetCore/DaprEndpointRouteBuilderExtensions.cs +++ b/src/Dapr.AspNetCore/DaprEndpointRouteBuilderExtensions.cs @@ -58,15 +58,25 @@ private static IEndpointConventionBuilder CreateSubscribeEndPoint(IEndpointRoute var dataSource = context.RequestServices.GetRequiredService(); var subscriptions = dataSource.Endpoints .OfType() - .Where(e => e.Metadata.GetMetadata()?.Name != null) // only endpoints which have TopicAttribute with not null Name. + .Where(e => e.Metadata.GetOrderedMetadata().Any(t => t.Name != null)) // only endpoints which have TopicAttribute with not null Name. + .SelectMany(e => + { + var topicMetadata = e.Metadata.GetOrderedMetadata(); + var subs = new List<(string PubsubName, string Name, bool? EnableRawPayload, string Match, int Priority, RoutePattern RoutePattern)>(); + + for (int i = 0; i < topicMetadata.Count(); i++) + { + subs.Add((topicMetadata[i].PubsubName, + topicMetadata[i].Name, + (topicMetadata[i] as IRawTopicMetadata)?.EnableRawPayload, + topicMetadata[i].Match, + topicMetadata[i].Priority, + e.RoutePattern)); + } + + return subs; + }) .Distinct() - .Select(e => ( - e.Metadata.GetMetadata().PubsubName, - e.Metadata.GetMetadata().Name, - e.Metadata.GetMetadata()?.EnableRawPayload, - e.Metadata.GetMetadata().Match, - e.Metadata.GetMetadata().Priority, - e.RoutePattern)) .GroupBy(e => new { e.PubsubName, e.Name }) .Select(e => e.OrderBy(e => e.Priority)) .Select(e => @@ -79,7 +89,7 @@ private static IEndpointConventionBuilder CreateSubscribeEndPoint(IEndpointRoute if (logger != null) { - if (defaultRoutes.Count() > 1) + if (defaultRoutes.Count > 1) { logger.LogError("A default subscription to topic {name} on pubsub {pubsub} already exists.", first.Name, first.PubsubName); } @@ -105,7 +115,7 @@ private static IEndpointConventionBuilder CreateSubscribeEndPoint(IEndpointRoute }; // Use the V2 routing rules structure - if (rules.Count() > 0) + if (rules.Count > 0) { subscription.Routes = new Routes { diff --git a/src/Dapr.AspNetCore/TopicAttribute.cs b/src/Dapr.AspNetCore/TopicAttribute.cs index 6848ac1fa..a96648f19 100644 --- a/src/Dapr.AspNetCore/TopicAttribute.cs +++ b/src/Dapr.AspNetCore/TopicAttribute.cs @@ -10,6 +10,7 @@ namespace Dapr /// /// TopicAttribute describes an endpoint as a subscriber to a topic. /// + [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] public class TopicAttribute : Attribute, ITopicMetadata, IRawTopicMetadata { /// diff --git a/test/Dapr.AspNetCore.IntegrationTest.App/DaprController.cs b/test/Dapr.AspNetCore.IntegrationTest.App/DaprController.cs index 47a3b8fba..52090e4d9 100644 --- a/test/Dapr.AspNetCore.IntegrationTest.App/DaprController.cs +++ b/test/Dapr.AspNetCore.IntegrationTest.App/DaprController.cs @@ -53,6 +53,19 @@ public void TopicEImportant() { } + [Topic("pubsub", "F")] + [Topic("pubsub", "F.1", true)] + [HttpPost("/multiTopicAttr")] + public void MultipleTopics() + { + } + + [Topic("pubsub", "splitTopicAttr", true)] + [HttpPost("/splitTopics")] + public void SplitTopic() + { + } + [Topic("pubsub", "register-user")] [HttpPost("/register-user")] public ActionResult RegisterUser(UserInfo user) diff --git a/test/Dapr.AspNetCore.IntegrationTest.App/Startup.cs b/test/Dapr.AspNetCore.IntegrationTest.App/Startup.cs index 632581b84..d4e0aeebc 100644 --- a/test/Dapr.AspNetCore.IntegrationTest.App/Startup.cs +++ b/test/Dapr.AspNetCore.IntegrationTest.App/Startup.cs @@ -53,7 +53,9 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) endpoints.MapSubscribeHandler(); endpoints.MapControllers(); - endpoints.MapPost("/topic-a", context => Task.CompletedTask).WithTopic("testpubsub", "A"); + endpoints.MapPost("/topic-a", context => Task.CompletedTask).WithTopic("testpubsub", "A").WithTopic("testpubsub", "A.1"); + + endpoints.MapPost("/splitTopics", context => Task.CompletedTask).WithTopic("pubsub", "splitTopicBuilder"); endpoints.MapPost("/routingwithstateentry/{widget}", async context => { diff --git a/test/Dapr.AspNetCore.IntegrationTest/SubscribeEndpointTest.cs b/test/Dapr.AspNetCore.IntegrationTest/SubscribeEndpointTest.cs index 1adf4d0c7..e1115f31c 100644 --- a/test/Dapr.AspNetCore.IntegrationTest/SubscribeEndpointTest.cs +++ b/test/Dapr.AspNetCore.IntegrationTest/SubscribeEndpointTest.cs @@ -31,7 +31,7 @@ public async Task SubscribeEndpoint_ReportsTopics() var json = await JsonSerializer.DeserializeAsync(stream); json.ValueKind.Should().Be(JsonValueKind.Array); - json.GetArrayLength().Should().Be(7); + json.GetArrayLength().Should().Be(12); var subscriptions = new List<(string PubsubName, string Topic, string Route, string rawPayload, string match)>(); foreach (var element in json.EnumerateArray()) { @@ -66,6 +66,7 @@ public async Task SubscribeEndpoint_ReportsTopics() } subscriptions.Should().Contain(("testpubsub", "A", "topic-a", string.Empty, string.Empty)); + subscriptions.Should().Contain(("testpubsub", "A.1", "topic-a", string.Empty, string.Empty)); subscriptions.Should().Contain(("pubsub", "B", "B", string.Empty, string.Empty)); subscriptions.Should().Contain(("custom-pubsub", "custom-C", "C", string.Empty, string.Empty)); subscriptions.Should().Contain(("pubsub", "register-user", "register-user", string.Empty, string.Empty)); @@ -74,6 +75,10 @@ public async Task SubscribeEndpoint_ReportsTopics() subscriptions.Should().Contain(("pubsub", "E", "E", string.Empty, string.Empty)); subscriptions.Should().Contain(("pubsub", "E", "E-Critical", string.Empty, "event.type == \"critical\"")); subscriptions.Should().Contain(("pubsub", "E", "E-Important", string.Empty, "event.type == \"important\"")); + subscriptions.Should().Contain(("pubsub", "F", "multiTopicAttr", string.Empty, string.Empty)); + subscriptions.Should().Contain(("pubsub", "F.1", "multiTopicAttr", "true", string.Empty)); + subscriptions.Should().Contain(("pubsub", "splitTopicBuilder", "splitTopics", string.Empty, string.Empty)); + subscriptions.Should().Contain(("pubsub", "splitTopicAttr", "splitTopics", "true", string.Empty)); // Test priority route sorting var eTopic = subscriptions.FindAll(e => e.Topic == "E");