Browse Source

feat(webhooks): added data access configuration

pull/532/head
cKey 4 years ago
parent
commit
5d525ea3ba
  1. 5
      aspnet-core/Directory.Build.props
  2. 9
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/DefaultWebhookPublisher.cs
  3. 21
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/Extensions/WebhookSubscriptionExtensions.cs
  4. 4
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/NullWebhookSendAttemptStore.cs
  5. 12
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/WebhookManager.cs
  6. 6
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/WebhookSubscriptionManager.cs
  7. 4
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Domain.Shared/LINGYUN/Abp/WebhooksManagement/Localization/Resources/en.json
  8. 4
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Domain.Shared/LINGYUN/Abp/WebhooksManagement/Localization/Resources/zh-Hans.json
  9. 8
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Domain.Shared/LINGYUN/Abp/WebhooksManagement/ObjectExtending/WebhooksManagementModuleExtensionConfiguration.cs
  10. 2
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Domain.Shared/LINGYUN/Abp/WebhooksManagement/ObjectExtending/WebhooksManagementModuleExtensionConfigurationDictionaryExtensions.cs
  11. 4
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Domain.Shared/LINGYUN/Abp/WebhooksManagement/ObjectExtending/WebhooksManagementModuleExtensionConsts.cs
  12. 12
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Domain.Shared/LINGYUN/Abp/WebhooksManagement/WebhookEventEto.cs
  13. 7
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Domain.Shared/LINGYUN/Abp/WebhooksManagement/WebhookEventRecordConsts.cs
  14. 16
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Domain.Shared/LINGYUN/Abp/WebhooksManagement/WebhookSendAttemptEto.cs
  15. 6
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Domain.Shared/LINGYUN/Abp/WebhooksManagement/WebhookSendRecordConsts.cs
  16. 9
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Domain.Shared/LINGYUN/Abp/WebhooksManagement/WebhookSubscriptionConsts.cs
  17. 14
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Domain.Shared/LINGYUN/Abp/WebhooksManagement/WebhookSubscriptionEto.cs
  18. 4
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Domain/LINGYUN/Abp/WebhooksManagement/DefaultWebhookManager.cs
  19. 29
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Domain/LINGYUN/Abp/WebhooksManagement/Extensions/WebhookSubscriptionExtensions.cs
  20. 175
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Domain/LINGYUN/Abp/WebhooksManagement/Extensions/WebhookSubscriptionInfoExtensions.cs
  21. 1
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Domain/LINGYUN/Abp/WebhooksManagement/IWebhookSendRecordRepository.cs
  22. 5
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Domain/LINGYUN/Abp/WebhooksManagement/WebhookEventRecord.cs
  23. 9
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Domain/LINGYUN/Abp/WebhooksManagement/WebhookEventStore.cs
  24. 127
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Domain/LINGYUN/Abp/WebhooksManagement/WebhookSendAttemptStore.cs
  25. 3
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Domain/LINGYUN/Abp/WebhooksManagement/WebhookSendRecord.cs
  26. 2
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Domain/LINGYUN/Abp/WebhooksManagement/WebhookSendRecordFilter.cs
  27. 24
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Domain/LINGYUN/Abp/WebhooksManagement/WebhookSubscription.cs
  28. 129
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Domain/LINGYUN/Abp/WebhooksManagement/WebhookSubscriptionsStore.cs
  29. 9
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Domain/LINGYUN/Abp/WebhooksManagement/WebhooksManagementDomainMapperProfile.cs
  30. 29
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Domain/LINGYUN/Abp/WebhooksManagement/WebhooksManagementDomainModule.cs
  31. 15
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.EntityFrameworkCore/LINGYUN/Abp/WebhooksManagement/EntityFrameworkCore/EfCoreWebhookEventRecordRepository.cs
  32. 58
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.EntityFrameworkCore/LINGYUN/Abp/WebhooksManagement/EntityFrameworkCore/EfCoreWebhookSendRecordRepository.cs
  33. 16
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.EntityFrameworkCore/LINGYUN/Abp/WebhooksManagement/EntityFrameworkCore/EfCoreWebhookSubscriptionRepository.cs
  34. 55
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.EntityFrameworkCore/LINGYUN/Abp/WebhooksManagement/EntityFrameworkCore/WebhooksManagementDbContextModelCreatingExtensions.cs
  35. 15
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.EntityFrameworkCore/LINGYUN/Abp/WebhooksManagement/EntityFrameworkCore/WebhooksManagementEfCoreQueryableExtensions.cs
  36. 4
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.EntityFrameworkCore/LINGYUN/Abp/WebhooksManagement/EntityFrameworkCore/WebhooksManagementEntityFrameworkCoreModule.cs
  37. 2
      aspnet-core/services/LY.MicroService.WebhooksManagement.HttpApi.Host/Controllers/HomeController.cs
  38. 2
      aspnet-core/services/LY.MicroService.WebhooksManagement.HttpApi.Host/DataSeeder/WebhooksManagementDataSeederWorker.cs
  39. 5
      aspnet-core/services/LY.MicroService.WebhooksManagement.HttpApi.Host/EntityFrameworkCore/WebhooksManagementMigrationsDbContext.cs
  40. 2
      aspnet-core/services/LY.MicroService.WebhooksManagement.HttpApi.Host/EntityFrameworkCore/WebhooksManagementMigrationsDbContextFactory.cs
  41. 10
      aspnet-core/services/LY.MicroService.WebhooksManagement.HttpApi.Host/EventBus/Handlers/TenantSynchronizer.cs
  42. 9
      aspnet-core/services/LY.MicroService.WebhooksManagement.HttpApi.Host/LY.MicroService.WebhooksManagement.HttpApi.Host.csproj
  43. 2
      aspnet-core/services/LY.MicroService.WebhooksManagement.HttpApi.Host/Program.cs
  44. 9
      aspnet-core/services/LY.MicroService.WebhooksManagement.HttpApi.Host/Properties/launchSettings.json
  45. 2
      aspnet-core/services/LY.MicroService.WebhooksManagement.HttpApi.Host/TenantHeaderParamter.cs
  46. 8
      aspnet-core/services/LY.MicroService.WebhooksManagement.HttpApi.Host/WebhooksManagementHttpApiHostModule.Configure.cs
  47. 4
      aspnet-core/services/LY.MicroService.WebhooksManagement.HttpApi.Host/WebhooksManagementHttpApiHostModule.DataSeeder.cs
  48. 11
      aspnet-core/services/LY.MicroService.WebhooksManagement.HttpApi.Host/WebhooksManagementHttpApiHostModule.cs

5
aspnet-core/Directory.Build.props

@ -12,6 +12,11 @@
<HangfireMySqlStoragePackageVersion>2.0.3</HangfireMySqlStoragePackageVersion>
<HangfireMSSQLStoragePackageVersion>1.7.28</HangfireMSSQLStoragePackageVersion>
<NESTPackageVersion>7.15.1</NESTPackageVersion>
<OpenTelemetryExtensionsHostingPackageVersion>1.0.0-rc8</OpenTelemetryExtensionsHostingPackageVersion>
<OpenTelemetryExporterZipkinPackageVersion>1.2.0-rc1</OpenTelemetryExporterZipkinPackageVersion>
<OpenTelemetryInstrumentationAspNetCorePackageVersion>1.0.0-rc8</OpenTelemetryInstrumentationAspNetCorePackageVersion>
<OpenTelemetryInstrumentationHttpPackageVersion>1.0.0-rc8</OpenTelemetryInstrumentationHttpPackageVersion>
<OpenTelemetryContribInstrumentationEntityFrameworkCorePackageVersion>1.0.0-beta2</OpenTelemetryContribInstrumentationEntityFrameworkCorePackageVersion>
<QuartzNETPackageVersion>3.3.3</QuartzNETPackageVersion>
<StackExchangeRedisPackageVersion>2.0.593</StackExchangeRedisPackageVersion>
<SerilogPackageVersion>2.10.0</SerilogPackageVersion>

9
aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/DefaultWebhookPublisher.cs

@ -1,10 +1,10 @@
using System;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.BackgroundJobs;
using Volo.Abp.Guids;
using Volo.Abp.Json;
using Volo.Abp.MultiTenancy;
namespace LINGYUN.Abp.Webhooks
@ -15,7 +15,6 @@ namespace LINGYUN.Abp.Webhooks
private readonly ICurrentTenant _currentTenant;
private readonly IGuidGenerator _guidGenerator;
private readonly IJsonSerializer _jsonSerializer;
private readonly IBackgroundJobManager _backgroundJobManager;
private readonly IWebhookSubscriptionManager _webhookSubscriptionManager;
@ -23,12 +22,10 @@ namespace LINGYUN.Abp.Webhooks
IWebhookSubscriptionManager webhookSubscriptionManager,
ICurrentTenant currentTenant,
IGuidGenerator guidGenerator,
IJsonSerializer jsonSerializer,
IBackgroundJobManager backgroundJobManager)
{
_currentTenant = currentTenant;
_guidGenerator = guidGenerator;
_jsonSerializer = jsonSerializer;
_backgroundJobManager = backgroundJobManager;
_webhookSubscriptionManager = webhookSubscriptionManager;
@ -114,7 +111,7 @@ namespace LINGYUN.Abp.Webhooks
{
Id = _guidGenerator.Create(),
WebhookName = webhookName,
Data = _jsonSerializer.Serialize(data),
Data = JsonConvert.SerializeObject(data),
TenantId = tenantId
};

21
aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/Extensions/WebhookSubscriptionExtensions.cs

@ -0,0 +1,21 @@
using System.Collections.Generic;
namespace LINGYUN.Abp.Webhooks.Extensions
{
public static class WebhookSubscriptionExtensions
{
/// <summary>
/// checks if subscribed to given webhook
/// </summary>
/// <returns></returns>
public static bool IsSubscribed(this WebhookSubscriptionInfo webhookSubscription, string webhookName)
{
if (webhookSubscription.Webhooks.IsNullOrEmpty())
{
return false;
}
return webhookSubscription.Webhooks.Contains(webhookName);
}
}
}

4
aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/NullWebhookSendAttemptStore.cs

@ -33,10 +33,10 @@ namespace LINGYUN.Abp.Webhooks
return default;
}
public Task<IReadOnlyCollection<WebhookSendAttempt>> GetAllSendAttemptsBySubscriptionAsPagedListAsync(Guid? tenantId, Guid subscriptionId, int maxResultCount,
public Task<(int TotalCount, IReadOnlyCollection<WebhookSendAttempt> Webhooks)> GetAllSendAttemptsBySubscriptionAsPagedListAsync(Guid? tenantId, Guid subscriptionId, int maxResultCount,
int skipCount)
{
return Task.FromResult(new List<WebhookSendAttempt>() as IReadOnlyCollection<WebhookSendAttempt>);
return Task.FromResult(ValueTuple.Create(0, new List<WebhookSendAttempt>() as IReadOnlyCollection<WebhookSendAttempt>));
}
public Task<List<WebhookSendAttempt>> GetAllSendAttemptsByWebhookEventIdAsync(Guid? tenantId, Guid webhookEventId)

12
aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/WebhookManager.cs

@ -1,10 +1,10 @@
using System;
using Newtonsoft.Json;
using System;
using System.Globalization;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.Json;
namespace LINGYUN.Abp.Webhooks
{
@ -13,21 +13,17 @@ namespace LINGYUN.Abp.Webhooks
private const string SignatureHeaderKey = "sha256";
private const string SignatureHeaderValueTemplate = SignatureHeaderKey + "={0}";
private const string SignatureHeaderName = "abp-webhook-signature";
protected IJsonSerializer JsonSerializer { get; }
protected IWebhookSendAttemptStore WebhookSendAttemptStore { get; }
protected WebhookManager(
IJsonSerializer jsonSerializer,
IWebhookSendAttemptStore webhookSendAttemptStore)
{
JsonSerializer = jsonSerializer;
WebhookSendAttemptStore = webhookSendAttemptStore;
}
public virtual async Task<WebhookPayload> GetWebhookPayloadAsync(WebhookSenderArgs webhookSenderArgs)
{
var data = JsonSerializer.Serialize(webhookSenderArgs.Data);
var data = JsonConvert.SerializeObject(webhookSenderArgs.Data);
var attemptNumber = await WebhookSendAttemptStore.GetSendAttemptCountAsync(
webhookSenderArgs.TenantId,
@ -72,7 +68,7 @@ namespace LINGYUN.Abp.Webhooks
var payload = await GetWebhookPayloadAsync(webhookSenderArgs);
var serializedBody = JsonSerializer.Serialize(payload);
var serializedBody = JsonConvert.SerializeObject(payload);
return serializedBody;
}

6
aspnet-core/modules/webhooks/LINGYUN.Abp.WebHooks/LINGYUN/Abp/Webhooks/WebhookSubscriptionManager.cs

@ -93,11 +93,7 @@ namespace LINGYUN.Abp.Webhooks
}
else
{
var subscription = await WebhookSubscriptionsStore.GetAsync(webhookSubscription.Id);
subscription.WebhookUri = webhookSubscription.WebhookUri;
subscription.Webhooks = webhookSubscription.Webhooks;
subscription.Headers = webhookSubscription.Headers;
await WebhookSubscriptionsStore.UpdateAsync(subscription);
await WebhookSubscriptionsStore.UpdateAsync(webhookSubscription);
}
await uow.SaveChangesAsync();

4
aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Domain.Shared/LINGYUN/Abp/WebhooksManagement/Localization/Resources/en.json

@ -1,8 +1,8 @@
{
"culture": "en",
"texts": {
"Features:WebhooksManagement": "WebhooksManagement",
"Permission:WebhooksManagement": "WebhooksManagement",
"Features:WebhooksManagement": "Webhooks",
"Permission:WebhooksManagement": "Webhooks",
"Permission:ManageSettings": "Manage Settings"
}
}

4
aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Domain.Shared/LINGYUN/Abp/WebhooksManagement/Localization/Resources/zh-Hans.json

@ -1,8 +1,8 @@
{
"culture": "zh-Hans",
"texts": {
"Features:WebhooksManagement": "WebhooksManagement",
"Permission:WebhooksManagement": "WebhooksManagement",
"Features:WebhooksManagement": "Webhooks",
"Permission:WebhooksManagement": "Webhooks",
"Permission:ManageSettings": "管理设置"
}
}

8
aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Domain.Shared/LINGYUN/Abp/WebhooksManagement/ObjectExtending/WebhooksManagementModuleExtensionConfiguration.cs

@ -8,9 +8,9 @@ public class WebhooksManagementModuleExtensionConfiguration : ModuleExtensionCon
public WebhooksManagementModuleExtensionConfiguration ConfigureWebhooksManagement(
Action<EntityExtensionConfiguration> configureAction)
{
return this.ConfigureEntity(
WebhooksManagementModuleExtensionConsts.EntityNames.Entity,
configureAction
);
return this
.ConfigureEntity(WebhooksManagementModuleExtensionConsts.EntityNames.WebhookEvent, configureAction)
.ConfigureEntity(WebhooksManagementModuleExtensionConsts.EntityNames.WebhookSendAttempt, configureAction)
.ConfigureEntity(WebhooksManagementModuleExtensionConsts.EntityNames.WebhookSubscription, configureAction);
}
}

2
aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Domain.Shared/LINGYUN/Abp/WebhooksManagement/ObjectExtending/WebhooksManagementModuleExtensionConfigurationDictionaryExtensions.cs

@ -1,6 +1,4 @@
using System;
using System.Collections.Generic;
using System.Text;
using Volo.Abp.ObjectExtending.Modularity;
namespace LINGYUN.Abp.WebhooksManagement.ObjectExtending;

4
aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Domain.Shared/LINGYUN/Abp/WebhooksManagement/ObjectExtending/WebhooksManagementModuleExtensionConsts.cs

@ -6,6 +6,8 @@ public static class WebhooksManagementModuleExtensionConsts
public static class EntityNames
{
public const string Entity = "Entity";
public const string WebhookEvent = "WebhookEvent";
public const string WebhookSendAttempt = "WebhookSendAttempt";
public const string WebhookSubscription = "WebhookSubscription";
}
}

12
aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Domain.Shared/LINGYUN/Abp/WebhooksManagement/WebhookEventEto.cs

@ -0,0 +1,12 @@
using System;
using Volo.Abp.MultiTenancy;
namespace LINGYUN.Abp.WebhooksManagement;
[Serializable]
public class WebhookEventEto : IMultiTenant
{
public Guid Id { get; set; }
public Guid? TenantId { get; set; }
public string WebhookName { get; set; }
}

7
aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Domain.Shared/LINGYUN/Abp/WebhooksManagement/WebhookEventRecordConsts.cs

@ -0,0 +1,7 @@
namespace LINGYUN.Abp.WebhooksManagement;
public static class WebhookEventRecordConsts
{
public static int MaxWebhookNameLength { get; set; } = 100;
public static int MaxDataLength { get; set; } = int.MaxValue;
}

16
aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Domain.Shared/LINGYUN/Abp/WebhooksManagement/WebhookSendAttemptEto.cs

@ -0,0 +1,16 @@
using System;
using Volo.Abp.MultiTenancy;
namespace LINGYUN.Abp.WebhooksManagement;
[Serializable]
public class WebhookSendAttemptEto : IMultiTenant
{
public Guid Id { get; set; }
public Guid? TenantId { get; set; }
public Guid WebhookEventId { get; set; }
public Guid WebhookSubscriptionId { get; set; }
}

6
aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Domain.Shared/LINGYUN/Abp/WebhooksManagement/WebhookSendRecordConsts.cs

@ -0,0 +1,6 @@
namespace LINGYUN.Abp.WebhooksManagement;
public static class WebhookSendRecordConsts
{
public static int MaxResponseLength { get; set; } = int.MaxValue;
}

9
aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Domain.Shared/LINGYUN/Abp/WebhooksManagement/WebhookSubscriptionConsts.cs

@ -0,0 +1,9 @@
namespace LINGYUN.Abp.WebhooksManagement;
public static class WebhookSubscriptionConsts
{
public static int MaxWebhookUriLength { get; set; } = 255;
public static int MaxSecretLength { get; set; } = 128;
public static int MaxWebhooksLength { get; set; } = int.MaxValue;
public static int MaxHeadersLength { get; set; } = int.MaxValue;
}

14
aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Domain.Shared/LINGYUN/Abp/WebhooksManagement/WebhookSubscriptionEto.cs

@ -0,0 +1,14 @@
using System;
using Volo.Abp.MultiTenancy;
namespace LINGYUN.Abp.WebhooksManagement;
[Serializable]
public class WebhookSubscriptionEto : IMultiTenant
{
public Guid Id { get; set; }
public Guid? TenantId { get; set; }
public string WebhookUri { get; set; }
}

4
aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Domain/LINGYUN/Abp/WebhooksManagement/DefaultWebhookManager.cs

@ -4,7 +4,6 @@ using System.Net;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Guids;
using Volo.Abp.Json;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Uow;
@ -19,11 +18,10 @@ public class DefaultWebhookManager : WebhookManager, ITransientDependency
public DefaultWebhookManager(
ICurrentTenant currentTenant,
IGuidGenerator guidGenerator,
IJsonSerializer jsonSerializer,
IWebhookSendAttemptStore webhookSendAttemptStore,
IUnitOfWorkManager unitOfWorkManager,
IWebhookSendRecordRepository webhookSendAttemptRepository)
: base(jsonSerializer, webhookSendAttemptStore)
: base(webhookSendAttemptStore)
{
CurrentTenant = currentTenant;
GuidGenerator = guidGenerator;

29
aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Domain/LINGYUN/Abp/WebhooksManagement/Extensions/WebhookSubscriptionExtensions.cs

@ -0,0 +1,29 @@
using LINGYUN.Abp.Webhooks;
using Newtonsoft.Json;
using System.Linq;
namespace LINGYUN.Abp.WebhooksManagement.Extensions
{
public static class WebhookSubscriptionExtensions
{
public static string ToSubscribedWebhooksString(this WebhookSubscriptionInfo webhookSubscription)
{
if (webhookSubscription.Webhooks.Any())
{
return JsonConvert.SerializeObject(webhookSubscription.Webhooks);
}
return null;
}
public static string ToWebhookHeadersString(this WebhookSubscriptionInfo webhookSubscription)
{
if (webhookSubscription.Headers.Any())
{
return JsonConvert.SerializeObject(webhookSubscription.Headers);
}
return null;
}
}
}

175
aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Domain/LINGYUN/Abp/WebhooksManagement/Extensions/WebhookSubscriptionInfoExtensions.cs

@ -0,0 +1,175 @@
using LINGYUN.Abp.Webhooks;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
namespace LINGYUN.Abp.WebhooksManagement.Extensions
{
public static class WebhookSubscriptionInfoExtensions
{
/// <summary>
/// Return List of subscribed webhooks definitions <see cref="WebhookSubscriptionInfo.Webhooks"/>
/// </summary>
/// <returns></returns>
public static List<string> GetSubscribedWebhooks(this WebhookSubscription webhookSubscription)
{
if (webhookSubscription.Webhooks.IsNullOrWhiteSpace())
{
return new List<string>();
}
return JsonConvert.DeserializeObject<List<string>>(webhookSubscription.Webhooks);
}
/// <summary>
/// Adds webhook subscription to <see cref="WebhookSubscriptionInfo.Webhooks"/> if not exists
/// </summary>
/// <param name="webhookSubscription"></param>
/// <param name="name">webhook unique name</param>
public static void SubscribeWebhook(this WebhookSubscription webhookSubscription, string name)
{
name = name.Trim();
if (name.IsNullOrWhiteSpace())
{
throw new ArgumentNullException(nameof(name), $"{nameof(name)} can not be null, empty or whitespace!");
}
var webhookDefinitions = webhookSubscription.GetSubscribedWebhooks();
if (webhookDefinitions.Contains(name))
{
return;
}
webhookDefinitions.Add(name);
webhookSubscription.SetWebhooks(JsonConvert.SerializeObject(webhookDefinitions));
}
/// <summary>
/// Removes webhook subscription from <see cref="WebhookSubscriptionInfo.Webhooks"/> if exists
/// </summary>
/// <param name="webhookSubscription"></param>
/// <param name="name">webhook unique name</param>
public static void UnsubscribeWebhook(this WebhookSubscription webhookSubscription, string name)
{
name = name.Trim();
if (name.IsNullOrWhiteSpace())
{
throw new ArgumentNullException(nameof(name), $"{nameof(name)} can not be null, empty or whitespace!");
}
var webhookDefinitions = webhookSubscription.GetSubscribedWebhooks();
if (!webhookDefinitions.Contains(name))
{
return;
}
webhookDefinitions.Remove(name);
webhookSubscription.SetWebhooks(JsonConvert.SerializeObject(webhookDefinitions));
}
/// <summary>
/// Clears all <see cref="WebhookSubscriptionInfo.Webhooks"/>
/// </summary>
/// <param name="webhookSubscription"></param>
public static void RemoveAllSubscribedWebhooks(this WebhookSubscription webhookSubscription)
{
webhookSubscription.SetWebhooks(null);
}
/// <summary>
/// if subscribed to given webhook
/// </summary>
/// <returns></returns>
public static bool IsSubscribed(this WebhookSubscription webhookSubscription, string webhookName)
{
if (webhookSubscription.Webhooks.IsNullOrWhiteSpace())
{
return false;
}
return webhookSubscription.GetSubscribedWebhooks().Contains(webhookName);
}
/// <summary>
/// Returns additional webhook headers <see cref="WebhookSubscriptionInfo.Headers"/>
/// </summary>
/// <returns></returns>
public static IDictionary<string, string> GetWebhookHeaders(this WebhookSubscription webhookSubscription)
{
if (webhookSubscription.Headers.IsNullOrWhiteSpace())
{
return new Dictionary<string, string>();
}
return JsonConvert.DeserializeObject<Dictionary<string, string>>(webhookSubscription.Headers);
}
/// <summary>
/// Adds webhook subscription to <see cref="WebhookSubscriptionInfo.Webhooks"/> if not exists
/// </summary>
public static void AddWebhookHeader(this WebhookSubscription webhookSubscription, string key, string value)
{
if (key.IsNullOrWhiteSpace() )
{
throw new ArgumentNullException(nameof(key), $"{nameof(key)} can not be null, empty or whitespace!");
}
if (value.IsNullOrWhiteSpace())
{
throw new ArgumentNullException(nameof(value), $"{nameof(value)} can not be null, empty or whitespace!");
}
var headers = webhookSubscription.GetWebhookHeaders();
headers[key] = value;
webhookSubscription.SetHeaders(JsonConvert.SerializeObject(headers));
}
/// <summary>
/// Adds webhook subscription to <see cref="WebhookSubscriptionInfo.Webhooks"/> if not exists
/// </summary>
/// <param name="webhookSubscription"></param>
/// <param name="header">Key of header</param>
public static void RemoveWebhookHeader(this WebhookSubscription webhookSubscription, string header)
{
if (header.IsNullOrWhiteSpace())
{
throw new ArgumentNullException(nameof(header), $"{nameof(header)} can not be null, empty or whitespace!");
}
var headers = webhookSubscription.GetWebhookHeaders();
if (!headers.ContainsKey(header))
{
return;
}
headers.Remove(header);
webhookSubscription.SetHeaders(JsonConvert.SerializeObject(headers));
}
/// <summary>
/// Clears all <see cref="WebhookSubscriptionInfo.Webhooks"/>
/// </summary>
/// <param name="webhookSubscription"></param>
public static void RemoveAllWebhookHeaders(this WebhookSubscription webhookSubscription)
{
webhookSubscription.SetHeaders(null);
}
public static WebhookSubscriptionInfo ToWebhookSubscriptionInfo(this WebhookSubscription webhookSubscription)
{
return new WebhookSubscriptionInfo
{
Id = webhookSubscription.Id,
TenantId = webhookSubscription.TenantId,
IsActive = webhookSubscription.IsActive,
Secret = webhookSubscription.Secret,
WebhookUri = webhookSubscription.WebhookUri,
Webhooks = webhookSubscription.GetSubscribedWebhooks(),
Headers = webhookSubscription.GetWebhookHeaders()
};
}
}
}

1
aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Domain/LINGYUN/Abp/WebhooksManagement/IWebhookSendRecordRepository.cs

@ -17,5 +17,6 @@ public interface IWebhookSendRecordRepository : IRepository<WebhookSendRecord, G
string sorting = nameof(WebhookSendRecord.CreationTime),
int maxResultCount = 10,
int skipCount = 10,
bool includeDetails = false,
CancellationToken cancellationToken = default);
}

5
aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Domain/LINGYUN/Abp/WebhooksManagement/WebhookEventRecord.cs

@ -1,4 +1,5 @@
using System;
using Volo.Abp;
using Volo.Abp.Auditing;
using Volo.Abp.Domain.Entities;
using Volo.Abp.MultiTenancy;
@ -23,8 +24,8 @@ public class WebhookEventRecord : Entity<Guid>, IMultiTenant, IHasCreationTime,
string data,
Guid? tenantId = null) : base(id)
{
WebhookName = webhookName;
Data = data;
WebhookName = Check.NotNullOrWhiteSpace(webhookName, nameof(webhookName), WebhookEventRecordConsts.MaxWebhookNameLength);
Data = Check.Length(data, nameof(data), WebhookEventRecordConsts.MaxDataLength);
TenantId = tenantId;
}
}

9
aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Domain/LINGYUN/Abp/WebhooksManagement/WebhookEventStore.cs

@ -11,20 +11,17 @@ public class WebhookEventStore : DomainService, IWebhookEventStore
{
protected IObjectMapper<WebhooksManagementDomainModule> ObjectMapper => LazyServiceProvider.LazyGetRequiredService<IObjectMapper<WebhooksManagementDomainModule>>();
protected IUnitOfWorkManager UnitOfWorkManager { get; }
protected IWebhookEventRecordRepository WebhookEventRepository { get; }
public WebhookEventStore(
IUnitOfWorkManager unitOfWorkManager,
IWebhookEventRecordRepository webhookEventRepository)
{
UnitOfWorkManager = unitOfWorkManager;
WebhookEventRepository = webhookEventRepository;
}
[UnitOfWork]
public async virtual Task<WebhookEvent> GetAsync(Guid? tenantId, Guid id)
{
using var uow = UnitOfWorkManager.Begin();
using (CurrentTenant.Change(tenantId))
{
var record = await WebhookEventRepository.GetAsync(id);
@ -33,9 +30,9 @@ public class WebhookEventStore : DomainService, IWebhookEventStore
}
}
[UnitOfWork]
public async virtual Task<Guid> InsertAndGetIdAsync(WebhookEvent webhookEvent)
{
using var uow = UnitOfWorkManager.Begin();
using (CurrentTenant.Change(webhookEvent.TenantId))
{
var record = new WebhookEventRecord(
@ -49,8 +46,6 @@ public class WebhookEventStore : DomainService, IWebhookEventStore
await WebhookEventRepository.InsertAsync(record);
await uow.SaveChangesAsync();
return record.Id;
}
}

127
aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Domain/LINGYUN/Abp/WebhooksManagement/WebhookSendAttemptStore.cs

@ -7,7 +7,6 @@ using System.Net;
using System.Threading.Tasks;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Domain.Services;
using Volo.Abp.Linq;
using Volo.Abp.ObjectMapping;
using Volo.Abp.Uow;
@ -16,150 +15,108 @@ namespace LINGYUN.Abp.WebhooksManagement;
public class WebhookSendAttemptStore : DomainService, IWebhookSendAttemptStore
{
protected IObjectMapper<WebhooksManagementDomainModule> ObjectMapper => LazyServiceProvider.LazyGetRequiredService<IObjectMapper<WebhooksManagementDomainModule>>();
protected IAsyncQueryableExecuter AsyncQueryableExecuter => LazyServiceProvider.LazyGetRequiredService<IAsyncQueryableExecuter>();
protected IUnitOfWorkManager UnitOfWorkManager { get; }
protected IWebhookSendRecordRepository WebhookSendAttemptRepository { get; }
public WebhookSendAttemptStore(
IUnitOfWorkManager unitOfWorkManager,
IWebhookSendRecordRepository webhookSendAttemptRepository)
{
UnitOfWorkManager = unitOfWorkManager;
WebhookSendAttemptRepository = webhookSendAttemptRepository;
}
[UnitOfWork]
public async virtual Task<(int TotalCount, IReadOnlyCollection<WebhookSendAttempt> Webhooks)> GetAllSendAttemptsBySubscriptionAsPagedListAsync(
Guid? tenantId,
Guid subscriptionId,
int maxResultCount,
int skipCount)
{
(int TotalCount, IReadOnlyCollection<WebhookSendAttempt> Webhooks) sendAttempts;
using (var uow = UnitOfWorkManager.Begin())
using (CurrentTenant.Change(tenantId))
{
using (CurrentTenant.Change(tenantId))
var filter = new WebhookSendRecordFilter
{
var filter = new WebhookSendRecordFilter
{
SubscriptionId = subscriptionId,
};
var totalCount = await WebhookSendAttemptRepository.GetCountAsync(filter);
var list = await WebhookSendAttemptRepository.GetListAsync(
filter,
maxResultCount: maxResultCount,
skipCount: skipCount);
SubscriptionId = subscriptionId,
};
var totalCount = await WebhookSendAttemptRepository.GetCountAsync(filter);
var webHooks = ObjectMapper.Map<List<WebhookSendRecord>, List<WebhookSendAttempt>>(list);
var list = await WebhookSendAttemptRepository.GetListAsync(
filter,
maxResultCount: maxResultCount,
skipCount: skipCount);
sendAttempts = ValueTuple.Create(totalCount, webHooks.ToImmutableList());
}
var webHooks = ObjectMapper.Map<List<WebhookSendRecord>, List<WebhookSendAttempt>>(list);
await uow.CompleteAsync();
return ValueTuple.Create(totalCount, webHooks.ToImmutableList());
}
return sendAttempts;
}
[UnitOfWork]
public async virtual Task<List<WebhookSendAttempt>> GetAllSendAttemptsByWebhookEventIdAsync(
Guid? tenantId,
Guid webhookEventId)
{
List<WebhookSendAttempt> sendAttempts;
using (var uow = UnitOfWorkManager.Begin())
using (CurrentTenant.Change(tenantId))
{
using (CurrentTenant.Change(tenantId))
{
var queryable = await WebhookSendAttemptRepository.GetQueryableAsync();
var queryable = await WebhookSendAttemptRepository.GetQueryableAsync();
var list = await AsyncQueryableExecuter.ToListAsync(queryable
.Where(attempt => attempt.WebhookEventId == webhookEventId)
.OrderByDescending(attempt => attempt.CreationTime)
);
sendAttempts = ObjectMapper.Map<List<WebhookSendRecord>, List<WebhookSendAttempt>>(list);
}
var list = await AsyncExecuter.ToListAsync(queryable
.Where(attempt => attempt.WebhookEventId == webhookEventId)
.OrderByDescending(attempt => attempt.CreationTime)
);
await uow.CompleteAsync();
return ObjectMapper.Map<List<WebhookSendRecord>, List<WebhookSendAttempt>>(list);
}
return sendAttempts;
}
[UnitOfWork]
public async virtual Task<WebhookSendAttempt> GetAsync(
Guid? tenantId,
Guid id)
{
WebhookSendRecord sendAttempt;
using (var uow = UnitOfWorkManager.Begin())
using (CurrentTenant.Change(tenantId))
{
using (CurrentTenant.Change(tenantId))
{
sendAttempt = await WebhookSendAttemptRepository.GetAsync(id);
}
var sendAttempt = await WebhookSendAttemptRepository.GetAsync(id);
await uow.CompleteAsync();
return ObjectMapper.Map<WebhookSendRecord, WebhookSendAttempt>(sendAttempt);
}
return ObjectMapper.Map<WebhookSendRecord, WebhookSendAttempt>(sendAttempt);
}
[UnitOfWork]
public async virtual Task<int> GetSendAttemptCountAsync(
Guid? tenantId,
Guid webhookEventId,
Guid webhookSubscriptionId)
{
int sendAttemptCount;
using (var uow = UnitOfWorkManager.Begin())
using (CurrentTenant.Change(tenantId))
{
using (CurrentTenant.Change(tenantId))
{
sendAttemptCount = await WebhookSendAttemptRepository.CountAsync(attempt =>
attempt.WebhookEventId == webhookEventId &&
attempt.WebhookSubscriptionId == webhookSubscriptionId);
}
await uow.CompleteAsync();
return await WebhookSendAttemptRepository.CountAsync(attempt =>
attempt.WebhookEventId == webhookEventId &&
attempt.WebhookSubscriptionId == webhookSubscriptionId);
}
return sendAttemptCount;
}
[UnitOfWork]
public async virtual Task<bool> HasXConsecutiveFailAsync(
Guid? tenantId,
Guid subscriptionId,
int failCount)
{
bool result;
using (var uow = UnitOfWorkManager.Begin())
using (CurrentTenant.Change(tenantId))
{
using (CurrentTenant.Change(tenantId))
if (await WebhookSendAttemptRepository.CountAsync(x => x.WebhookSubscriptionId == subscriptionId) < failCount)
{
if (await WebhookSendAttemptRepository.CountAsync(x => x.WebhookSubscriptionId == subscriptionId) < failCount)
{
result = false;
}
else
{
var queryable = await WebhookSendAttemptRepository.GetQueryableAsync();
result = !await AsyncQueryableExecuter.AnyAsync(queryable
.OrderByDescending(attempt => attempt.CreationTime)
.Take(failCount)
.Where(attempt => attempt.ResponseStatusCode == HttpStatusCode.OK)
);
}
return false;
}
else
{
var queryable = await WebhookSendAttemptRepository.GetQueryableAsync();
await uow.CompleteAsync();
return !await AsyncExecuter.AnyAsync(queryable
.OrderByDescending(attempt => attempt.CreationTime)
.Take(failCount)
.Where(attempt => attempt.ResponseStatusCode == HttpStatusCode.OK)
);
}
}
return result;
}
}

3
aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Domain/LINGYUN/Abp/WebhooksManagement/WebhookSendRecord.cs

@ -1,5 +1,6 @@
using System;
using System.Net;
using Volo.Abp;
using Volo.Abp.Auditing;
using Volo.Abp.Domain.Entities;
using Volo.Abp.MultiTenancy;
@ -44,7 +45,7 @@ public class WebhookSendRecord : Entity<Guid>, IHasCreationTime, IHasModificatio
string response,
HttpStatusCode? statusCode = null)
{
Response = response;
Response = Check.Length(response, nameof(response), WebhookSendRecordConsts.MaxResponseLength);
ResponseStatusCode = statusCode;
}
}

2
aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Domain/LINGYUN/Abp/WebhooksManagement/WebhookSendRecordFilter.cs

@ -11,8 +11,6 @@ public class WebhookSendRecordFilter
public Guid? SubscriptionId { get; set; }
public string Response { get; set; }
public HttpStatusCode? ResponseStatusCode { get; set; }
public DateTime? BeginCreationTime { get; set; }

24
aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Domain/LINGYUN/Abp/WebhooksManagement/WebhookSubscription.cs

@ -1,4 +1,5 @@
using System;
using Volo.Abp;
using Volo.Abp.Domain.Entities.Auditing;
namespace LINGYUN.Abp.WebhooksManagement;
@ -22,12 +23,27 @@ public class WebhookSubscription : CreationAuditedEntity<Guid>
string headers,
Guid? tenantId = null) : base(id)
{
WebhookUri = webhookUri;
Secret = secret;
Webhooks = webhooks;
Headers = headers;
Secret = Check.NotNullOrWhiteSpace(secret, nameof(secret), WebhookSubscriptionConsts.MaxSecretLength);
SetWebhookUri(webhookUri);
SetWebhooks(webhooks);
SetHeaders(headers);
TenantId = tenantId;
IsActive = true;
}
public void SetWebhookUri(string webhookUri)
{
WebhookUri = Check.NotNullOrWhiteSpace(webhookUri, nameof(webhookUri), WebhookSubscriptionConsts.MaxWebhookUriLength);
}
public void SetWebhooks(string webhooks)
{
Webhooks = Check.Length(webhooks, nameof(webhooks), WebhookSubscriptionConsts.MaxWebhooksLength);
}
public void SetHeaders(string headers)
{
Headers = Check.Length(headers, nameof(headers), WebhookSubscriptionConsts.MaxHeadersLength);
}
}

129
aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Domain/LINGYUN/Abp/WebhooksManagement/WebhookSubscriptionsStore.cs

@ -1,55 +1,148 @@
using LINGYUN.Abp.Webhooks;
using LINGYUN.Abp.WebhooksManagement.Extensions;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.Domain.Services;
using Volo.Abp.Uow;
namespace LINGYUN.Abp.WebhooksManagement;
public class WebhookSubscriptionsStore : DomainService, IWebhookSubscriptionsStore
{
public Task DeleteAsync(Guid id)
protected IWebhookSubscriptionRepository SubscriptionRepository { get; }
public WebhookSubscriptionsStore(
IWebhookSubscriptionRepository subscriptionRepository)
{
SubscriptionRepository = subscriptionRepository;
}
[UnitOfWork]
public async virtual Task DeleteAsync(Guid id)
{
throw new NotImplementedException();
using (CurrentTenant.Change(null))
{
await SubscriptionRepository.DeleteAsync(id);
}
}
public Task<List<WebhookSubscriptionInfo>> GetAllSubscriptionsAsync(Guid? tenantId)
[UnitOfWork]
public async virtual Task<List<WebhookSubscriptionInfo>> GetAllSubscriptionsAsync(Guid? tenantId)
{
throw new NotImplementedException();
using (CurrentTenant.Change(null))
{
var queryable = await SubscriptionRepository.GetQueryableAsync();
var subscriptions = await AsyncExecuter.ToListAsync(queryable.Where(x => x.TenantId == tenantId));
return subscriptions.Select(subscription => subscription.ToWebhookSubscriptionInfo()).ToList();
}
}
public Task<List<WebhookSubscriptionInfo>> GetAllSubscriptionsAsync(Guid? tenantId, string webhookName)
[UnitOfWork]
public async virtual Task<List<WebhookSubscriptionInfo>> GetAllSubscriptionsAsync(Guid? tenantId, string webhookName)
{
throw new NotImplementedException();
using (CurrentTenant.Change(null))
{
var queryable = await SubscriptionRepository.GetQueryableAsync();
var subscriptions = await AsyncExecuter.ToListAsync(
queryable.Where(x =>
x.TenantId == tenantId &&
x.IsActive &&
x.Webhooks.Contains("\"" + webhookName + "\"")));
return subscriptions.Select(subscription => subscription.ToWebhookSubscriptionInfo()).ToList();
}
}
public Task<List<WebhookSubscriptionInfo>> GetAllSubscriptionsOfTenantsAsync(Guid?[] tenantIds)
[UnitOfWork]
public async virtual Task<List<WebhookSubscriptionInfo>> GetAllSubscriptionsOfTenantsAsync(Guid?[] tenantIds)
{
throw new NotImplementedException();
using (CurrentTenant.Change(null))
{
var queryable = await SubscriptionRepository.GetQueryableAsync();
var subscriptions = await AsyncExecuter.ToListAsync(queryable.Where(x => tenantIds.Contains(x.TenantId)));
return subscriptions.Select(subscription => subscription.ToWebhookSubscriptionInfo()).ToList();
}
}
public Task<List<WebhookSubscriptionInfo>> GetAllSubscriptionsOfTenantsAsync(Guid?[] tenantIds, string webhookName)
[UnitOfWork]
public async virtual Task<List<WebhookSubscriptionInfo>> GetAllSubscriptionsOfTenantsAsync(Guid?[] tenantIds, string webhookName)
{
throw new NotImplementedException();
using (CurrentTenant.Change(null))
{
var queryable = await SubscriptionRepository.GetQueryableAsync();
var subscriptions = await AsyncExecuter.ToListAsync(
queryable.Where(x =>
x.IsActive &&
tenantIds.Contains(x.TenantId) &&
x.Webhooks.Contains("\"" + webhookName + "\"")));
return subscriptions.Select(subscription => subscription.ToWebhookSubscriptionInfo()).ToList();
}
}
public Task<WebhookSubscriptionInfo> GetAsync(Guid id)
[UnitOfWork]
public async virtual Task<WebhookSubscriptionInfo> GetAsync(Guid id)
{
throw new NotImplementedException();
using (CurrentTenant.Change(null))
{
var subscription = await SubscriptionRepository.GetAsync(id);
return subscription.ToWebhookSubscriptionInfo();
}
}
public Task InsertAsync(WebhookSubscriptionInfo webhookSubscription)
[UnitOfWork]
public async virtual Task InsertAsync(WebhookSubscriptionInfo webhookSubscription)
{
throw new NotImplementedException();
using (CurrentTenant.Change(null))
{
var subscription = new WebhookSubscription(
webhookSubscription.Id,
webhookSubscription.WebhookUri,
webhookSubscription.Secret,
JsonConvert.SerializeObject(webhookSubscription.Webhooks),
JsonConvert.SerializeObject(webhookSubscription.Headers),
webhookSubscription.TenantId);
await SubscriptionRepository.InsertAsync(subscription);
}
}
public Task<bool> IsSubscribedAsync(Guid? tenantId, string webhookName)
[UnitOfWork]
public async virtual Task<bool> IsSubscribedAsync(Guid? tenantId, string webhookName)
{
throw new NotImplementedException();
using (CurrentTenant.Change(null))
{
var queryable = await SubscriptionRepository.GetQueryableAsync();
return await AsyncExecuter.AnyAsync(
queryable.Where(x =>
x.TenantId == tenantId &&
x.IsActive &&
x.Webhooks.Contains("\"" + webhookName + "\"")));
}
}
public Task UpdateAsync(WebhookSubscriptionInfo webhookSubscription)
[UnitOfWork]
public async virtual Task UpdateAsync(WebhookSubscriptionInfo webhookSubscription)
{
throw new NotImplementedException();
using (CurrentTenant.Change(webhookSubscription.TenantId))
{
var subscription = await SubscriptionRepository.GetAsync(webhookSubscription.Id);
subscription.SetWebhookUri(webhookSubscription.WebhookUri);
subscription.SetWebhooks(webhookSubscription.ToSubscribedWebhooksString());
subscription.SetHeaders(webhookSubscription.ToWebhookHeadersString());
await SubscriptionRepository.UpdateAsync(subscription);
}
}
}

9
aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Domain/LINGYUN/Abp/WebhooksManagement/WebhooksManagementDomainMapperProfile.cs

@ -1,4 +1,8 @@
using AutoMapper;
using LINGYUN.Abp.Webhooks;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
namespace LINGYUN.Abp.WebhooksManagement;
@ -6,6 +10,11 @@ public class WebhooksManagementDomainMapperProfile : Profile
{
public WebhooksManagementDomainMapperProfile()
{
CreateMap<WebhookEventRecord, WebhookEventEto>();
CreateMap<WebhookSendRecord, WebhookSendAttemptEto>();
CreateMap<WebhookSubscription, WebhookSubscriptionEto>();
CreateMap<WebhookEventRecord, WebhookEvent>();
CreateMap<WebhookSendRecord, WebhookSendAttempt>();
}
}

29
aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Domain/LINGYUN/Abp/WebhooksManagement/WebhooksManagementDomainModule.cs

@ -1,8 +1,10 @@
using LINGYUN.Abp.Webhooks;
using LINGYUN.Abp.WebhooksManagement.ObjectExtending;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.AutoMapper;
using Volo.Abp.Domain.Entities.Events.Distributed;
using Volo.Abp.Modularity;
using Volo.Abp.ObjectExtending.Modularity;
using Volo.Abp.Threading;
namespace LINGYUN.Abp.WebhooksManagement;
@ -25,6 +27,13 @@ public class WebhooksManagementDomainModule : AbpModule
Configure<AbpDistributedEntityEventOptions>(options =>
{
options.EtoMappings.Add<WebhookEventRecord, WebhookEventEto>();
options.EtoMappings.Add<WebhookSendRecord, WebhookSendAttemptEto>();
options.EtoMappings.Add<WebhookSubscription, WebhookSubscriptionEto>();
options.AutoEventSelectors.Add<WebhookEventRecord>();
options.AutoEventSelectors.Add<WebhookSendRecord>();
options.AutoEventSelectors.Add<WebhookSubscription>();
});
}
@ -33,11 +42,21 @@ public class WebhooksManagementDomainModule : AbpModule
OneTimeRunner.Run(() =>
{
// 扩展实体配置
//ModuleExtensionConfigurationHelper.ApplyEntityConfigurationToEntity(
// WebhooksManagementModuleExtensionConsts.ModuleName,
// WebhooksManagementModuleExtensionConsts.EntityNames.Entity,
// typeof(Entity)
//);
ModuleExtensionConfigurationHelper.ApplyEntityConfigurationToEntity(
WebhooksManagementModuleExtensionConsts.ModuleName,
WebhooksManagementModuleExtensionConsts.EntityNames.WebhookEvent,
typeof(WebhookEventRecord)
);
ModuleExtensionConfigurationHelper.ApplyEntityConfigurationToEntity(
WebhooksManagementModuleExtensionConsts.ModuleName,
WebhooksManagementModuleExtensionConsts.EntityNames.WebhookSubscription,
typeof(WebhookSubscription)
);
ModuleExtensionConfigurationHelper.ApplyEntityConfigurationToEntity(
WebhooksManagementModuleExtensionConsts.ModuleName,
WebhooksManagementModuleExtensionConsts.EntityNames.WebhookSendAttempt,
typeof(WebhookSendRecord)
);
});
}
}

15
aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.EntityFrameworkCore/LINGYUN/Abp/WebhooksManagement/EntityFrameworkCore/EfCoreWebhookEventRecordRepository.cs

@ -0,0 +1,15 @@
using System;
using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;
namespace LINGYUN.Abp.WebhooksManagement.EntityFrameworkCore;
public class EfCoreWebhookEventRecordRepository :
EfCoreRepository<IWebhooksManagementDbContext, WebhookEventRecord, Guid>,
IWebhookEventRecordRepository
{
public EfCoreWebhookEventRecordRepository(IDbContextProvider<IWebhooksManagementDbContext> dbContextProvider)
: base(dbContextProvider)
{
}
}

58
aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.EntityFrameworkCore/LINGYUN/Abp/WebhooksManagement/EntityFrameworkCore/EfCoreWebhookSendRecordRepository.cs

@ -0,0 +1,58 @@
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;
namespace LINGYUN.Abp.WebhooksManagement.EntityFrameworkCore;
public class EfCoreWebhookSendRecordRepository :
EfCoreRepository<IWebhooksManagementDbContext, WebhookSendRecord, Guid>,
IWebhookSendRecordRepository
{
public EfCoreWebhookSendRecordRepository(
IDbContextProvider<IWebhooksManagementDbContext> dbContextProvider)
: base(dbContextProvider)
{
}
public async virtual Task<int> GetCountAsync(
WebhookSendRecordFilter filter,
CancellationToken cancellationToken = default)
{
return await ApplyFilter(await GetDbSetAsync(), filter)
.CountAsync(GetCancellationToken(cancellationToken));
}
public async virtual Task<List<WebhookSendRecord>> GetListAsync(
WebhookSendRecordFilter filter,
string sorting = "CreationTime",
int maxResultCount = 10,
int skipCount = 10,
bool includeDetails = false,
CancellationToken cancellationToken = default)
{
return await ApplyFilter((await GetDbSetAsync()).IncludeDetails(includeDetails), filter)
.OrderBy(sorting ?? $"{nameof(WebhookSendRecord.CreationTime)} DESC")
.PageBy(skipCount, maxResultCount)
.ToListAsync(GetCancellationToken(cancellationToken));
}
protected virtual IQueryable<WebhookSendRecord> ApplyFilter(
IQueryable<WebhookSendRecord> queryable,
WebhookSendRecordFilter filter)
{
return queryable
.WhereIf(filter.WebhookEventId.HasValue, x => x.WebhookEventId == filter.WebhookEventId)
.WhereIf(filter.SubscriptionId.HasValue, x => x.WebhookSubscriptionId == filter.SubscriptionId)
.WhereIf(filter.ResponseStatusCode.HasValue, x => x.ResponseStatusCode == filter.ResponseStatusCode)
.WhereIf(filter.BeginCreationTime.HasValue, x => x.CreationTime.CompareTo(filter.BeginCreationTime) >= 0)
.WhereIf(filter.EndCreationTime.HasValue, x => x.CreationTime.CompareTo(filter.EndCreationTime) <= 0)
.WhereIf(!filter.Filter.IsNullOrWhiteSpace(), x => x.Response.Contains(filter.Filter));
}
}

16
aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.EntityFrameworkCore/LINGYUN/Abp/WebhooksManagement/EntityFrameworkCore/EfCoreWebhookSubscriptionRepository.cs

@ -0,0 +1,16 @@
using System;
using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;
namespace LINGYUN.Abp.WebhooksManagement.EntityFrameworkCore;
public class EfCoreWebhookSubscriptionRepository :
EfCoreRepository<IWebhooksManagementDbContext, WebhookSubscription, Guid>,
IWebhookSubscriptionRepository
{
public EfCoreWebhookSubscriptionRepository(
IDbContextProvider<IWebhooksManagementDbContext> dbContextProvider)
: base(dbContextProvider)
{
}
}

55
aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.EntityFrameworkCore/LINGYUN/Abp/WebhooksManagement/EntityFrameworkCore/WebhooksManagementDbContextModelCreatingExtensions.cs

@ -1,6 +1,7 @@
using Microsoft.EntityFrameworkCore;
using System;
using Volo.Abp;
using Volo.Abp.EntityFrameworkCore.Modeling;
namespace LINGYUN.Abp.WebhooksManagement.EntityFrameworkCore;
@ -17,5 +18,59 @@ public static class WebhooksManagementDbContextModelCreatingExtensions
WebhooksManagementDbProperties.DbSchema
);
optionsAction?.Invoke(options);
builder.Entity<WebhookEventRecord>(b =>
{
b.ToTable(options.TablePrefix + "WebhookEvents", options.Schema);
b.Property(p => p.WebhookName)
.IsRequired()
.HasColumnName(nameof(WebhookEventRecord.WebhookName))
.HasMaxLength(WebhookEventRecordConsts.MaxWebhookNameLength);
b.Property(p => p.Data)
.HasColumnName(nameof(WebhookEventRecord.Data))
.HasMaxLength(WebhookEventRecordConsts.MaxDataLength);
b.ConfigureByConvention();
});
builder.Entity<WebhookSendRecord>(b =>
{
b.ToTable(options.TablePrefix + "WebhookSendAttempts", options.Schema);
b.Property(p => p.Response)
.HasColumnName(nameof(WebhookSendRecord.Response))
.HasMaxLength(WebhookSendRecordConsts.MaxResponseLength);
b.ConfigureByConvention();
b.HasOne(p => p.WebhookEvent)
.WithOne()
.HasForeignKey<WebhookSendRecord>(fk => fk.WebhookEventId)
.HasPrincipalKey<WebhookEventRecord>(pk => pk.Id );
});
builder.Entity<WebhookSubscription>(b =>
{
b.ToTable(options.TablePrefix + "WebhookSubscriptions", options.Schema);
b.Property(p => p.WebhookUri)
.IsRequired()
.HasColumnName(nameof(WebhookSubscription.WebhookUri))
.HasMaxLength(WebhookSubscriptionConsts.MaxWebhookUriLength);
b.Property(p => p.Secret)
.IsRequired()
.HasColumnName(nameof(WebhookSubscription.Secret))
.HasMaxLength(WebhookSubscriptionConsts.MaxSecretLength);
b.Property(p => p.Webhooks)
.HasColumnName(nameof(WebhookSubscription.Webhooks))
.HasMaxLength(WebhookSubscriptionConsts.MaxWebhooksLength);
b.Property(p => p.Headers)
.HasColumnName(nameof(WebhookSubscription.Headers))
.HasMaxLength(WebhookSubscriptionConsts.MaxHeadersLength);
b.ConfigureByConvention();
});
}
}

15
aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.EntityFrameworkCore/LINGYUN/Abp/WebhooksManagement/EntityFrameworkCore/WebhooksManagementEfCoreQueryableExtensions.cs

@ -1,6 +1,19 @@
namespace LINGYUN.Abp.WebhooksManagement.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using System.Linq;
namespace LINGYUN.Abp.WebhooksManagement.EntityFrameworkCore;
public static class WebhooksManagementEfCoreQueryableExtensions
{
// 在此聚合仓储服务的扩展方法
public static IQueryable<WebhookSendRecord> IncludeDetails(this IQueryable<WebhookSendRecord> queryable, bool include = true)
{
if (!include)
{
return queryable;
}
return queryable
.Include(x => x.WebhookEvent);
}
}

4
aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.EntityFrameworkCore/LINGYUN/Abp/WebhooksManagement/EntityFrameworkCore/WebhooksManagementEntityFrameworkCoreModule.cs

@ -13,6 +13,10 @@ public class WebhooksManagementEntityFrameworkCoreModule : AbpModule
{
context.Services.AddAbpDbContext<WebhooksManagementDbContext>(options =>
{
options.AddRepository<WebhookSendRecord, EfCoreWebhookSendRecordRepository>();
options.AddRepository<WebhookEventRecord, EfCoreWebhookEventRecordRepository>();
options.AddRepository<WebhookSubscription, EfCoreWebhookSubscriptionRepository>();
options.AddDefaultRepositories<IWebhooksManagementDbContext>();
});
}

2
aspnet-core/services/LY.MicroService.WebhooksManagement.HttpApi.Host/Controllers/HomeController.cs

@ -1,7 +1,7 @@
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc;
namespace LY..WebhooksManagement.Controllers;
namespace LY.MicroService.WebhooksManagement.Controllers;
public class HomeController : AbpController
{

2
aspnet-core/services/LY.MicroService.WebhooksManagement.HttpApi.Host/DataSeeder/WebhooksManagementDataSeederWorker.cs

@ -3,7 +3,7 @@ using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.Data;
namespace LY..WebhooksManagement.DataSeeder;
namespace LY.MicroService.WebhooksManagement.DataSeeder;
public class WebhooksManagementDataSeederWorker : BackgroundService
{

5
aspnet-core/services/LY.MicroService.WebhooksManagement.HttpApi.Host/EntityFrameworkCore/WebhooksManagementMigrationsDbContext.cs

@ -1,7 +1,8 @@
using Microsoft.EntityFrameworkCore;
using LINGYUN.Abp.WebhooksManagement.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;
namespace LY..WebhooksManagement.EntityFrameworkCore;
namespace LY.MicroService.WebhooksManagement.EntityFrameworkCore;
public class WebhooksManagementMigrationsDbContext : AbpDbContext<WebhooksManagementMigrationsDbContext>
{

2
aspnet-core/services/LY.MicroService.WebhooksManagement.HttpApi.Host/EntityFrameworkCore/WebhooksManagementMigrationsDbContextFactory.cs

@ -3,7 +3,7 @@ using Microsoft.EntityFrameworkCore.Design;
using Microsoft.Extensions.Configuration;
using System.IO;
namespace LY..WebhooksManagement.EntityFrameworkCore;
namespace LY.MicroService.WebhooksManagement.EntityFrameworkCore;
public class WebhooksManagementMigrationsDbContextFactory : IDesignTimeDbContextFactory<WebhooksManagementMigrationsDbContext>
{

10
aspnet-core/services/LY.MicroService.WebhooksManagement.HttpApi.Host/EventBus/Handlers/TenantSynchronizer.cs

@ -1,6 +1,6 @@
using LY..WebhooksManagement.EntityFrameworkCore;
using LINGYUN.Abp.Data.DbMigrator;
using LINGYUN.Abp.Data.DbMigrator;
using LINGYUN.Abp.MultiTenancy;
using LINGYUN.Abp.WebhooksManagement.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using System.Threading.Tasks;
@ -10,7 +10,7 @@ using Volo.Abp.EventBus.Distributed;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Uow;
namespace LY..WebhooksManagement.EventBus.Handlers;
namespace LY.MicroService.WebhooksManagement.EventBus.Handlers;
public class TenantSynchronizer :
IDistributedEventHandler<CreateEventData>,
@ -49,7 +49,7 @@ public class TenantSynchronizer :
{
using (CurrentTenant.Change(eventData.Id, eventData.Name))
{
Logger.LogInformation("Migrating the new tenant database with LY..WebhooksManagement...");
Logger.LogInformation("Migrating the new tenant database with WebhooksManagement...");
// 迁移租户数据
await DbSchemaMigrator.MigrateAsync<WebhooksManagementDbContext>(
(connectionString, builder) =>
@ -58,7 +58,7 @@ public class TenantSynchronizer :
return new WebhooksManagementDbContext(builder.Options);
});
Logger.LogInformation("Migrated the new tenant database with LY..WebhooksManagement...");
Logger.LogInformation("Migrated the new tenant database with WebhooksManagement...");
await DataSeeder.SeedAsync(new DataSeedContext(eventData.Id));

9
aspnet-core/services/LY.MicroService.WebhooksManagement.HttpApi.Host/LY.MicroService.WebhooksManagement.HttpApi.Host.csproj

@ -2,7 +2,7 @@
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<RootNamespace>LY..WebhooksManagement</RootNamespace>
<RootNamespace>LY.MicroService.WebhooksManagement</RootNamespace>
</PropertyGroup>
<ItemGroup>
@ -57,10 +57,9 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\LY..WebhooksManagement.Application\LY..WebhooksManagement.Application.csproj" />
<ProjectReference Include="..\..\src\LY..WebhooksManagement.EntityFrameworkCore\LY..WebhooksManagement.EntityFrameworkCore.csproj" />
<ProjectReference Include="..\..\src\LY..WebhooksManagement.HttpApi\LY..WebhooksManagement.HttpApi.csproj" />
<ProjectReference Include="..\..\src\LY..WebhooksManagement.SettingManagement\LY..WebhooksManagement.SettingManagement.csproj" />
<ProjectReference Include="..\..\modules\webhooks\LINGYUN.Abp.WebhooksManagement.Application\LINGYUN.Abp.WebhooksManagement.Application.csproj" />
<ProjectReference Include="..\..\modules\webhooks\LINGYUN.Abp.WebhooksManagement.EntityFrameworkCore\LINGYUN.Abp.WebhooksManagement.EntityFrameworkCore.csproj" />
<ProjectReference Include="..\..\modules\webhooks\LINGYUN.Abp.WebhooksManagement.HttpApi\LINGYUN.Abp.WebhooksManagement.HttpApi.csproj" />
</ItemGroup>
</Project>

2
aspnet-core/services/LY.MicroService.WebhooksManagement.HttpApi.Host/Program.cs

@ -9,7 +9,7 @@ using System.Threading.Tasks;
using Volo.Abp.IO;
using Volo.Abp.Modularity.PlugIns;
namespace LY..WebhooksManagement;
namespace LY.MicroService.WebhooksManagement;
public class Program
{

9
aspnet-core/services/LY.MicroService.WebhooksManagement.HttpApi.Host/Properties/launchSettings.json

@ -14,15 +14,8 @@
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:57264",
"applicationUrl": "http://127.0.0.1:30045",
"dotnetRunMessages": "true"
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": false,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

2
aspnet-core/services/LY.MicroService.WebhooksManagement.HttpApi.Host/TenantHeaderParamter.cs

@ -4,7 +4,7 @@ using Swashbuckle.AspNetCore.SwaggerGen;
using System.Collections.Generic;
using Volo.Abp.MultiTenancy;
namespace LY..WebhooksManagement;
namespace LY.MicroService.WebhooksManagement;
public class TenantHeaderParamter : IOperationFilter
{

8
aspnet-core/services/LY.MicroService.WebhooksManagement.HttpApi.Host/WebhooksManagementHttpApiHostModule.Configure.cs

@ -31,7 +31,7 @@ using Volo.Abp.MultiTenancy;
using Volo.Abp.Threading;
using Volo.Abp.VirtualFileSystem;
namespace LY..WebhooksManagement;
namespace LY.MicroService.WebhooksManagement;
public partial class WebhooksManagementHttpApiHostModule
{
@ -53,7 +53,7 @@ public partial class WebhooksManagementHttpApiHostModule
PreConfigure<AbpSerilogEnrichersUniqueIdOptions>(options =>
{
// 以开放端口区别
options.SnowflakeIdOptions.WorkerId = 5000;
options.SnowflakeIdOptions.WorkerId = 30045;
options.SnowflakeIdOptions.WorkerIdBits = 5;
options.SnowflakeIdOptions.DatacenterId = 1;
});
@ -160,7 +160,7 @@ public partial class WebhooksManagementHttpApiHostModule
{
Configure<AbpAuditingOptions>(options =>
{
options.ApplicationName = "WebhooksManagement";
options.ApplicationName = ApplicationName;
// 是否启用实体变更记录
var entitiesChangedConfig = configuration.GetSection("App:TrackingEntitiesChanged");
if (entitiesChangedConfig.Exists() && entitiesChangedConfig.Get<bool>())
@ -196,7 +196,7 @@ public partial class WebhooksManagementHttpApiHostModule
{
Configure<AbpVirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<WebhooksManagementHttpApiHostModule>("LY..WebhooksManagement");
options.FileSets.AddEmbedded<WebhooksManagementHttpApiHostModule>("LY.MicroService.WebhooksManagement");
});
}

4
aspnet-core/services/LY.MicroService.WebhooksManagement.HttpApi.Host/WebhooksManagementHttpApiHostModule.DataSeeder.cs

@ -1,7 +1,7 @@
using Microsoft.Extensions.DependencyInjection;
using LY..WebhooksManagement.DataSeeder;
using LY.MicroService.WebhooksManagement.DataSeeder;
namespace LY..WebhooksManagement;
namespace LY.MicroService.WebhooksManagement;
public partial class WebhooksManagementHttpApiHostModule
{

11
aspnet-core/services/LY.MicroService.WebhooksManagement.HttpApi.Host/WebhooksManagementHttpApiHostModule.cs

@ -1,4 +1,5 @@
using LINGYUN.Abp.AspNetCore.Mvc.Wrapper;
using DotNetCore.CAP;
using LINGYUN.Abp.AspNetCore.Mvc.Wrapper;
using LINGYUN.Abp.AuditLogging.Elasticsearch;
using LINGYUN.Abp.EventBus.CAP;
using LINGYUN.Abp.ExceptionHandling.Emailing;
@ -6,12 +7,12 @@ using LINGYUN.Abp.LocalizationManagement.EntityFrameworkCore;
using LINGYUN.Abp.Saas.EntityFrameworkCore;
using LINGYUN.Abp.Serilog.Enrichers.Application;
using LINGYUN.Abp.Serilog.Enrichers.UniqueId;
using LINGYUN.Abp.WebhooksManagement;
using LINGYUN.Abp.WebhooksManagement.EntityFrameworkCore;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using LY..WebhooksManagement.EntityFrameworkCore;
using LY..WebhooksManagement.SettingManagement;
using Volo.Abp;
using Volo.Abp.AspNetCore.Authentication.JwtBearer;
using Volo.Abp.AspNetCore.MultiTenancy;
@ -27,7 +28,7 @@ using Volo.Abp.PermissionManagement.EntityFrameworkCore;
using Volo.Abp.SettingManagement.EntityFrameworkCore;
using Volo.Abp.Swashbuckle;
namespace LY.WebhooksManagement;
namespace LY.MicroService.WebhooksManagement;
[DependsOn(
typeof(AbpSerilogEnrichersApplicationModule),
@ -37,7 +38,6 @@ namespace LY.WebhooksManagement;
typeof(WebhooksManagementApplicationModule),
typeof(WebhooksManagementHttpApiModule),
typeof(WebhooksManagementEntityFrameworkCoreModule),
typeof(WebhooksManagementSettingManagementModule),
typeof(AbpEntityFrameworkCoreMySQLModule),
typeof(AbpAspNetCoreAuthenticationJwtBearerModule),
typeof(AbpEmailingExceptionHandlingModule),
@ -101,6 +101,7 @@ public partial class WebhooksManagementHttpApiHostModule : AbpModule
app.UseMultiTenancy();
app.UseMapRequestLocalization();
app.UseAuthorization();
app.UseCapDashboard();
app.UseSwagger();
app.UseAbpSwaggerUI(options =>
{

Loading…
Cancel
Save