diff --git a/src/DotNetCore.CAP/CAP.Options.cs b/src/DotNetCore.CAP/CAP.Options.cs index 2990a36..e9e2b27 100644 --- a/src/DotNetCore.CAP/CAP.Options.cs +++ b/src/DotNetCore.CAP/CAP.Options.cs @@ -34,6 +34,16 @@ namespace DotNetCore.CAP /// public string DefaultGroup { get; set; } + /// + /// Subscriber group prefix. + /// + public string GroupNamePrefix { get; set; } + + /// + /// Topic prefix. + /// + public string TopicNamePrefix { get; set; } + /// /// The default version of the message, configured to isolate data in the same instance. The length must not exceed 20 /// diff --git a/src/DotNetCore.CAP/Internal/ConsumerExecutorDescriptor.cs b/src/DotNetCore.CAP/Internal/ConsumerExecutorDescriptor.cs index a9da4ad..0e61ba3 100644 --- a/src/DotNetCore.CAP/Internal/ConsumerExecutorDescriptor.cs +++ b/src/DotNetCore.CAP/Internal/ConsumerExecutorDescriptor.cs @@ -24,6 +24,8 @@ namespace DotNetCore.CAP.Internal public IList Parameters { get; set; } + public string TopicNamePrefix { get; set; } + private string _topicName; /// /// Topic name based on both and . @@ -43,6 +45,11 @@ namespace DotNetCore.CAP.Internal { _topicName = Attribute.Name; } + + if (!string.IsNullOrEmpty(TopicNamePrefix) && !string.IsNullOrEmpty(_topicName)) + { + _topicName = $"{TopicNamePrefix}.{_topicName}"; + } } return _topicName; } diff --git a/src/DotNetCore.CAP/Internal/ICapPublisher.Default.cs b/src/DotNetCore.CAP/Internal/ICapPublisher.Default.cs index c238bf8..2841f04 100644 --- a/src/DotNetCore.CAP/Internal/ICapPublisher.Default.cs +++ b/src/DotNetCore.CAP/Internal/ICapPublisher.Default.cs @@ -11,6 +11,7 @@ using DotNetCore.CAP.Messages; using DotNetCore.CAP.Persistence; using DotNetCore.CAP.Transport; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; namespace DotNetCore.CAP.Internal { @@ -18,6 +19,7 @@ namespace DotNetCore.CAP.Internal { private readonly IDispatcher _dispatcher; private readonly IDataStorage _storage; + private readonly CapOptions _capOptions; // ReSharper disable once InconsistentNaming protected static readonly DiagnosticListener s_diagnosticListener = @@ -28,6 +30,7 @@ namespace DotNetCore.CAP.Internal ServiceProvider = service; _dispatcher = service.GetRequiredService(); _storage = service.GetRequiredService(); + _capOptions = service.GetService>().Value; Transaction = new AsyncLocal(); } @@ -63,6 +66,11 @@ namespace DotNetCore.CAP.Internal throw new ArgumentNullException(nameof(name)); } + if (!string.IsNullOrEmpty(_capOptions.TopicNamePrefix)) + { + name = $"{_capOptions.TopicNamePrefix}.{name}"; + } + headers ??= new Dictionary(); if (!headers.ContainsKey(Headers.MessageId)) diff --git a/src/DotNetCore.CAP/Internal/IConsumerServiceSelector.Default.cs b/src/DotNetCore.CAP/Internal/IConsumerServiceSelector.Default.cs index 9a2d7d1..7bfc988 100644 --- a/src/DotNetCore.CAP/Internal/IConsumerServiceSelector.Default.cs +++ b/src/DotNetCore.CAP/Internal/IConsumerServiceSelector.Default.cs @@ -59,6 +59,11 @@ namespace DotNetCore.CAP.Internal return null; } + if (!string.IsNullOrEmpty(_capOptions.TopicNamePrefix)) + { + key = $"{_capOptions.TopicNamePrefix}.{key}"; + } + var result = MatchUsingName(key, executeDescriptor); if (result != null) { @@ -165,10 +170,13 @@ namespace DotNetCore.CAP.Internal protected virtual void SetSubscribeAttribute(TopicAttribute attribute) { - attribute.Group = (attribute.Group ?? _capOptions.DefaultGroup) + "." + _capOptions.Version; + var prefix = !string.IsNullOrEmpty(_capOptions.GroupNamePrefix) + ? $"{_capOptions.GroupNamePrefix}." + : string.Empty; + attribute.Group = $"{prefix}{attribute.Group ?? _capOptions.DefaultGroup}.{_capOptions.Version}"; } - private static ConsumerExecutorDescriptor InitDescriptor( + private ConsumerExecutorDescriptor InitDescriptor( TopicAttribute attr, MethodInfo methodInfo, TypeInfo implType, @@ -183,7 +191,8 @@ namespace DotNetCore.CAP.Internal MethodInfo = methodInfo, ImplTypeInfo = implType, ServiceTypeInfo = serviceTypeInfo, - Parameters = parameters + Parameters = parameters, + TopicNamePrefix = _capOptions.TopicNamePrefix }; return descriptor; diff --git a/test/DotNetCore.CAP.Test/CustomConsumerSubscribeTest.cs b/test/DotNetCore.CAP.Test/CustomConsumerSubscribeTest.cs index fd9c899..e253fb4 100644 --- a/test/DotNetCore.CAP.Test/CustomConsumerSubscribeTest.cs +++ b/test/DotNetCore.CAP.Test/CustomConsumerSubscribeTest.cs @@ -12,6 +12,9 @@ namespace DotNetCore.CAP.Test { public class CustomConsumerSubscribeTest { + private const string TopicNamePrefix = "topic"; + private const string GroupNamePrefix = "group"; + private readonly IServiceProvider _provider; public CustomConsumerSubscribeTest() @@ -20,7 +23,11 @@ namespace DotNetCore.CAP.Test services.AddSingleton(); services.AddTransient(); services.AddLogging(); - services.AddCap(x => { }); + services.AddCap(x => + { + x.TopicNamePrefix = TopicNamePrefix; + x.GroupNamePrefix = GroupNamePrefix; + }); _provider = services.BuildServiceProvider(); } @@ -42,6 +49,8 @@ namespace DotNetCore.CAP.Test Assert.NotNull(bestCandidates); Assert.NotNull(bestCandidates.MethodInfo); + Assert.StartsWith(GroupNamePrefix, bestCandidates.Attribute.Group); + Assert.StartsWith(TopicNamePrefix, bestCandidates.TopicName); Assert.Equal(typeof(Task), bestCandidates.MethodInfo.ReturnType); } } @@ -102,6 +111,11 @@ namespace DotNetCore.CAP.Test attr.Group = attr.Group + "." + _capOptions.Version; } + if (!string.IsNullOrEmpty(_capOptions.GroupNamePrefix)) + { + attr.Group = $"{_capOptions.GroupNamePrefix}.{attr.Group}"; + } + yield return new ConsumerExecutorDescriptor { Attribute = new CapSubscribeAttribute(attr.Name) @@ -109,7 +123,8 @@ namespace DotNetCore.CAP.Test Group = attr.Group }, MethodInfo = method, - ImplTypeInfo = typeInfo + ImplTypeInfo = typeInfo, + TopicNamePrefix = _capOptions.TopicNamePrefix }; } }