mirror of https://github.com/abpframework/abp.git
45 changed files with 766 additions and 319 deletions
@ -0,0 +1,148 @@ |
|||||
|
name: 🐞 Bug Report |
||||
|
description: Create a report to help us improve |
||||
|
labels: [bug] |
||||
|
body: |
||||
|
- type: markdown |
||||
|
attributes: |
||||
|
value: | |
||||
|
We welcome bug reports! This template will help us gather the information we need to start the triage process. |
||||
|
|
||||
|
Please keep in mind that the GitHub issue tracker is not intended as a general support forum, but for reporting **non-security** bugs and feature requests. |
||||
|
If you believe you have an issue that affects the SECURITY of the platform, please do NOT create an issue and instead email your issue details to info@abp.io. |
||||
|
For other types of questions, consider using [StackOverflow](https://stackoverflow.com/questions/tagged/abp). |
||||
|
- type: checkboxes |
||||
|
id: searched |
||||
|
attributes: |
||||
|
label: Is there an existing issue for this? |
||||
|
description: Please search to see if an issue already exists for the bug you encountered ([abp/issues](https://github.com/abpframework/abp/issues)). |
||||
|
options: |
||||
|
- label: I have searched the existing issues |
||||
|
required: true |
||||
|
- type: textarea |
||||
|
id: background |
||||
|
attributes: |
||||
|
label: Description |
||||
|
description: Please share a clear and concise description of the problem. |
||||
|
placeholder: Description |
||||
|
validations: |
||||
|
required: true |
||||
|
- type: textarea |
||||
|
id: repro-steps |
||||
|
attributes: |
||||
|
label: Reproduction Steps |
||||
|
description: | |
||||
|
Please include minimal steps to reproduce the problem if possible. E.g.: the smallest possible code snippet; or a small project, with steps to run it. If possible include text as text rather than screenshots (so it shows up in searches). |
||||
|
placeholder: Minimal Reproduction |
||||
|
validations: |
||||
|
required: false |
||||
|
- type: textarea |
||||
|
id: expected-behavior |
||||
|
attributes: |
||||
|
label: Expected behavior |
||||
|
description: | |
||||
|
Provide a description of the expected behavior. |
||||
|
placeholder: Expected behavior |
||||
|
validations: |
||||
|
required: false |
||||
|
- type: textarea |
||||
|
id: actual-behavior |
||||
|
attributes: |
||||
|
label: Actual behavior |
||||
|
description: | |
||||
|
Provide a description of the actual behavior observed. If applicable please include any error messages, exception stacktraces or memory dumps. |
||||
|
placeholder: Actual behavior |
||||
|
validations: |
||||
|
required: false |
||||
|
- type: textarea |
||||
|
id: regression |
||||
|
attributes: |
||||
|
label: Regression? |
||||
|
description: | |
||||
|
Did this work in a previous build or release of ABP framework? If you can try a previous release or build to find out, that can help us narrow down the problem. If you don't know, that's OK. |
||||
|
placeholder: Regression? |
||||
|
validations: |
||||
|
required: false |
||||
|
- type: textarea |
||||
|
id: known-workarounds |
||||
|
attributes: |
||||
|
label: Known Workarounds |
||||
|
description: | |
||||
|
Please provide a description of any known workarounds. |
||||
|
placeholder: Known Workarounds |
||||
|
validations: |
||||
|
required: false |
||||
|
- type: markdown |
||||
|
attributes: |
||||
|
value: | |
||||
|
## Configuration |
||||
|
Please provide more information on your ABP configuration. |
||||
|
- type: input |
||||
|
id: version |
||||
|
attributes: |
||||
|
label: Version |
||||
|
description: Which version of ABP is the code running on? |
||||
|
placeholder: Version |
||||
|
validations: |
||||
|
required: true |
||||
|
- type: dropdown |
||||
|
id: user-interface |
||||
|
attributes: |
||||
|
label: User Interface |
||||
|
description: Which user interface of ABP is related to the problem? |
||||
|
options: |
||||
|
- Common (Default) |
||||
|
- MVC |
||||
|
- Angular |
||||
|
- Blazor |
||||
|
- Blazor Server |
||||
|
- React Native |
||||
|
- MAUI |
||||
|
validations: |
||||
|
required: true |
||||
|
- type: dropdown |
||||
|
id: database-provider |
||||
|
attributes: |
||||
|
label: Database Provider |
||||
|
description: Which database provider of ABP is used? |
||||
|
options: |
||||
|
- EF Core (Default) |
||||
|
- MongoDB |
||||
|
- None/Others |
||||
|
validations: |
||||
|
required: true |
||||
|
- type: dropdown |
||||
|
id: structure |
||||
|
attributes: |
||||
|
label: Tiered or separate authentication server |
||||
|
description: Which structure of ABP is specified? |
||||
|
options: |
||||
|
- None (Default) |
||||
|
- Tiered |
||||
|
- Separate Auth Server |
||||
|
validations: |
||||
|
required: true |
||||
|
- type: dropdown |
||||
|
id: Operation-System |
||||
|
attributes: |
||||
|
label: Operation System |
||||
|
description: What is the operation system of the server? |
||||
|
options: |
||||
|
- Windows (Default) |
||||
|
- Linux |
||||
|
- macOS |
||||
|
- Others |
||||
|
validations: |
||||
|
required: true |
||||
|
- type: markdown |
||||
|
attributes: |
||||
|
value: | |
||||
|
--- |
||||
|
- type: textarea |
||||
|
id: other-info |
||||
|
attributes: |
||||
|
label: Other information |
||||
|
description: | |
||||
|
If you have an idea where the problem might lie, let us know that here. Please include any pointers to code, relevant changes, or related issues you know of. |
||||
|
placeholder: Other information |
||||
|
validations: |
||||
|
required: false |
||||
@ -0,0 +1,34 @@ |
|||||
|
name: 💡 Feature request |
||||
|
description: Suggest an idea for this project |
||||
|
labels: [feature] |
||||
|
body: |
||||
|
- type: checkboxes |
||||
|
attributes: |
||||
|
label: Is there an existing issue for this? |
||||
|
description: Please search to see if an issue already exists for the feature you are requesting. (https://github.com/abpframework/abp/issues). |
||||
|
options: |
||||
|
- label: I have searched the existing issues |
||||
|
required: true |
||||
|
- type: textarea |
||||
|
attributes: |
||||
|
label: Is your feature request related to a problem? Please describe the problem. |
||||
|
description: A clear and concise description of what the problem is. |
||||
|
placeholder: I am trying to do [...] but [...] |
||||
|
validations: |
||||
|
required: false |
||||
|
- type: textarea |
||||
|
attributes: |
||||
|
label: Describe the solution you'd like |
||||
|
description: | |
||||
|
A clear and concise description of what you want to happen. Include any alternative solutions you've considered. |
||||
|
placeholder: I would like to see [...] |
||||
|
validations: |
||||
|
required: true |
||||
|
- type: textarea |
||||
|
attributes: |
||||
|
label: Additional context |
||||
|
description: | |
||||
|
Add any other context or screenshots about the feature request here. |
||||
|
placeholder: Add any other context or screenshots about the feature request here. |
||||
|
validations: |
||||
|
required: false |
||||
@ -0,0 +1,20 @@ |
|||||
|
name: 💎 Article request |
||||
|
description: Article suggestion you want to be published on community.abp.io |
||||
|
labels: [community-article-request] |
||||
|
body: |
||||
|
- type: checkboxes |
||||
|
id: searched |
||||
|
attributes: |
||||
|
label: Is there an existing article or article request for this? |
||||
|
description: Please search to see if there is an article or article request related to your article request ([community.abp.io](https://community.abp.io/posts), [abp/issues](https://github.com/abpframework/abp/issues?q=is%3Aopen+is%3Aissue+label%3Acommunity-article-request)) |
||||
|
options: |
||||
|
- label: I have searched the existing resources |
||||
|
required: true |
||||
|
- type: textarea |
||||
|
attributes: |
||||
|
label: Describe the article you'd like |
||||
|
description: | |
||||
|
Please describe the article you'd like to be published on community.abp.io. |
||||
|
If you have any reference article, please share it here. |
||||
|
validations: |
||||
|
required: true |
||||
@ -0,0 +1,49 @@ |
|||||
|
--- |
||||
|
name: Performance issue |
||||
|
about: Report a performance problem or regression |
||||
|
title: '' |
||||
|
labels: 'problem' |
||||
|
assignees: '' |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
<!--This is just a template - feel free to delete any and all of it and replace as appropriate.--> |
||||
|
|
||||
|
### Description |
||||
|
|
||||
|
<!-- |
||||
|
* Please share a clear and concise description of the performance problem. |
||||
|
* Include minimal steps to reproduce the problem if possible. E.g.: the smallest possible code snippet; or a small repo to clone, with steps to run it. |
||||
|
--> |
||||
|
|
||||
|
### Configuration |
||||
|
|
||||
|
<!-- |
||||
|
(If you are posting Benchmark.NET results, this info will be included.) |
||||
|
* Which version of .NET is the code running on? |
||||
|
* What OS version, and what distro if applicable? |
||||
|
* What is the architecture (x64, x86, ARM, ARM64)? |
||||
|
* If relevant, what are the specs of the machine? |
||||
|
--> |
||||
|
|
||||
|
### Regression? |
||||
|
|
||||
|
<!-- |
||||
|
* Did this work in a previous build or release of ABP framework? If you can try a previous release or build to find out, that can help us narrow down the problem. If you don't know, that's OK. |
||||
|
--> |
||||
|
|
||||
|
### Data |
||||
|
|
||||
|
<!-- |
||||
|
* Please include any benchmark results, images of graphs, timings or measurements, or callstacks that are relevant. |
||||
|
* If possible please include text as text rather than images (so it shows up in searches). |
||||
|
* If applicable please include before and after measurements. |
||||
|
--> |
||||
|
|
||||
|
### Analysis |
||||
|
|
||||
|
<!-- |
||||
|
* If you have an idea where the problem might lie, let us know that here. |
||||
|
* Please include any pointers to code, relevant changes, or related issues you know of. |
||||
|
* If you don't know, you can delete this section. |
||||
|
--> |
||||
@ -0,0 +1,8 @@ |
|||||
|
blank_issues_enabled: true |
||||
|
contact_links: |
||||
|
- name: Issue with ABP Commercial |
||||
|
url: https://support.abp.io/QA/Questions |
||||
|
about: Please open issues relating to ABP Commercial in support.abp.io. |
||||
|
- name: Ask a question (community support) |
||||
|
url: https://stackoverflow.com/questions/tagged/abp |
||||
|
about: Ask a question that will be answered by the ABP community |
||||
@ -1,3 +0,0 @@ |
|||||
Please explain the content (an article or a video tutorial) that you would like to see on the ABP Community website, https://community.abp.io. |
|
||||
|
|
||||
Before creating your own request, please check existing requests: https://github.com/abpframework/abp/labels/community-article-request |
|
||||
@ -1 +0,0 @@ |
|||||
Please describe the feature need! |
|
||||
@ -0,0 +1,296 @@ |
|||||
|
// ------------------------------------------------------------------------
|
||||
|
// 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.
|
||||
|
// ------------------------------------------------------------------------
|
||||
|
|
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace Dapr |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// This class defines configurations for the subscribe endpoint.
|
||||
|
/// </summary>
|
||||
|
public class AbpSubscribeOptions |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Gets or Sets a value which indicates whether to enable or disable processing raw messages.
|
||||
|
/// </summary>
|
||||
|
public bool EnableRawPayload { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// An optional delegate used to configure the subscriptions.
|
||||
|
/// </summary>
|
||||
|
public Func<List<AbpSubscription>, Task> SubscriptionsCallback { get; set; } |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// This class defines subscribe endpoint response
|
||||
|
/// </summary>
|
||||
|
public class AbpSubscription |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Gets or sets the topic name.
|
||||
|
/// </summary>
|
||||
|
public string Topic { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the pubsub name
|
||||
|
/// </summary>
|
||||
|
public string PubsubName { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the route
|
||||
|
/// </summary>
|
||||
|
public string Route { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the routes
|
||||
|
/// </summary>
|
||||
|
public AbpRoutes Routes { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the metadata.
|
||||
|
/// </summary>
|
||||
|
public AbpMetadata Metadata { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the deadletter topic.
|
||||
|
/// </summary>
|
||||
|
public string DeadLetterTopic { get; set; } |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// This class defines the metadata for subscribe endpoint.
|
||||
|
/// </summary>
|
||||
|
public class AbpMetadata : Dictionary<string, string> |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the Metadata class.
|
||||
|
/// </summary>
|
||||
|
public AbpMetadata() { } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the Metadata class.
|
||||
|
/// </summary>
|
||||
|
/// <param name="dictionary"></param>
|
||||
|
public AbpMetadata(IDictionary<string, string> dictionary) : base(dictionary) { } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// RawPayload key
|
||||
|
/// </summary>
|
||||
|
internal const string RawPayload = "rawPayload"; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// This class defines the routes for subscribe endpoint.
|
||||
|
/// </summary>
|
||||
|
public class AbpRoutes |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Gets or sets the default route
|
||||
|
/// </summary>
|
||||
|
public string Default { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the routing rules
|
||||
|
/// </summary>
|
||||
|
public List<AbpRule> Rules { get; set; } |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// This class defines the rule for subscribe endpoint.
|
||||
|
/// </summary>
|
||||
|
public class AbpRule |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Gets or sets the CEL expression to match this route.
|
||||
|
/// </summary>
|
||||
|
public string Match { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the path of the route.
|
||||
|
/// </summary>
|
||||
|
public string Path { get; set; } |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
namespace Microsoft.AspNetCore.Builder |
||||
|
{ |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Text.Json; |
||||
|
using System.Text.Json.Serialization; |
||||
|
using Dapr; |
||||
|
using Microsoft.AspNetCore.Http; |
||||
|
using Microsoft.AspNetCore.Routing; |
||||
|
using Microsoft.AspNetCore.Routing.Patterns; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Microsoft.Extensions.Logging; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Contains extension methods for <see cref="IEndpointRouteBuilder" />.
|
||||
|
/// </summary>
|
||||
|
public static class AbpDaprEndpointRouteBuilderExtensions |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Maps an endpoint that will respond to requests to <c>/dapr/subscribe</c> from the
|
||||
|
/// Dapr runtime.
|
||||
|
/// </summary>
|
||||
|
/// <param name="endpoints">The <see cref="IEndpointRouteBuilder" />.</param>
|
||||
|
/// <returns>The <see cref="IEndpointConventionBuilder" />.</returns>
|
||||
|
public static IEndpointConventionBuilder MapAbpSubscribeHandler(this IEndpointRouteBuilder endpoints) |
||||
|
{ |
||||
|
return CreateSubscribeEndPoint(endpoints); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Maps an endpoint that will respond to requests to <c>/dapr/subscribe</c> from the
|
||||
|
/// Dapr runtime.
|
||||
|
/// </summary>
|
||||
|
/// <param name="endpoints">The <see cref="IEndpointRouteBuilder" />.</param>
|
||||
|
/// <param name="options">Configuration options</param>
|
||||
|
/// <returns>The <see cref="IEndpointConventionBuilder" />.</returns>
|
||||
|
/// <seealso cref="MapAbpSubscribeHandler(IEndpointRouteBuilder)"/>
|
||||
|
public static IEndpointConventionBuilder MapAbpSubscribeHandler(this IEndpointRouteBuilder endpoints, AbpSubscribeOptions options) |
||||
|
{ |
||||
|
return CreateSubscribeEndPoint(endpoints, options); |
||||
|
} |
||||
|
|
||||
|
private static IEndpointConventionBuilder CreateSubscribeEndPoint(IEndpointRouteBuilder endpoints, AbpSubscribeOptions options = null) |
||||
|
{ |
||||
|
if (endpoints is null) |
||||
|
{ |
||||
|
throw new System.ArgumentNullException(nameof(endpoints)); |
||||
|
} |
||||
|
|
||||
|
return endpoints.MapGet("dapr/subscribe", async context => |
||||
|
{ |
||||
|
var logger = context.RequestServices.GetRequiredService<ILoggerFactory>().CreateLogger("DaprTopicSubscription"); |
||||
|
var dataSource = context.RequestServices.GetRequiredService<EndpointDataSource>(); |
||||
|
var subscriptions = dataSource.Endpoints |
||||
|
.OfType<RouteEndpoint>() |
||||
|
.Where(e => e.Metadata.GetOrderedMetadata<ITopicMetadata>().Any(t => t.Name != null)) // only endpoints which have TopicAttribute with not null Name.
|
||||
|
.SelectMany(e => |
||||
|
{ |
||||
|
var topicMetadata = e.Metadata.GetOrderedMetadata<ITopicMetadata>(); |
||||
|
var originalTopicMetadata = e.Metadata.GetOrderedMetadata<IOriginalTopicMetadata>(); |
||||
|
|
||||
|
var subs = new List<(string PubsubName, string Name, string DeadLetterTopic, bool? EnableRawPayload, string Match, int Priority, Dictionary<string, string[]> OriginalTopicMetadata, string MetadataSeparator, RoutePattern RoutePattern)>(); |
||||
|
|
||||
|
for (int i = 0; i < topicMetadata.Count(); i++) |
||||
|
{ |
||||
|
subs.Add((topicMetadata[i].PubsubName, |
||||
|
topicMetadata[i].Name, |
||||
|
(topicMetadata[i] as IDeadLetterTopicMetadata)?.DeadLetterTopic, |
||||
|
(topicMetadata[i] as IRawTopicMetadata)?.EnableRawPayload, |
||||
|
topicMetadata[i].Match, |
||||
|
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)); |
||||
|
} |
||||
|
|
||||
|
return subs; |
||||
|
}) |
||||
|
.Distinct() |
||||
|
.GroupBy(e => new { e.PubsubName, e.Name }) |
||||
|
.Select(e => e.OrderBy(e => e.Priority)) |
||||
|
.Select(e => |
||||
|
{ |
||||
|
var first = e.First(); |
||||
|
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 defaultRoutes = e.Where(e => string.IsNullOrEmpty(e.Match)).Select(e => RoutePatternToString(e.RoutePattern)).ToList(); |
||||
|
var defaultRoute = defaultRoutes.FirstOrDefault(); |
||||
|
|
||||
|
//multiple identical names. use comma separation.
|
||||
|
var metadata = new AbpMetadata(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(AbpMetadata.RawPayload, "true"); |
||||
|
} |
||||
|
|
||||
|
if (logger != null) |
||||
|
{ |
||||
|
if (defaultRoutes.Count > 1) |
||||
|
{ |
||||
|
logger.LogError("A default subscription to topic {name} on pubsub {pubsub} already exists.", first.Name, first.PubsubName); |
||||
|
} |
||||
|
|
||||
|
var duplicatePriorities = rules.GroupBy(e => e.Priority) |
||||
|
.Where(g => g.Count() > 1) |
||||
|
.ToDictionary(x => x.Key, y => y.Count()); |
||||
|
|
||||
|
foreach (var entry in duplicatePriorities) |
||||
|
{ |
||||
|
logger.LogError("A subscription to topic {name} on pubsub {pubsub} has duplicate priorities for {priority}: found {count} occurrences.", first.Name, first.PubsubName, entry.Key, entry.Value); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
var subscription = new AbpSubscription |
||||
|
{ |
||||
|
Topic = first.Name, |
||||
|
PubsubName = first.PubsubName, |
||||
|
Metadata = metadata.Count > 0 ? metadata : null, |
||||
|
}; |
||||
|
|
||||
|
if (first.DeadLetterTopic != null) |
||||
|
{ |
||||
|
subscription.DeadLetterTopic = first.DeadLetterTopic; |
||||
|
} |
||||
|
|
||||
|
// Use the V2 routing rules structure
|
||||
|
if (rules.Count > 0) |
||||
|
{ |
||||
|
subscription.Routes = new AbpRoutes |
||||
|
{ |
||||
|
Rules = rules.Select(e => new AbpRule |
||||
|
{ |
||||
|
Match = e.Match, |
||||
|
Path = RoutePatternToString(e.RoutePattern), |
||||
|
}).ToList(), |
||||
|
Default = defaultRoute, |
||||
|
}; |
||||
|
} |
||||
|
// Use the V1 structure for backward compatibility.
|
||||
|
else |
||||
|
{ |
||||
|
subscription.Route = defaultRoute; |
||||
|
} |
||||
|
|
||||
|
return subscription; |
||||
|
}) |
||||
|
.OrderBy(e => (e.PubsubName, e.Topic)) |
||||
|
.ToList(); |
||||
|
|
||||
|
await options?.SubscriptionsCallback(subscriptions); |
||||
|
await context.Response.WriteAsync(JsonSerializer.Serialize(subscriptions, |
||||
|
new JsonSerializerOptions |
||||
|
{ |
||||
|
PropertyNamingPolicy = JsonNamingPolicy.CamelCase, |
||||
|
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull |
||||
|
})); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
private static string RoutePatternToString(RoutePattern routePattern) |
||||
|
{ |
||||
|
return string.Join("/", routePattern.PathSegments |
||||
|
.Select(segment => string.Concat(segment.Parts.Cast<RoutePatternLiteralPart>() |
||||
|
.Select(part => part.Content)))); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,11 +0,0 @@ |
|||||
namespace Volo.Abp.AspNetCore.Mvc.Dapr.EventBus; |
|
||||
|
|
||||
public class AbpAspNetCoreMvcDaprEventBusOptions |
|
||||
{ |
|
||||
public List<IAbpAspNetCoreMvcDaprPubSubProviderContributor> Contributors { get; } |
|
||||
|
|
||||
public AbpAspNetCoreMvcDaprEventBusOptions() |
|
||||
{ |
|
||||
Contributors = new List<IAbpAspNetCoreMvcDaprPubSubProviderContributor>(); |
|
||||
} |
|
||||
} |
|
||||
@ -1,63 +0,0 @@ |
|||||
using Microsoft.Extensions.DependencyInjection; |
|
||||
using Microsoft.Extensions.Options; |
|
||||
using Volo.Abp.AspNetCore.Mvc.Dapr.EventBus.Models; |
|
||||
using Volo.Abp.DependencyInjection; |
|
||||
using Volo.Abp.EventBus; |
|
||||
using Volo.Abp.EventBus.Dapr; |
|
||||
using Volo.Abp.EventBus.Distributed; |
|
||||
|
|
||||
namespace Volo.Abp.AspNetCore.Mvc.Dapr.EventBus; |
|
||||
|
|
||||
public class AbpAspNetCoreMvcDaprPubSubProvider : ITransientDependency |
|
||||
{ |
|
||||
protected IServiceProvider ServiceProvider { get; } |
|
||||
protected AbpAspNetCoreMvcDaprEventBusOptions AspNetCoreMvcDaprEventBusOptions { get; } |
|
||||
protected AbpDaprEventBusOptions DaprEventBusOptions { get; } |
|
||||
protected AbpDistributedEventBusOptions DistributedEventBusOptions { get; } |
|
||||
|
|
||||
public AbpAspNetCoreMvcDaprPubSubProvider( |
|
||||
IServiceProvider serviceProvider, |
|
||||
IOptions<AbpAspNetCoreMvcDaprEventBusOptions> aspNetCoreDaprEventBusOptions, |
|
||||
IOptions<AbpDaprEventBusOptions> daprEventBusOptions, |
|
||||
IOptions<AbpDistributedEventBusOptions> distributedEventBusOptions) |
|
||||
{ |
|
||||
ServiceProvider = serviceProvider; |
|
||||
AspNetCoreMvcDaprEventBusOptions = aspNetCoreDaprEventBusOptions.Value; |
|
||||
DaprEventBusOptions = daprEventBusOptions.Value; |
|
||||
DistributedEventBusOptions = distributedEventBusOptions.Value; |
|
||||
} |
|
||||
|
|
||||
public virtual async Task<List<AbpAspNetCoreMvcDaprSubscriptionDefinition>> GetSubscriptionsAsync() |
|
||||
{ |
|
||||
var subscriptions = new List<AbpAspNetCoreMvcDaprSubscriptionDefinition>(); |
|
||||
foreach (var handler in DistributedEventBusOptions.Handlers) |
|
||||
{ |
|
||||
foreach (var @interface in handler.GetInterfaces().Where(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IDistributedEventHandler<>))) |
|
||||
{ |
|
||||
var eventType = @interface.GetGenericArguments()[0]; |
|
||||
var eventName = EventNameAttribute.GetNameOrDefault(eventType); |
|
||||
|
|
||||
subscriptions.Add(new AbpAspNetCoreMvcDaprSubscriptionDefinition() |
|
||||
{ |
|
||||
PubSubName = DaprEventBusOptions.PubSubName, |
|
||||
Topic = eventName, |
|
||||
Route = AbpAspNetCoreMvcDaprPubSubConsts.DaprEventCallbackUrl |
|
||||
}); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
if (AspNetCoreMvcDaprEventBusOptions.Contributors.Any()) |
|
||||
{ |
|
||||
using (var scope = ServiceProvider.CreateScope()) |
|
||||
{ |
|
||||
var context = new AbpAspNetCoreMvcDaprPubSubProviderContributorContext(scope.ServiceProvider, subscriptions); |
|
||||
foreach (var contributor in AspNetCoreMvcDaprEventBusOptions.Contributors) |
|
||||
{ |
|
||||
await contributor.ContributeAsync(context); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return subscriptions; |
|
||||
} |
|
||||
} |
|
||||
@ -1,16 +0,0 @@ |
|||||
using Volo.Abp.AspNetCore.Mvc.Dapr.EventBus.Models; |
|
||||
|
|
||||
namespace Volo.Abp.AspNetCore.Mvc.Dapr.EventBus; |
|
||||
|
|
||||
public class AbpAspNetCoreMvcDaprPubSubProviderContributorContext |
|
||||
{ |
|
||||
public IServiceProvider ServiceProvider { get; } |
|
||||
|
|
||||
public List<AbpAspNetCoreMvcDaprSubscriptionDefinition> Subscriptions { get; } |
|
||||
|
|
||||
public AbpAspNetCoreMvcDaprPubSubProviderContributorContext(IServiceProvider serviceProvider, List<AbpAspNetCoreMvcDaprSubscriptionDefinition> daprSubscriptionModels) |
|
||||
{ |
|
||||
ServiceProvider = serviceProvider; |
|
||||
Subscriptions = daprSubscriptionModels; |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,38 @@ |
|||||
|
using System; |
||||
|
using System.Text.Json; |
||||
|
using System.Threading.Tasks; |
||||
|
using Microsoft.AspNetCore.Mvc; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Microsoft.Extensions.Logging; |
||||
|
using Volo.Abp.Dapr; |
||||
|
using Volo.Abp.EventBus.Dapr; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Mvc.Dapr.EventBus.Controllers; |
||||
|
|
||||
|
[Area("abp")] |
||||
|
[RemoteService(Name = "abp")] |
||||
|
public class AbpAspNetCoreMvcDaprEventsController : AbpController |
||||
|
{ |
||||
|
[HttpPost(AbpAspNetCoreMvcDaprPubSubConsts.DaprEventCallbackUrl)] |
||||
|
public virtual async Task<IActionResult> EventAsync() |
||||
|
{ |
||||
|
HttpContext.ValidateDaprAppApiToken(); |
||||
|
|
||||
|
var daprSerializer = HttpContext.RequestServices.GetRequiredService<IDaprSerializer>(); |
||||
|
var body = (await JsonDocument.ParseAsync(HttpContext.Request.Body)); |
||||
|
|
||||
|
var pubSubName = body.RootElement.GetProperty("pubsubname").GetString(); |
||||
|
var topic = body.RootElement.GetProperty("topic").GetString(); |
||||
|
var data = body.RootElement.GetProperty("data").GetRawText(); |
||||
|
if (pubSubName.IsNullOrWhiteSpace() || topic.IsNullOrWhiteSpace() || data.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
Logger.LogError("Invalid Dapr event request."); |
||||
|
return BadRequest(); |
||||
|
} |
||||
|
|
||||
|
var distributedEventBus = HttpContext.RequestServices.GetRequiredService<DaprDistributedEventBus>(); |
||||
|
var eventData = daprSerializer.Deserialize(data, distributedEventBus.GetEventType(topic)); |
||||
|
await distributedEventBus.TriggerHandlersAsync(distributedEventBus.GetEventType(topic), eventData); |
||||
|
return Ok(); |
||||
|
} |
||||
|
} |
||||
@ -1,38 +0,0 @@ |
|||||
using System.Text.Json; |
|
||||
using Microsoft.AspNetCore.Mvc; |
|
||||
using Microsoft.Extensions.DependencyInjection; |
|
||||
using Microsoft.Extensions.Options; |
|
||||
using Volo.Abp.AspNetCore.Mvc.Dapr.EventBus.Models; |
|
||||
using Volo.Abp.Dapr; |
|
||||
using Volo.Abp.EventBus.Dapr; |
|
||||
|
|
||||
namespace Volo.Abp.AspNetCore.Mvc.Dapr.EventBus.Controllers; |
|
||||
|
|
||||
[Area("abp")] |
|
||||
[RemoteService(Name = "abp")] |
|
||||
public class AbpAspNetCoreMvcDaprPubSubController : AbpController |
|
||||
{ |
|
||||
[HttpGet(AbpAspNetCoreMvcDaprPubSubConsts.DaprSubscribeUrl)] |
|
||||
public virtual async Task<List<AbpAspNetCoreMvcDaprSubscriptionDefinition>> SubscribeAsync() |
|
||||
{ |
|
||||
return await HttpContext.RequestServices.GetRequiredService<AbpAspNetCoreMvcDaprPubSubProvider>().GetSubscriptionsAsync(); |
|
||||
} |
|
||||
|
|
||||
[HttpPost(AbpAspNetCoreMvcDaprPubSubConsts.DaprEventCallbackUrl)] |
|
||||
public virtual async Task<IActionResult> EventsAsync() |
|
||||
{ |
|
||||
this.HttpContext.ValidateDaprAppApiToken(); |
|
||||
|
|
||||
var bodyJsonDocument = await JsonDocument.ParseAsync(HttpContext.Request.Body); |
|
||||
var request = JsonSerializer.Deserialize<AbpAspNetCoreMvcDaprSubscriptionRequest>(bodyJsonDocument.RootElement.GetRawText(), |
|
||||
HttpContext.RequestServices.GetRequiredService<IOptions<JsonOptions>>().Value.JsonSerializerOptions); |
|
||||
|
|
||||
var distributedEventBus = HttpContext.RequestServices.GetRequiredService<DaprDistributedEventBus>(); |
|
||||
var daprSerializer = HttpContext.RequestServices.GetRequiredService<IDaprSerializer>(); |
|
||||
|
|
||||
var eventData = daprSerializer.Deserialize(bodyJsonDocument.RootElement.GetProperty("data").GetRawText(), distributedEventBus.GetEventType(request.Topic)); |
|
||||
await distributedEventBus.TriggerHandlersAsync(distributedEventBus.GetEventType(request.Topic), eventData); |
|
||||
|
|
||||
return Ok(); |
|
||||
} |
|
||||
} |
|
||||
@ -1,6 +0,0 @@ |
|||||
namespace Volo.Abp.AspNetCore.Mvc.Dapr.EventBus; |
|
||||
|
|
||||
public interface IAbpAspNetCoreMvcDaprPubSubProviderContributor |
|
||||
{ |
|
||||
Task ContributeAsync(AbpAspNetCoreMvcDaprPubSubProviderContributorContext context); |
|
||||
} |
|
||||
@ -1,10 +0,0 @@ |
|||||
namespace Volo.Abp.AspNetCore.Mvc.Dapr.EventBus.Models; |
|
||||
|
|
||||
public class AbpAspNetCoreMvcDaprSubscriptionDefinition |
|
||||
{ |
|
||||
public string PubSubName { get; set; } |
|
||||
|
|
||||
public string Topic { get; set; } |
|
||||
|
|
||||
public string Route { get; set; } |
|
||||
} |
|
||||
@ -1,8 +0,0 @@ |
|||||
namespace Volo.Abp.AspNetCore.Mvc.Dapr.EventBus.Models; |
|
||||
|
|
||||
public class AbpAspNetCoreMvcDaprSubscriptionRequest |
|
||||
{ |
|
||||
public string PubSubName { get; set; } |
|
||||
|
|
||||
public string Topic { get; set; } |
|
||||
} |
|
||||
@ -1,11 +0,0 @@ |
|||||
using System.Text.Json; |
|
||||
|
|
||||
namespace Volo.Abp.AspNetCore.Mvc.Dapr.EventBus.SystemTextJson; |
|
||||
|
|
||||
public class AbpAspNetCoreMvcDaprPubSubJsonNamingPolicy : JsonNamingPolicy |
|
||||
{ |
|
||||
public override string ConvertName(string name) |
|
||||
{ |
|
||||
return name.ToLower(); |
|
||||
} |
|
||||
} |
|
||||
@ -1,25 +0,0 @@ |
|||||
using System.Text.Json; |
|
||||
using System.Text.Json.Serialization; |
|
||||
using Volo.Abp.AspNetCore.Mvc.Dapr.EventBus.Models; |
|
||||
|
|
||||
namespace Volo.Abp.AspNetCore.Mvc.Dapr.EventBus.SystemTextJson; |
|
||||
|
|
||||
public class AbpAspNetCoreMvcDaprSubscriptionDefinitionConverter : JsonConverter<AbpAspNetCoreMvcDaprSubscriptionDefinition> |
|
||||
{ |
|
||||
private JsonSerializerOptions? _writeJsonSerializerOptions; |
|
||||
|
|
||||
public override AbpAspNetCoreMvcDaprSubscriptionDefinition Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) |
|
||||
{ |
|
||||
throw new NotSupportedException(); |
|
||||
} |
|
||||
|
|
||||
public override void Write(Utf8JsonWriter writer, AbpAspNetCoreMvcDaprSubscriptionDefinition value, JsonSerializerOptions options) |
|
||||
{ |
|
||||
_writeJsonSerializerOptions ??= JsonSerializerOptionsHelper.Create(new JsonSerializerOptions(options) |
|
||||
{ |
|
||||
PropertyNamingPolicy = new AbpAspNetCoreMvcDaprPubSubJsonNamingPolicy() |
|
||||
}, x => x == this); |
|
||||
|
|
||||
JsonSerializer.Serialize(writer, value, _writeJsonSerializerOptions); |
|
||||
} |
|
||||
} |
|
||||
@ -1,14 +1,16 @@ |
|||||
|
using System; |
||||
|
using System.Net.Http; |
||||
using Dapr.Client; |
using Dapr.Client; |
||||
|
|
||||
namespace Volo.Abp.Dapr; |
namespace Volo.Abp.Dapr; |
||||
|
|
||||
public interface IAbpDaprClientFactory |
public interface IAbpDaprClientFactory |
||||
{ |
{ |
||||
DaprClient Create(Action<DaprClientBuilder>? builderAction = null); |
DaprClient Create(Action<DaprClientBuilder> builderAction = null); |
||||
|
|
||||
HttpClient CreateHttpClient( |
HttpClient CreateHttpClient( |
||||
string? appId = null, |
string appId = null, |
||||
string? daprEndpoint = null, |
string daprEndpoint = null, |
||||
string? daprApiToken = null |
string daprApiToken = null |
||||
); |
); |
||||
} |
} |
||||
|
|||||
@ -1,15 +1,17 @@ |
|||||
namespace Volo.Abp.DistributedLocking.Dapr; |
using System; |
||||
|
|
||||
|
namespace Volo.Abp.DistributedLocking.Dapr; |
||||
|
|
||||
public class AbpDistributedLockDaprOptions |
public class AbpDistributedLockDaprOptions |
||||
{ |
{ |
||||
public string StoreName { get; set; } |
public string StoreName { get; set; } |
||||
|
|
||||
public string? Owner { get; set; } |
public string? Owner { get; set; } |
||||
|
|
||||
public TimeSpan DefaultExpirationTimeout { get; set; } |
public TimeSpan DefaultExpirationTimeout { get; set; } |
||||
|
|
||||
public AbpDistributedLockDaprOptions() |
public AbpDistributedLockDaprOptions() |
||||
{ |
{ |
||||
DefaultExpirationTimeout = TimeSpan.FromMinutes(2); |
DefaultExpirationTimeout = TimeSpan.FromMinutes(2); |
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -1,18 +1,19 @@ |
|||||
using Dapr.Client; |
using System.Threading.Tasks; |
||||
|
using Dapr.Client; |
||||
|
|
||||
namespace Volo.Abp.DistributedLocking.Dapr; |
namespace Volo.Abp.DistributedLocking.Dapr; |
||||
|
|
||||
public class DaprAbpDistributedLockHandle : IAbpDistributedLockHandle |
public class DaprAbpDistributedLockHandle : IAbpDistributedLockHandle |
||||
{ |
{ |
||||
protected TryLockResponse LockResponse { get; } |
protected TryLockResponse LockResponse { get; } |
||||
|
|
||||
public DaprAbpDistributedLockHandle(TryLockResponse lockResponse) |
public DaprAbpDistributedLockHandle(TryLockResponse lockResponse) |
||||
{ |
{ |
||||
LockResponse = lockResponse; |
LockResponse = lockResponse; |
||||
} |
} |
||||
|
|
||||
public async ValueTask DisposeAsync() |
public async ValueTask DisposeAsync() |
||||
{ |
{ |
||||
await LockResponse.DisposeAsync(); |
await LockResponse.DisposeAsync(); |
||||
} |
} |
||||
} |
} |
||||
|
|||||
Loading…
Reference in new issue