mirror of https://github.com/dapr/dotnet-sdk.git
add original topic metadata support (#876)
* add original topic metadata support Signed-off-by: saberwang <saberwang@hotmail.com> * Add topicmetadata sample Signed-off-by: saberwang <saberwang@hotmail.com>
This commit is contained in:
parent
a4af2a4567
commit
927daa48eb
|
@ -1,4 +1,4 @@
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
// Copyright 2021 The Dapr Authors
|
// Copyright 2021 The Dapr Authors
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
|
@ -155,5 +155,18 @@ namespace ControllerSample.Controllers
|
||||||
{
|
{
|
||||||
return Ok();
|
return Ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Method which uses <see cref="TopicMetadataAttribute" /> for binding this endpoint to a subscription and adds routingkey metadata.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="transaction"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[Topic("pubsub", "topicmetadata")]
|
||||||
|
[TopicMetadata("routingKey", "keyA")]
|
||||||
|
[HttpPost("examplecustomtopicmetadata")]
|
||||||
|
public ActionResult<Account> ExampleCustomTopicMetadata(Transaction transaction)
|
||||||
|
{
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
// Copyright 2021 The Dapr Authors
|
// Copyright 2021 The Dapr Authors
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
|
@ -14,6 +14,7 @@
|
||||||
namespace Microsoft.AspNetCore.Builder
|
namespace Microsoft.AspNetCore.Builder
|
||||||
{
|
{
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using Dapr;
|
using Dapr;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -35,6 +36,24 @@ namespace Microsoft.AspNetCore.Builder
|
||||||
return WithTopic(builder, pubsubName, name, false);
|
return WithTopic(builder, pubsubName, name, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds <see cref="ITopicMetadata" /> metadata to the provided <see cref="IEndpointConventionBuilder" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The <see cref="IEndpointConventionBuilder" />.</param>\
|
||||||
|
/// <param name="pubsubName">The name of the pubsub component to use.</param>
|
||||||
|
/// <param name="name">The topic name.</param>
|
||||||
|
/// <param name="metadata">
|
||||||
|
/// A collection of metadata key-value pairs that will be provided to the pubsub. The valid metadata keys and values
|
||||||
|
/// are determined by the type of pubsub component used.
|
||||||
|
/// </param>
|
||||||
|
/// <typeparam name="T">The <see cref="IEndpointConventionBuilder" /> type.</typeparam>
|
||||||
|
/// <returns>The <see cref="IEndpointConventionBuilder" /> builder object.</returns>
|
||||||
|
public static T WithTopic<T>(this T builder, string pubsubName, string name, IDictionary<string, string> metadata)
|
||||||
|
where T : IEndpointConventionBuilder
|
||||||
|
{
|
||||||
|
return WithTopic(builder, pubsubName, name, false, metadata);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds <see cref="ITopicMetadata" /> metadata to the provided <see cref="IEndpointConventionBuilder" />.
|
/// Adds <see cref="ITopicMetadata" /> metadata to the provided <see cref="IEndpointConventionBuilder" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -46,6 +65,25 @@ namespace Microsoft.AspNetCore.Builder
|
||||||
/// <returns>The <see cref="IEndpointConventionBuilder" /> builder object.</returns>
|
/// <returns>The <see cref="IEndpointConventionBuilder" /> builder object.</returns>
|
||||||
public static T WithTopic<T>(this T builder, string pubsubName, string name, bool enableRawPayload)
|
public static T WithTopic<T>(this T builder, string pubsubName, string name, bool enableRawPayload)
|
||||||
where T : IEndpointConventionBuilder
|
where T : IEndpointConventionBuilder
|
||||||
|
{
|
||||||
|
return WithTopic(builder, pubsubName, name, enableRawPayload, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds <see cref="ITopicMetadata" /> metadata to the provided <see cref="IEndpointConventionBuilder" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The <see cref="IEndpointConventionBuilder" />.</param>\
|
||||||
|
/// <param name="pubsubName">The name of the pubsub component to use.</param>
|
||||||
|
/// <param name="name">The topic name.</param>
|
||||||
|
/// <param name="enableRawPayload">The enable/disable raw pay load flag.</param>
|
||||||
|
/// <param name="metadata">
|
||||||
|
/// A collection of metadata key-value pairs that will be provided to the pubsub. The valid metadata keys and values
|
||||||
|
/// are determined by the type of pubsub component used.
|
||||||
|
/// </param>
|
||||||
|
/// <typeparam name="T">The <see cref="IEndpointConventionBuilder" /> type.</typeparam>
|
||||||
|
/// <returns>The <see cref="IEndpointConventionBuilder" /> builder object.</returns>
|
||||||
|
public static T WithTopic<T>(this T builder, string pubsubName, string name, bool enableRawPayload, IDictionary<string, string> metadata)
|
||||||
|
where T : IEndpointConventionBuilder
|
||||||
{
|
{
|
||||||
if (builder is null)
|
if (builder is null)
|
||||||
{
|
{
|
||||||
|
@ -56,6 +94,13 @@ namespace Microsoft.AspNetCore.Builder
|
||||||
ArgumentVerifier.ThrowIfNullOrEmpty(name, nameof(name));
|
ArgumentVerifier.ThrowIfNullOrEmpty(name, nameof(name));
|
||||||
|
|
||||||
builder.WithMetadata(new TopicAttribute(pubsubName, name, enableRawPayload));
|
builder.WithMetadata(new TopicAttribute(pubsubName, name, enableRawPayload));
|
||||||
|
if (metadata is not null)
|
||||||
|
{
|
||||||
|
foreach (var md in metadata)
|
||||||
|
{
|
||||||
|
builder.WithMetadata(new TopicMetadataAttribute(md.Key, md.Value));
|
||||||
|
}
|
||||||
|
}
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
// Copyright 2021 The Dapr Authors
|
// Copyright 2021 The Dapr Authors
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
|
@ -70,7 +70,9 @@ namespace Microsoft.AspNetCore.Builder
|
||||||
.SelectMany(e =>
|
.SelectMany(e =>
|
||||||
{
|
{
|
||||||
var topicMetadata = e.Metadata.GetOrderedMetadata<ITopicMetadata>();
|
var topicMetadata = e.Metadata.GetOrderedMetadata<ITopicMetadata>();
|
||||||
var subs = new List<(string PubsubName, string Name, bool? EnableRawPayload, string Match, int Priority, RoutePattern RoutePattern)>();
|
var originalTopicMetadata = e.Metadata.GetOrderedMetadata<IOriginalTopicMetadata>();
|
||||||
|
|
||||||
|
var subs = new List<(string PubsubName, string Name, bool? EnableRawPayload, string Match, int Priority, Dictionary<string, string[]> OriginalTopicMetadata, string MetadataSeparator, RoutePattern RoutePattern)>();
|
||||||
|
|
||||||
for (int i = 0; i < topicMetadata.Count(); i++)
|
for (int i = 0; i < topicMetadata.Count(); i++)
|
||||||
{
|
{
|
||||||
|
@ -79,6 +81,10 @@ namespace Microsoft.AspNetCore.Builder
|
||||||
(topicMetadata[i] as IRawTopicMetadata)?.EnableRawPayload,
|
(topicMetadata[i] as IRawTopicMetadata)?.EnableRawPayload,
|
||||||
topicMetadata[i].Match,
|
topicMetadata[i].Match,
|
||||||
topicMetadata[i].Priority,
|
topicMetadata[i].Priority,
|
||||||
|
originalTopicMetadata.Where(m => (topicMetadata[i] as IOwnedOriginalTopicMetadata)?.OwnedMetadatas?.Any(o => o.Equals(m.Id)) == true || string.IsNullOrEmpty(m.Id))
|
||||||
|
.GroupBy(c => c.Name)
|
||||||
|
.ToDictionary(m => m.Key, m => m.Select(c => c.Value).Distinct().ToArray()),
|
||||||
|
(topicMetadata[i] as IOwnedOriginalTopicMetadata)?.MetadataSeparator,
|
||||||
e.RoutePattern));
|
e.RoutePattern));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,10 +97,18 @@ namespace Microsoft.AspNetCore.Builder
|
||||||
{
|
{
|
||||||
var first = e.First();
|
var first = e.First();
|
||||||
var rawPayload = e.Any(e => e.EnableRawPayload.GetValueOrDefault());
|
var rawPayload = e.Any(e => e.EnableRawPayload.GetValueOrDefault());
|
||||||
|
var metadataSeparator = e.FirstOrDefault(e => string.IsNullOrEmpty(e.MetadataSeparator)).MetadataSeparator ?? ",";
|
||||||
var rules = e.Where(e => !string.IsNullOrEmpty(e.Match)).ToList();
|
var rules = e.Where(e => !string.IsNullOrEmpty(e.Match)).ToList();
|
||||||
var defaultRoutes = e.Where(e => string.IsNullOrEmpty(e.Match)).Select(e => RoutePatternToString(e.RoutePattern)).ToList();
|
var defaultRoutes = e.Where(e => string.IsNullOrEmpty(e.Match)).Select(e => RoutePatternToString(e.RoutePattern)).ToList();
|
||||||
var defaultRoute = defaultRoutes.FirstOrDefault();
|
var defaultRoute = defaultRoutes.FirstOrDefault();
|
||||||
|
|
||||||
|
//multiple identical names. use comma separation.
|
||||||
|
var metadata = new Metadata(e.SelectMany(c => c.OriginalTopicMetadata).GroupBy(c => c.Key).ToDictionary(c => c.Key, c => string.Join(metadataSeparator, c.SelectMany(c => c.Value).Distinct())));
|
||||||
|
if (rawPayload || options?.EnableRawPayload is true)
|
||||||
|
{
|
||||||
|
metadata.Add(Metadata.RawPayload, "true");
|
||||||
|
}
|
||||||
|
|
||||||
if (logger != null)
|
if (logger != null)
|
||||||
{
|
{
|
||||||
if (defaultRoutes.Count > 1)
|
if (defaultRoutes.Count > 1)
|
||||||
|
@ -116,10 +130,7 @@ namespace Microsoft.AspNetCore.Builder
|
||||||
{
|
{
|
||||||
Topic = first.Name,
|
Topic = first.Name,
|
||||||
PubsubName = first.PubsubName,
|
PubsubName = first.PubsubName,
|
||||||
Metadata = rawPayload ? new Metadata
|
Metadata = metadata.Count > 0 ? metadata : null,
|
||||||
{
|
|
||||||
RawPayload = "true",
|
|
||||||
} : null,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Use the V2 routing rules structure
|
// Use the V2 routing rules structure
|
||||||
|
@ -154,7 +165,8 @@ namespace Microsoft.AspNetCore.Builder
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string RoutePatternToString(RoutePattern routePattern) {
|
private static string RoutePatternToString(RoutePattern routePattern)
|
||||||
|
{
|
||||||
return string.Join("/", routePattern.PathSegments
|
return string.Join("/", routePattern.PathSegments
|
||||||
.Select(segment => string.Concat(segment.Parts.Cast<RoutePatternLiteralPart>()
|
.Select(segment => string.Concat(segment.Parts.Cast<RoutePatternLiteralPart>()
|
||||||
.Select(part => part.Content))));
|
.Select(part => part.Content))));
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// Copyright 2021 The Dapr Authors
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace Dapr
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// IOriginalTopicMetadata that describes subscribe endpoint to a topic original metadata.
|
||||||
|
/// </summary>
|
||||||
|
public interface IOriginalTopicMetadata
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the topic metadata id.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// It is only used for simple identification,<see cref="IOwnedOriginalTopicMetadata.OwnedMetadatas"/>. When it is empty, it can be used for all topics in the current context.
|
||||||
|
/// </remarks>
|
||||||
|
string Id { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the topic metadata name.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>Multiple identical names. only the first <see cref="Value"/> is valid.</remarks>
|
||||||
|
string Name { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the topic metadata value.
|
||||||
|
/// </summary>
|
||||||
|
string Value { get; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// Copyright 2021 The Dapr Authors
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace Dapr
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// IOwnedOriginalTopicMetadata that describes subscribe endpoint to topic owned metadata.
|
||||||
|
/// </summary>
|
||||||
|
public interface IOwnedOriginalTopicMetadata
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <see cref="IOriginalTopicMetadata.Id"/> owned by topic.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>When the <see cref="IOriginalTopicMetadata.Id"/> is not empty, the metadata owned by topic.</remarks>
|
||||||
|
string[] OwnedMetadatas { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get separator to use for metadata
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>Separator to be used for <see cref="IOriginalTopicMetadata.Value"/> when multiple values exist for a <see cref="IOriginalTopicMetadata.Name"/>.</remarks>
|
||||||
|
string MetadataSeparator { get; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
// Copyright 2021 The Dapr Authors
|
// Copyright 2021 The Dapr Authors
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
|
@ -49,12 +49,16 @@ namespace Dapr
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This class defines the metadata for subscribe endpoint.
|
/// This class defines the metadata for subscribe endpoint.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal class Metadata
|
internal class Metadata : Dictionary<string, string>
|
||||||
{
|
{
|
||||||
|
public Metadata() { }
|
||||||
|
|
||||||
|
public Metadata(IDictionary<string, string> dictionary) : base(dictionary) { }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the raw payload
|
/// RawPayload key
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string RawPayload { get; set; }
|
internal const string RawPayload = "rawPayload";
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class Routes
|
internal class Routes
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
// Copyright 2021 The Dapr Authors
|
// Copyright 2021 The Dapr Authors
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
|
@ -19,20 +19,24 @@ namespace Dapr
|
||||||
/// TopicAttribute describes an endpoint as a subscriber to a topic.
|
/// TopicAttribute describes an endpoint as a subscriber to a topic.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[AttributeUsage(AttributeTargets.All, AllowMultiple = true)]
|
[AttributeUsage(AttributeTargets.All, AllowMultiple = true)]
|
||||||
public class TopicAttribute : Attribute, ITopicMetadata, IRawTopicMetadata
|
public class TopicAttribute : Attribute, ITopicMetadata, IRawTopicMetadata, IOwnedOriginalTopicMetadata
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="TopicAttribute" /> class.
|
/// Initializes a new instance of the <see cref="TopicAttribute" /> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="pubsubName">The name of the pubsub component to use.</param>
|
/// <param name="pubsubName">The name of the pubsub component to use.</param>
|
||||||
/// <param name="name">The topic name.</param>
|
/// <param name="name">The topic name.</param>
|
||||||
public TopicAttribute(string pubsubName, string name)
|
/// <param name="ownedMetadatas">The topic owned metadata ids.</param>
|
||||||
|
/// <param name="metadataSeparator">Separator to use for metadata.</param>
|
||||||
|
public TopicAttribute(string pubsubName, string name, string[] ownedMetadatas = null,string metadataSeparator = ",")
|
||||||
{
|
{
|
||||||
ArgumentVerifier.ThrowIfNullOrEmpty(pubsubName, nameof(pubsubName));
|
ArgumentVerifier.ThrowIfNullOrEmpty(pubsubName, nameof(pubsubName));
|
||||||
ArgumentVerifier.ThrowIfNullOrEmpty(name, nameof(name));
|
ArgumentVerifier.ThrowIfNullOrEmpty(name, nameof(name));
|
||||||
|
|
||||||
this.Name = name;
|
this.Name = name;
|
||||||
this.PubsubName = pubsubName;
|
this.PubsubName = pubsubName;
|
||||||
|
this.OwnedMetadatas = ownedMetadatas;
|
||||||
|
this.MetadataSeparator = metadataSeparator;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -41,7 +45,9 @@ namespace Dapr
|
||||||
/// <param name="pubsubName">The name of the pubsub component to use.</param>
|
/// <param name="pubsubName">The name of the pubsub component to use.</param>
|
||||||
/// <param name="name">The topic name.</param>
|
/// <param name="name">The topic name.</param>
|
||||||
/// <param name="enableRawPayload">The enable/disable raw pay load flag.</param>
|
/// <param name="enableRawPayload">The enable/disable raw pay load flag.</param>
|
||||||
public TopicAttribute(string pubsubName, string name, bool enableRawPayload)
|
/// <param name="ownedMetadatas">The topic owned metadata ids.</param>
|
||||||
|
/// <param name="metadataSeparator">Separator to use for metadata.</param>
|
||||||
|
public TopicAttribute(string pubsubName, string name, bool enableRawPayload, string[] ownedMetadatas = null, string metadataSeparator = ",")
|
||||||
{
|
{
|
||||||
ArgumentVerifier.ThrowIfNullOrEmpty(pubsubName, nameof(pubsubName));
|
ArgumentVerifier.ThrowIfNullOrEmpty(pubsubName, nameof(pubsubName));
|
||||||
ArgumentVerifier.ThrowIfNullOrEmpty(name, nameof(name));
|
ArgumentVerifier.ThrowIfNullOrEmpty(name, nameof(name));
|
||||||
|
@ -49,6 +55,8 @@ namespace Dapr
|
||||||
this.Name = name;
|
this.Name = name;
|
||||||
this.PubsubName = pubsubName;
|
this.PubsubName = pubsubName;
|
||||||
this.EnableRawPayload = enableRawPayload;
|
this.EnableRawPayload = enableRawPayload;
|
||||||
|
this.OwnedMetadatas = ownedMetadatas;
|
||||||
|
this.MetadataSeparator = metadataSeparator;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -58,7 +66,9 @@ namespace Dapr
|
||||||
/// <param name="name">The topic name.</param>
|
/// <param name="name">The topic name.</param>
|
||||||
/// <param name="match">The CEL expression to test the cloud event with.</param>
|
/// <param name="match">The CEL expression to test the cloud event with.</param>
|
||||||
/// <param name="priority">The priority of the rule (low-to-high values).</param>
|
/// <param name="priority">The priority of the rule (low-to-high values).</param>
|
||||||
public TopicAttribute(string pubsubName, string name, string match, int priority)
|
/// <param name="ownedMetadatas">The topic owned metadata ids.</param>
|
||||||
|
/// <param name="metadataSeparator">Separator to use for metadata.</param>
|
||||||
|
public TopicAttribute(string pubsubName, string name, string match, int priority, string[] ownedMetadatas = null, string metadataSeparator = ",")
|
||||||
{
|
{
|
||||||
ArgumentVerifier.ThrowIfNullOrEmpty(pubsubName, nameof(pubsubName));
|
ArgumentVerifier.ThrowIfNullOrEmpty(pubsubName, nameof(pubsubName));
|
||||||
ArgumentVerifier.ThrowIfNullOrEmpty(name, nameof(name));
|
ArgumentVerifier.ThrowIfNullOrEmpty(name, nameof(name));
|
||||||
|
@ -67,6 +77,8 @@ namespace Dapr
|
||||||
this.PubsubName = pubsubName;
|
this.PubsubName = pubsubName;
|
||||||
this.Match = match;
|
this.Match = match;
|
||||||
this.Priority = priority;
|
this.Priority = priority;
|
||||||
|
this.OwnedMetadatas = ownedMetadatas;
|
||||||
|
this.MetadataSeparator = metadataSeparator;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -77,7 +89,9 @@ namespace Dapr
|
||||||
/// <param name="enableRawPayload">The enable/disable raw pay load flag.</param>
|
/// <param name="enableRawPayload">The enable/disable raw pay load flag.</param>
|
||||||
/// <param name="match">The CEL expression to test the cloud event with.</param>
|
/// <param name="match">The CEL expression to test the cloud event with.</param>
|
||||||
/// <param name="priority">The priority of the rule (low-to-high values).</param>
|
/// <param name="priority">The priority of the rule (low-to-high values).</param>
|
||||||
public TopicAttribute(string pubsubName, string name, bool enableRawPayload, string match, int priority)
|
/// <param name="ownedMetadatas">The topic owned metadata ids.</param>
|
||||||
|
/// <param name="metadataSeparator">Separator to use for metadata.</param>
|
||||||
|
public TopicAttribute(string pubsubName, string name, bool enableRawPayload, string match, int priority, string[] ownedMetadatas = null, string metadataSeparator = ",")
|
||||||
{
|
{
|
||||||
ArgumentVerifier.ThrowIfNullOrEmpty(pubsubName, nameof(pubsubName));
|
ArgumentVerifier.ThrowIfNullOrEmpty(pubsubName, nameof(pubsubName));
|
||||||
ArgumentVerifier.ThrowIfNullOrEmpty(name, nameof(name));
|
ArgumentVerifier.ThrowIfNullOrEmpty(name, nameof(name));
|
||||||
|
@ -87,6 +101,8 @@ namespace Dapr
|
||||||
this.EnableRawPayload = enableRawPayload;
|
this.EnableRawPayload = enableRawPayload;
|
||||||
this.Match = match;
|
this.Match = match;
|
||||||
this.Priority = priority;
|
this.Priority = priority;
|
||||||
|
this.OwnedMetadatas = ownedMetadatas;
|
||||||
|
this.MetadataSeparator = metadataSeparator;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
|
@ -103,5 +119,11 @@ namespace Dapr
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public int Priority { get; }
|
public int Priority { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public string[] OwnedMetadatas { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public string MetadataSeparator { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// Copyright 2021 The Dapr Authors
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace Dapr
|
||||||
|
{
|
||||||
|
using System;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// IOriginalTopicMetadata that describes subscribe endpoint to a topic original metadata.
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(AttributeTargets.All, AllowMultiple = true)]
|
||||||
|
public class TopicMetadataAttribute : Attribute, IOriginalTopicMetadata
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="TopicMetadataAttribute" /> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The metadata name.</param>
|
||||||
|
/// <param name="value">The metadata value.</param>
|
||||||
|
public TopicMetadataAttribute(string name, string value)
|
||||||
|
{
|
||||||
|
ArgumentVerifier.ThrowIfNullOrEmpty(name, nameof(name));
|
||||||
|
ArgumentVerifier.ThrowIfNullOrEmpty(value, nameof(value));
|
||||||
|
Name = name;
|
||||||
|
Value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="TopicMetadataAttribute" /> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The metadata id.</param>
|
||||||
|
/// <param name="name">The metadata name.</param>
|
||||||
|
/// <param name="value">The metadata value.</param>
|
||||||
|
public TopicMetadataAttribute(string id, string name, string value)
|
||||||
|
{
|
||||||
|
ArgumentVerifier.ThrowIfNullOrEmpty(id, nameof(name));
|
||||||
|
ArgumentVerifier.ThrowIfNullOrEmpty(name, nameof(name));
|
||||||
|
ArgumentVerifier.ThrowIfNullOrEmpty(value, nameof(value));
|
||||||
|
Id = id;
|
||||||
|
Name = name;
|
||||||
|
Value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public string Id { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public string Name { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public string Value { get; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
// Copyright 2021 The Dapr Authors
|
// Copyright 2021 The Dapr Authors
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
|
@ -68,6 +68,16 @@ namespace Dapr.AspNetCore.IntegrationTest.App
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Topic("pubsub", "metadata", new string[1] { "id1" })]
|
||||||
|
[Topic("pubsub", "metadata.1", true)]
|
||||||
|
[HttpPost("/multiMetadataTopicAttr")]
|
||||||
|
[TopicMetadata("n1", "v1")]
|
||||||
|
[TopicMetadata("id1", "n2", "v2")]
|
||||||
|
[TopicMetadata("id1", "n2", "v3")]
|
||||||
|
public void MultipleMetadataTopics()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
[Topic("pubsub", "splitTopicAttr", true)]
|
[Topic("pubsub", "splitTopicAttr", true)]
|
||||||
[HttpPost("/splitTopics")]
|
[HttpPost("/splitTopics")]
|
||||||
public void SplitTopic()
|
public void SplitTopic()
|
||||||
|
@ -112,7 +122,7 @@ namespace Dapr.AspNetCore.IntegrationTest.App
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("/echo-user")]
|
[HttpPost("/echo-user")]
|
||||||
public ActionResult<UserInfo> EchoUser([FromQuery]UserInfo user)
|
public ActionResult<UserInfo> EchoUser([FromQuery] UserInfo user)
|
||||||
{
|
{
|
||||||
// To simulate an action where there's no Dapr attribute, yet MVC still checks the list of available model binder providers.
|
// To simulate an action where there's no Dapr attribute, yet MVC still checks the list of available model binder providers.
|
||||||
return user;
|
return user;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
// Copyright 2021 The Dapr Authors
|
// Copyright 2021 The Dapr Authors
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
|
@ -66,6 +66,8 @@ namespace Dapr.AspNetCore.IntegrationTest.App
|
||||||
|
|
||||||
endpoints.MapPost("/splitTopics", context => Task.CompletedTask).WithTopic("pubsub", "splitTopicBuilder");
|
endpoints.MapPost("/splitTopics", context => Task.CompletedTask).WithTopic("pubsub", "splitTopicBuilder");
|
||||||
|
|
||||||
|
endpoints.MapPost("/splitMetadataTopics", context => Task.CompletedTask).WithTopic("pubsub", "splitMetadataTopicBuilder", new Dictionary<string, string> { { "n1", "v1" }, { "n2", "v1" } });
|
||||||
|
|
||||||
endpoints.MapPost("/routingwithstateentry/{widget}", async context =>
|
endpoints.MapPost("/routingwithstateentry/{widget}", async context =>
|
||||||
{
|
{
|
||||||
var daprClient = context.RequestServices.GetRequiredService<DaprClient>();
|
var daprClient = context.RequestServices.GetRequiredService<DaprClient>();
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
// Copyright 2021 The Dapr Authors
|
// Copyright 2021 The Dapr Authors
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
|
@ -14,9 +14,9 @@
|
||||||
namespace Dapr.AspNetCore.IntegrationTest
|
namespace Dapr.AspNetCore.IntegrationTest
|
||||||
{
|
{
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using FluentAssertions;
|
using FluentAssertions;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
@ -39,21 +39,38 @@ namespace Dapr.AspNetCore.IntegrationTest
|
||||||
var json = await JsonSerializer.DeserializeAsync<JsonElement>(stream);
|
var json = await JsonSerializer.DeserializeAsync<JsonElement>(stream);
|
||||||
|
|
||||||
json.ValueKind.Should().Be(JsonValueKind.Array);
|
json.ValueKind.Should().Be(JsonValueKind.Array);
|
||||||
json.GetArrayLength().Should().Be(12);
|
json.GetArrayLength().Should().Be(15);
|
||||||
var subscriptions = new List<(string PubsubName, string Topic, string Route, string rawPayload, string match)>();
|
var subscriptions = new List<(string PubsubName, string Topic, string Route, string rawPayload, string match, string metadata)>();
|
||||||
foreach (var element in json.EnumerateArray())
|
foreach (var element in json.EnumerateArray())
|
||||||
{
|
{
|
||||||
var pubsubName = element.GetProperty("pubsubName").GetString();
|
var pubsubName = element.GetProperty("pubsubName").GetString();
|
||||||
var topic = element.GetProperty("topic").GetString();
|
var topic = element.GetProperty("topic").GetString();
|
||||||
var rawPayload = string.Empty;
|
var rawPayload = string.Empty;
|
||||||
|
Dictionary<string, string> originalMetadata = new Dictionary<string, string>();
|
||||||
if (element.TryGetProperty("metadata", out JsonElement metadata))
|
if (element.TryGetProperty("metadata", out JsonElement metadata))
|
||||||
{
|
{
|
||||||
rawPayload = metadata.GetProperty("rawPayload").GetString();
|
if (metadata.TryGetProperty("rawPayload", out JsonElement rawPayloadJson))
|
||||||
|
{
|
||||||
|
rawPayload = rawPayloadJson.GetString();
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var originalMetadataProperty in metadata.EnumerateObject().OrderBy(c=>c.Name))
|
||||||
|
{
|
||||||
|
if (!originalMetadataProperty.Name.Equals("rawPayload"))
|
||||||
|
{
|
||||||
|
originalMetadata.Add(originalMetadataProperty.Name, originalMetadataProperty.Value.GetString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var originalMetadataString= string.Empty;
|
||||||
|
if (originalMetadata.Count > 0)
|
||||||
|
{
|
||||||
|
originalMetadataString = string.Join(";", originalMetadata.Select(c => $"{c.Key}={c.Value}"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (element.TryGetProperty("route", out JsonElement route))
|
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));
|
||||||
}
|
}
|
||||||
else if (element.TryGetProperty("routes", out JsonElement routes))
|
else if (element.TryGetProperty("routes", out JsonElement routes))
|
||||||
{
|
{
|
||||||
|
@ -63,30 +80,33 @@ namespace Dapr.AspNetCore.IntegrationTest
|
||||||
{
|
{
|
||||||
var match = rule.GetProperty("match").GetString();
|
var match = rule.GetProperty("match").GetString();
|
||||||
var path = rule.GetProperty("path").GetString();
|
var path = rule.GetProperty("path").GetString();
|
||||||
subscriptions.Add((pubsubName, topic, path, rawPayload, match));
|
subscriptions.Add((pubsubName, topic, path, rawPayload, match, originalMetadataString));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (routes.TryGetProperty("default", out JsonElement defaultProperty))
|
if (routes.TryGetProperty("default", out JsonElement defaultProperty))
|
||||||
{
|
{
|
||||||
subscriptions.Add((pubsubName, topic, defaultProperty.GetString(), rawPayload, string.Empty));
|
subscriptions.Add((pubsubName, topic, defaultProperty.GetString(), rawPayload, string.Empty, originalMetadataString));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
subscriptions.Should().Contain(("testpubsub", "A", "topic-a", string.Empty, string.Empty));
|
subscriptions.Should().Contain(("testpubsub", "A", "topic-a", string.Empty, string.Empty, string.Empty));
|
||||||
subscriptions.Should().Contain(("testpubsub", "A.1", "topic-a", string.Empty, string.Empty));
|
subscriptions.Should().Contain(("testpubsub", "A.1", "topic-a", string.Empty, string.Empty, string.Empty));
|
||||||
subscriptions.Should().Contain(("pubsub", "B", "B", string.Empty, string.Empty));
|
subscriptions.Should().Contain(("pubsub", "B", "B", string.Empty, string.Empty, string.Empty));
|
||||||
subscriptions.Should().Contain(("custom-pubsub", "custom-C", "C", string.Empty, string.Empty));
|
subscriptions.Should().Contain(("custom-pubsub", "custom-C", "C", string.Empty, string.Empty, string.Empty));
|
||||||
subscriptions.Should().Contain(("pubsub", "register-user", "register-user", string.Empty, string.Empty));
|
subscriptions.Should().Contain(("pubsub", "register-user", "register-user", string.Empty, string.Empty, string.Empty));
|
||||||
subscriptions.Should().Contain(("pubsub", "register-user-plaintext", "register-user-plaintext", string.Empty, string.Empty));
|
subscriptions.Should().Contain(("pubsub", "register-user-plaintext", "register-user-plaintext", string.Empty, string.Empty, string.Empty));
|
||||||
subscriptions.Should().Contain(("pubsub", "D", "D", "true", string.Empty));
|
subscriptions.Should().Contain(("pubsub", "D", "D", "true", string.Empty, string.Empty));
|
||||||
subscriptions.Should().Contain(("pubsub", "E", "E", string.Empty, string.Empty));
|
subscriptions.Should().Contain(("pubsub", "E", "E", string.Empty, string.Empty, string.Empty));
|
||||||
subscriptions.Should().Contain(("pubsub", "E", "E-Critical", string.Empty, "event.type == \"critical\""));
|
subscriptions.Should().Contain(("pubsub", "E", "E-Critical", string.Empty, "event.type == \"critical\"", string.Empty));
|
||||||
subscriptions.Should().Contain(("pubsub", "E", "E-Important", string.Empty, "event.type == \"important\""));
|
subscriptions.Should().Contain(("pubsub", "E", "E-Important", string.Empty, "event.type == \"important\"", string.Empty));
|
||||||
subscriptions.Should().Contain(("pubsub", "F", "multiTopicAttr", string.Empty, string.Empty));
|
subscriptions.Should().Contain(("pubsub", "F", "multiTopicAttr", string.Empty, string.Empty, string.Empty));
|
||||||
subscriptions.Should().Contain(("pubsub", "F.1", "multiTopicAttr", "true", string.Empty));
|
subscriptions.Should().Contain(("pubsub", "F.1", "multiTopicAttr", "true", string.Empty, string.Empty));
|
||||||
subscriptions.Should().Contain(("pubsub", "splitTopicBuilder", "splitTopics", string.Empty, string.Empty));
|
subscriptions.Should().Contain(("pubsub", "splitTopicBuilder", "splitTopics", string.Empty, string.Empty, string.Empty));
|
||||||
subscriptions.Should().Contain(("pubsub", "splitTopicAttr", "splitTopics", "true", string.Empty));
|
subscriptions.Should().Contain(("pubsub", "splitTopicAttr", "splitTopics", "true", string.Empty, string.Empty));
|
||||||
|
subscriptions.Should().Contain(("pubsub", "metadata", "multiMetadataTopicAttr", string.Empty, string.Empty, "n1=v1;n2=v2,v3"));
|
||||||
|
subscriptions.Should().Contain(("pubsub", "metadata.1", "multiMetadataTopicAttr", "true", string.Empty, "n1=v1"));
|
||||||
|
subscriptions.Should().Contain(("pubsub", "splitMetadataTopicBuilder", "splitMetadataTopics", string.Empty, string.Empty, "n1=v1;n2=v1"));
|
||||||
|
|
||||||
// Test priority route sorting
|
// Test priority route sorting
|
||||||
var eTopic = subscriptions.FindAll(e => e.Topic == "E");
|
var eTopic = subscriptions.FindAll(e => e.Topic == "E");
|
||||||
|
|
Loading…
Reference in New Issue