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; |
|||
|
|||
namespace Volo.Abp.Dapr; |
|||
|
|||
public interface IAbpDaprClientFactory |
|||
{ |
|||
DaprClient Create(Action<DaprClientBuilder>? builderAction = null); |
|||
DaprClient Create(Action<DaprClientBuilder> builderAction = null); |
|||
|
|||
HttpClient CreateHttpClient( |
|||
string? appId = null, |
|||
string? daprEndpoint = null, |
|||
string? daprApiToken = null |
|||
string appId = null, |
|||
string daprEndpoint = null, |
|||
string daprApiToken = null |
|||
); |
|||
} |
|||
} |
|||
|
|||
@ -1,15 +1,17 @@ |
|||
namespace Volo.Abp.DistributedLocking.Dapr; |
|||
using System; |
|||
|
|||
namespace Volo.Abp.DistributedLocking.Dapr; |
|||
|
|||
public class AbpDistributedLockDaprOptions |
|||
{ |
|||
public string StoreName { get; set; } |
|||
|
|||
|
|||
public string? Owner { get; set; } |
|||
|
|||
|
|||
public TimeSpan DefaultExpirationTimeout { get; set; } |
|||
|
|||
public AbpDistributedLockDaprOptions() |
|||
{ |
|||
DefaultExpirationTimeout = TimeSpan.FromMinutes(2); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -1,18 +1,19 @@ |
|||
using Dapr.Client; |
|||
using System.Threading.Tasks; |
|||
using Dapr.Client; |
|||
|
|||
namespace Volo.Abp.DistributedLocking.Dapr; |
|||
|
|||
public class DaprAbpDistributedLockHandle : IAbpDistributedLockHandle |
|||
{ |
|||
protected TryLockResponse LockResponse { get; } |
|||
|
|||
|
|||
public DaprAbpDistributedLockHandle(TryLockResponse lockResponse) |
|||
{ |
|||
LockResponse = lockResponse; |
|||
} |
|||
|
|||
|
|||
public async ValueTask DisposeAsync() |
|||
{ |
|||
await LockResponse.DisposeAsync(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
Loading…
Reference in new issue