Merge pull request #14164 from abpframework/Dapr-integration-improvement

Improve Dapr integration.
pull/14568/head
Halil İbrahim Kalkan 3 years ago committed by GitHub
commit 39986ce9d1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -209,7 +209,7 @@ ABP provides the following endpoints to receive events from Dapr:
* `dapr/subscribe`: Dapr uses this endpoint to get a list of subscriptions from the application. ABP automatically returns all the subscriptions for your distributed event handler classes and custom controller actions with the `Topic` attribute.
* `api/abp/dapr/event`: The unified endpoint to receive all the events from Dapr. ABP dispatches the events to your event handlers based on the topic name.
> **Since ABP provides the standard `dapr/subscribe` endpoint, you should not manually call the `app.MapSubscribeHandler()` method of Dapr.** You can use the `app.UseCloudEvents()` middleware in your ASP.NET Core pipeline if you want to support the [CloudEvents](https://cloudevents.io/) standard.
> **Since ABP will call `MapSubscribeHandler` internally, you should not manually call it anymore.** You can use the `app.UseCloudEvents()` middleware in your ASP.NET Core pipeline if you want to support the [CloudEvents](https://cloudevents.io/) standard.
### Usage
@ -299,8 +299,7 @@ public class MyController : AbpController
{
[HttpPost("/stock-changed")]
[Topic("pubsub", "StockChanged")]
public async Task<IActionResult> TestRouteAsync(
[FromBody] StockCountChangedEto model)
public async Task<IActionResult> TestRouteAsync([FromBody] StockCountChangedEto model)
{
HttpContext.ValidateDaprAppApiToken();
@ -430,8 +429,7 @@ public class MyController : AbpController
{
[HttpPost("/stock-changed")]
[Topic("pubsub", "StockChanged")]
public async Task<IActionResult> TestRouteAsync(
[FromBody] StockCountChangedEto model)
public async Task<IActionResult> TestRouteAsync([FromBody] StockCountChangedEto model)
{
// Validate the App API token!
HttpContext.ValidateDaprAppApiToken();

@ -209,7 +209,7 @@ ABP提供了以下端点来接收来自Dapr的事件:
* `dapr/subscribe`: Dapr使用此端点从应用程序获取订阅列表.ABP会自动返回所有分布式事件处理程序类和具有`Topic`属性的自定义控制器操作的订阅.
* `api/abp/dapr/event`: 用于接收来自Dapr的所有事件的统一端点.ABP根据主题名称将事件分派给您的事件处理程序.
> **由于ABP提供了标准的`dapr/subscribe`端点,所以你不应该手动调用Dapr的`app.MapSubscribeHandler()`方法.** 如果你想支持[CloudEvents](https://cloudevents.io/)标准,你可以在你的ASP.NET Core管道中使用`app.UseCloudEvents()`中间件.
> **由于ABP会在内部调用`MapSubscribeHandler` 方法,所以你不应该手动调用了.** 如果你想支持[CloudEvents](https://cloudevents.io/)标准,你可以在你的ASP.NET Core管道中使用`app.UseCloudEvents()`中间件.
### 用法
@ -299,8 +299,7 @@ public class MyController : AbpController
{
[HttpPost("/stock-changed")]
[Topic("pubsub", "StockChanged")]
public async Task<IActionResult> TestRouteAsync(
[FromBody] StockCountChangedEto model)
public async Task<IActionResult> TestRouteAsync([FromBody] StockCountChangedEto model)
{
HttpContext.ValidateDaprAppApiToken();
@ -430,8 +429,7 @@ public class MyController : AbpController
{
[HttpPost("/stock-changed")]
[Topic("pubsub", "StockChanged")]
public async Task<IActionResult> TestRouteAsync(
[FromBody] StockCountChangedEto model)
public async Task<IActionResult> TestRouteAsync([FromBody] StockCountChangedEto model)
{
// Validate the App API token!
HttpContext.ValidateDaprAppApiToken();

@ -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))));
}
}
}

@ -5,8 +5,6 @@
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<RootNamespace />
</PropertyGroup>

@ -1,7 +1,14 @@
using Microsoft.AspNetCore.Http.Json;
using Volo.Abp.AspNetCore.Mvc.Dapr.EventBus.SystemTextJson;
using System.Linq;
using System.Threading.Tasks;
using Dapr;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Volo.Abp.DependencyInjection;
using Volo.Abp.EventBus;
using Volo.Abp.EventBus.Dapr;
using Volo.Abp.Json.SystemTextJson;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.Modularity;
namespace Volo.Abp.AspNetCore.Mvc.Dapr.EventBus;
@ -14,16 +21,50 @@ public class AbpAspNetCoreMvcDaprEventBusModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
// TODO: Add NewtonsoftJson json converter.
var subscribeOptions = context.Services.ExecutePreConfiguredActions<AbpSubscribeOptions>();
Configure<JsonOptions>(options =>
Configure<AbpEndpointRouterOptions>(options =>
{
options.SerializerOptions.Converters.Add(new AbpAspNetCoreMvcDaprSubscriptionDefinitionConverter());
});
options.EndpointConfigureActions.Add(endpointContext =>
{
var rootServiceProvider = endpointContext.ScopeServiceProvider.GetRequiredService<IRootServiceProvider>();
subscribeOptions.SubscriptionsCallback = subscriptions =>
{
var daprEventBusOptions = rootServiceProvider.GetRequiredService<IOptions<AbpDaprEventBusOptions>>().Value;
foreach (var handler in rootServiceProvider.GetRequiredService<IOptions<AbpDistributedEventBusOptions>>().Value.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);
Configure<AbpSystemTextJsonSerializerOptions>(options =>
{
options.JsonSerializerOptions.Converters.Add(new AbpAspNetCoreMvcDaprSubscriptionDefinitionConverter());
if (subscriptions.Any(x => x.PubsubName == daprEventBusOptions.PubSubName && x.Topic == eventName))
{
// Controllers with a [Topic] attribute can replace built-in event handlers.
continue;
}
var subscription = new AbpSubscription
{
PubsubName = daprEventBusOptions.PubSubName,
Topic = eventName,
Route = AbpAspNetCoreMvcDaprPubSubConsts.DaprEventCallbackUrl,
Metadata = new AbpMetadata
{
{
AbpMetadata.RawPayload, "true"
}
}
};
subscriptions.Add(subscription);
}
}
return Task.CompletedTask;
};
endpointContext.Endpoints.MapAbpSubscribeHandler(subscribeOptions);
});
});
}
}

@ -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>();
}
}

@ -2,7 +2,5 @@
public class AbpAspNetCoreMvcDaprPubSubConsts
{
public const string DaprSubscribeUrl = "dapr/subscribe";
public const string DaprEventCallbackUrl = "api/abp/dapr/event";
}

@ -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);
}
}

@ -5,8 +5,6 @@
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<RootNamespace />
</PropertyGroup>
@ -16,7 +14,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Dapr.AspNetCore" Version="1.8.0" />
<PackageReference Include="Dapr.AspNetCore" Version="1.9.0" />
</ItemGroup>
</Project>

@ -1,5 +1,6 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.SignalR;
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Authorization;
using Volo.Abp.Dapr;
@ -10,13 +11,13 @@ namespace Volo.Abp.AspNetCore.Mvc.Dapr;
public class DaprAppApiTokenValidator : IDaprAppApiTokenValidator, ISingletonDependency
{
protected IHttpContextAccessor HttpContextAccessor { get; }
protected HttpContext HttpContext => GetHttpContext();
protected HttpContext HttpContext => GetHttpContext();
public DaprAppApiTokenValidator(IHttpContextAccessor httpContextAccessor)
{
HttpContextAccessor = httpContextAccessor;
}
public virtual void CheckDaprAppApiToken()
{
var expectedAppApiToken = GetConfiguredAppApiTokenOrNull();
@ -24,7 +25,7 @@ public class DaprAppApiTokenValidator : IDaprAppApiTokenValidator, ISingletonDep
{
return;
}
var headerAppApiToken = GetDaprAppApiTokenOrNull();
if (headerAppApiToken.IsNullOrWhiteSpace())
{
@ -44,12 +45,12 @@ public class DaprAppApiTokenValidator : IDaprAppApiTokenValidator, ISingletonDep
{
return true;
}
var headerAppApiToken = GetDaprAppApiTokenOrNull();
return expectedAppApiToken == headerAppApiToken;
}
public virtual string? GetDaprAppApiTokenOrNull()
public virtual string GetDaprAppApiTokenOrNull()
{
string apiTokenHeader = HttpContext.Request.Headers["dapr-api-token"];
if (string.IsNullOrEmpty(apiTokenHeader) || apiTokenHeader.Length < 1)
@ -59,8 +60,8 @@ public class DaprAppApiTokenValidator : IDaprAppApiTokenValidator, ISingletonDep
return apiTokenHeader;
}
protected virtual string? GetConfiguredAppApiTokenOrNull()
protected virtual string GetConfiguredAppApiTokenOrNull()
{
return HttpContext
.RequestServices
@ -72,4 +73,4 @@ public class DaprAppApiTokenValidator : IDaprAppApiTokenValidator, ISingletonDep
{
return HttpContextAccessor.HttpContext ?? throw new AbpException("HttpContext is not available!");
}
}
}

@ -1,4 +1,5 @@
using Microsoft.AspNetCore.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
namespace Volo.Abp.AspNetCore.Mvc.Dapr;
@ -12,7 +13,7 @@ public static class DaprHttpContextExtensions
.GetRequiredService<IDaprAppApiTokenValidator>()
.CheckDaprAppApiToken();
}
public static bool IsValidDaprAppApiToken(this HttpContext httpContext)
{
return httpContext
@ -20,12 +21,12 @@ public static class DaprHttpContextExtensions
.GetRequiredService<IDaprAppApiTokenValidator>()
.IsValidDaprAppApiToken();
}
public static string? GetDaprAppApiTokenOrNull(HttpContext httpContext)
public static string GetDaprAppApiTokenOrNull(HttpContext httpContext)
{
return httpContext
.RequestServices
.GetRequiredService<IDaprAppApiTokenValidator>()
.GetDaprAppApiTokenOrNull();
}
}
}

@ -3,6 +3,8 @@ namespace Volo.Abp.AspNetCore.Mvc.Dapr;
public interface IDaprAppApiTokenValidator
{
void CheckDaprAppApiToken();
bool IsValidDaprAppApiToken();
string? GetDaprAppApiTokenOrNull();
}
string GetDaprAppApiTokenOrNull();
}

@ -5,8 +5,6 @@
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<RootNamespace />
</PropertyGroup>
@ -15,7 +13,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Dapr.Client" Version="1.8.0" />
<PackageReference Include="Dapr.Client" Version="1.9.0" />
</ItemGroup>
</Project>

@ -1,4 +1,6 @@
using System.Text.Json;
using System;
using System.Net.Http;
using System.Text.Json;
using Dapr.Client;
using Microsoft.Extensions.Options;
using Volo.Abp.DependencyInjection;
@ -22,7 +24,7 @@ public class AbpDaprClientFactory : IAbpDaprClientFactory, ISingletonDependency
JsonSerializerOptions = CreateJsonSerializerOptions(systemTextJsonSerializerOptions.Value);
}
public virtual DaprClient Create(Action<DaprClientBuilder>? builderAction = null)
public virtual DaprClient Create(Action<DaprClientBuilder> builderAction = null)
{
var builder = new DaprClientBuilder()
.UseJsonSerializationOptions(JsonSerializerOptions);
@ -49,9 +51,9 @@ public class AbpDaprClientFactory : IAbpDaprClientFactory, ISingletonDependency
}
public virtual HttpClient CreateHttpClient(
string? appId = null,
string? daprEndpoint = null,
string? daprApiToken = null)
string appId = null,
string daprEndpoint = null,
string daprApiToken = null)
{
if(daprEndpoint.IsNullOrWhiteSpace() &&
!DaprOptions.HttpEndpoint.IsNullOrWhiteSpace())
@ -65,9 +67,9 @@ public class AbpDaprClientFactory : IAbpDaprClientFactory, ISingletonDependency
daprApiToken ?? DaprApiTokenProvider.GetDaprApiToken()
);
}
protected virtual JsonSerializerOptions CreateJsonSerializerOptions(AbpSystemTextJsonSerializerOptions systemTextJsonSerializerOptions)
{
return new JsonSerializerOptions(systemTextJsonSerializerOptions.JsonSerializerOptions);
}
}
}

@ -1,4 +1,5 @@
using Microsoft.Extensions.Configuration;
using System;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Volo.Abp.Json;
@ -12,7 +13,7 @@ public class AbpDaprModule : AbpModule
public override void ConfigureServices(ServiceConfigurationContext context)
{
var configuration = context.Services.GetConfiguration();
ConfigureDaprOptions(configuration);
context.Services.TryAddSingleton(

@ -11,14 +11,14 @@ public class DaprApiTokenProvider : IDaprApiTokenProvider, ISingletonDependency
{
Options = options.Value;
}
public virtual string? GetDaprApiToken()
public virtual string GetDaprApiToken()
{
return Options.DaprApiToken;
}
public virtual string? GetAppApiToken()
public virtual string GetAppApiToken()
{
return Options.AppApiToken;
}
}
}

@ -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
);
}
}

@ -2,7 +2,7 @@ namespace Volo.Abp.Dapr;
public interface IDaprApiTokenProvider
{
string? GetDaprApiToken();
string? GetAppApiToken();
}
string GetDaprApiToken();
string GetAppApiToken();
}

@ -1,4 +1,6 @@
namespace Volo.Abp.Dapr;
using System;
namespace Volo.Abp.Dapr;
public interface IDaprSerializer
{
@ -6,11 +8,5 @@ public interface IDaprSerializer
object Deserialize(byte[] value, Type type);
T Deserialize<T>(byte[] value);
string SerializeToString(object obj);
object Deserialize(string value, Type type);
T Deserialize<T>(string value);
}

@ -1,4 +1,5 @@
using System.Text;
using System;
using System.Text;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Json;
@ -23,23 +24,8 @@ public class Utf8JsonDaprSerializer : IDaprSerializer, ITransientDependency
return _jsonSerializer.Deserialize(type, Encoding.UTF8.GetString(value));
}
public T Deserialize<T>(byte[] value)
{
return _jsonSerializer.Deserialize<T>(Encoding.UTF8.GetString(value));
}
public string SerializeToString(object obj)
{
return _jsonSerializer.Serialize(obj);
}
public object Deserialize(string value, Type type)
{
return _jsonSerializer.Deserialize(type, value);
}
public T Deserialize<T>(string value)
{
return _jsonSerializer.Deserialize<T>(value);
}
}

@ -2,11 +2,9 @@
<Import Project="..\..\..\configureawait.props" />
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<RootNamespace />
</PropertyGroup>
@ -14,5 +12,5 @@
<ProjectReference Include="..\Volo.Abp.Dapr\Volo.Abp.Dapr.csproj" />
<ProjectReference Include="..\Volo.Abp.DistributedLocking.Abstractions\Volo.Abp.DistributedLocking.Abstractions.csproj" />
</ItemGroup>
</Project>

@ -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,4 +1,7 @@
using Microsoft.Extensions.Options;
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Options;
using Volo.Abp.Dapr;
using Volo.Abp.DependencyInjection;
@ -10,7 +13,7 @@ public class DaprAbpDistributedLock : IAbpDistributedLock, ITransientDependency
protected IAbpDaprClientFactory DaprClientFactory { get; }
protected AbpDistributedLockDaprOptions DistributedLockDaprOptions { get; }
protected IDistributedLockKeyNormalizer DistributedLockKeyNormalizer { get; }
public DaprAbpDistributedLock(
IAbpDaprClientFactory daprClientFactory,
IOptions<AbpDistributedLockDaprOptions> distributedLockDaprOptions,
@ -20,8 +23,8 @@ public class DaprAbpDistributedLock : IAbpDistributedLock, ITransientDependency
DistributedLockKeyNormalizer = distributedLockKeyNormalizer;
DistributedLockDaprOptions = distributedLockDaprOptions.Value;
}
public async Task<IAbpDistributedLockHandle?> TryAcquireAsync(
public async Task<IAbpDistributedLockHandle> TryAcquireAsync(
string name,
TimeSpan timeout = default,
CancellationToken cancellationToken = default)
@ -30,8 +33,8 @@ public class DaprAbpDistributedLock : IAbpDistributedLock, ITransientDependency
var daprClient = DaprClientFactory.Create();
var lockResponse = await daprClient.Lock(
DistributedLockDaprOptions.StoreName,
name,
DistributedLockDaprOptions.StoreName,
name,
DistributedLockDaprOptions.Owner ?? Guid.NewGuid().ToString(),
(int)DistributedLockDaprOptions.DefaultExpirationTimeout.TotalSeconds,
cancellationToken);
@ -43,4 +46,4 @@ public class DaprAbpDistributedLock : IAbpDistributedLock, ITransientDependency
return new DaprAbpDistributedLockHandle(lockResponse);
}
}
}

@ -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();
}
}
}

@ -2,11 +2,9 @@
<Import Project="..\..\..\configureawait.props" />
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<RootNamespace />
</PropertyGroup>

@ -1,4 +1,8 @@
using System.Collections.Concurrent;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Volo.Abp.Dapr;
@ -113,7 +117,7 @@ public class DaprDistributedEventBus : DistributedEventBusBase, ISingletonDepend
GetOrCreateHandlerFactories(eventType).Locking(factories => factories.Clear());
}
protected async override Task PublishToEventBusAsync(Type eventType, object eventData)
protected override async Task PublishToEventBusAsync(Type eventType, object eventData)
{
await PublishToDaprAsync(eventType, eventData);
}
@ -135,12 +139,12 @@ public class DaprDistributedEventBus : DistributedEventBusBase, ISingletonDepend
return handlerFactoryList.ToArray();
}
public async override Task PublishFromOutboxAsync(OutgoingEventInfo outgoingEvent, OutboxConfig outboxConfig)
public override async Task PublishFromOutboxAsync(OutgoingEventInfo outgoingEvent, OutboxConfig outboxConfig)
{
await PublishToDaprAsync(outgoingEvent.EventName, Serializer.Deserialize(outgoingEvent.EventData, GetEventType(outgoingEvent.EventName)));
}
public async override Task PublishManyFromOutboxAsync(IEnumerable<OutgoingEventInfo> outgoingEvents, OutboxConfig outboxConfig)
public override async Task PublishManyFromOutboxAsync(IEnumerable<OutgoingEventInfo> outgoingEvents, OutboxConfig outboxConfig)
{
var outgoingEventArray = outgoingEvents.ToArray();

@ -2,11 +2,9 @@
<Import Project="..\..\..\configureawait.props" />
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<RootNamespace />
</PropertyGroup>

@ -1,4 +1,5 @@
using Dapr.Client;
using System;
using Dapr.Client;
using Microsoft.Extensions.Options;
using Volo.Abp.Dapr;
using Volo.Abp.DependencyInjection;
@ -14,4 +15,4 @@ public class AbpInvocationHandler : InvocationHandler, ITransientDependency
DaprEndpoint = daprOptions.Value.HttpEndpoint;
}
}
}
}

Loading…
Cancel
Save