diff --git a/docs/en/Migration-Guides/Abp-5_0-Angular.md b/docs/en/Migration-Guides/Abp-5_0-Angular.md index 6cdb7af7c9..1188e68556 100644 --- a/docs/en/Migration-Guides/Abp-5_0-Angular.md +++ b/docs/en/Migration-Guides/Abp-5_0-Angular.md @@ -85,7 +85,7 @@ Following proxies have been affected: ### ChartComponent -`ChartComponent` has moved from `@abp/ng.theme.shared` to `@abp/ng.components/chart.js`. To use the component, you need to import the `ChartModule` to your module as follows: +[`ChartComponent`](../UI/Angular/Chart-Component.md) has moved from `@abp/ng.theme.shared` to `@abp/ng.components/chart.js`. To use the component, you need to import the `ChartModule` to your module as follows: ```ts import { ChartModule } from '@abp/ng.components/chart.js'; diff --git a/docs/en/UI/Angular/Chart-Component.md b/docs/en/UI/Angular/Chart-Component.md new file mode 100644 index 0000000000..a1cea80b52 --- /dev/null +++ b/docs/en/UI/Angular/Chart-Component.md @@ -0,0 +1,249 @@ +# Chart Component + +ABP Chart component exposed by `@abp/ng.components/chart.js` is based on [`charts.js`](https://www.chartjs.org/) v3+. You don't need to install the `chart.js` package. Since the `@abp/ng.components` is dependent on the `chart.js`, the package is already installed in your project. + +> Chart component loads `chart.js` script lazy. So it does not increase the bundle size. + +## How to Use + +First of all, need to import the `ChartModule` to your feature module as follows: + +```ts +// your-feature.module.ts + +import { ChartModule } from '@abp/ng.components/chart.js'; +import { ChartDemoComponent } from './chart-demo.component'; + +@NgModule({ + imports: [ + ChartModule, + // ... + ], + declarations: [ChartDemoComponent], + // ... +}) +export class YourFeatureModule {} +``` + +Then, `abp-chart` component can be used. See an example: + +```ts +// chart-demo.component.ts + +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-chart-demo', + template: ` `, +}) +export class ChartDemoComponent { + data = { + labels: ['Data 1', 'Data 2', 'Data 3'], + datasets: [ + { + label: 'Dataset 1', + data: [40, 15, 45], + backgroundColor: ['#ff7675', '#fdcb6e', '#0984e3'], + }, + ], + }; +} +``` + +> **Important Note**: Changing the chart data without creating a new data instance does not trigger change detection. In order to chart to redraw itself, a new data object needs to be created. + +See the result: + +![pie-chart](./images/pie-chart.png) + +## Examples + +### Doughnut + +```ts +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-chart-demo', + template: ` + + `, +}) +export class ChartDemoComponent { + data = { + labels: ['Data 1', 'Data 2', 'Data 3'], + datasets: [ + { + label: 'Dataset 1', + data: [40, 15, 45], + backgroundColor: ['#a0e6c3', '#f0ea4c', '#5b9dc3'], + }, + ], + }; + + options = { + plugins: { + title: { + display: true, + text: 'Doughnut Chart', + fontSize: 16, + }, + legend: { + position: 'bottom', + }, + }, + }; +} +``` + +Result: + +![Doughnut Chart](./images/doughnut-chart.png) + +### Bar + +```ts +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-chart-demo', + template: ` + + `, +}) +export class ChartDemoComponent { + data = { + labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'], + datasets: [ + { + label: 'First dataset', + backgroundColor: '#42A5F5', + data: [65, 59, 80, 81, 56, 55, 40], + }, + { + label: 'Second dataset', + backgroundColor: '#FFA726', + data: [28, 48, 40, 19, 86, 27, 90], + }, + ], + }; +} +``` + +Result: + +![Bar Chart](./images/bar-chart.png) + +### Radar + +```ts +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-chart-demo', + template: ` + + + + `, +}) +export class ChartDemoComponent { + data = { + labels: [ + 'January', + 'February', + 'March', + 'April', + 'May', + 'June', + 'July', + 'August', + 'September', + 'October', + 'November', + 'December', + ], + datasets: [ + { + label: 'Dataset 1', + backgroundColor: 'rgba(179,181,198,0.2)', + borderColor: 'rgba(179,181,198,1)', + data: [65, 59, 90, 81, 56, 55, 40, 35, 82, 51, 62, 95], + }, + { + label: 'Dataset 2', + backgroundColor: 'rgba(255,99,132,0.2)', + borderColor: 'rgba(255,99,132,1)', + data: [28, 48, 40, 58, 96, 27, 100, 44, 85, 77, 71, 39], + }, + ], + }; + + addDataset() { + this.data = { + ...this.data, + datasets: [ + ...this.data.datasets, + { + label: 'Dataset 3', + backgroundColor: 'rgba(54,162,235,0.2)', + borderColor: 'rgba(54, 162, 235, 1)', + data: [90, 95, 98, 91, 99, 96, 89, 95, 98, 93, 92, 90], + }, + ], + }; + } +} +``` + +Result: + +![Bar Chart](./images/radar-chart.gif) + +See the [`chart.js` samples](https://www.chartjs.org/docs/latest/samples) for more examples. + +## API + +### `abp-chart` + +#### Properties + +| Name | Description | Type | Default | +| --------------- | ---------------------------------------------------------------- | ----------------------- | ------- | +| `[type]` | Type of the chart. | `string` | null | +| `[data]` | Chart data to display | `any` | null | +| `[options]` | Chart options to customize | `any` | null | +| `[plugins]` | Chart plugins to customize behaviour | `any` | null | +| `[width]` | Witdh of the chart | `string` | null | +| `[height]` | Height of the chart | `string` | null | +| `[responsive]` | Whether the chart is responsive | `boolean` | true | +| `(dataSelect)` | A callback that executes when an element on the chart is clicked | `EventEmitter` | - | +| `(initialized)` | A callback that executes when the chart is initialized | `EventEmitter` | - | + +#### Methods + +| Name | Description | Parameters | +| ---------------- | ------------------------------------------------------------------- | ---------- | +| `refresh` | Redraws the chart | - | +| `reinit` | Destroys the chart then creates it again | - | +| `getBase64Image` | Returns a base 64 encoded string of the chart in it's current state | - | +| `generateLegend` | Returns an HTML string of a legend for the chart | - | +| `getCanvas` | Returns the canvas HTML element | - | diff --git a/docs/en/UI/Angular/Permission-Management.md b/docs/en/UI/Angular/Permission-Management.md index b8125bb2a3..dd373d6274 100644 --- a/docs/en/UI/Angular/Permission-Management.md +++ b/docs/en/UI/Angular/Permission-Management.md @@ -4,8 +4,6 @@ A permission is a simple policy that is granted or prohibited for a particular u You can get permission of authenticated user using `getGrantedPolicy` or `getGrantedPolicy$` method of `PermissionService`. -> ConfigState's getGrantedPolicy selector and ConfigStateService's getGrantedPolicy method deprecated. Use permission service's `getGrantedPolicy$` or `getGrantedPolicy`methods instead - You can get permission as boolean value: ```js @@ -77,4 +75,46 @@ const routes: Routes = [ ]; ``` -Granted Policies are stored in the `auth` property of `ConfigState`. \ No newline at end of file +## Customization + +In some cases, a custom permission management may be needed. All you need to do is to replace the service with your own. Here is how to achieve this: + +- First, create a service of your own. Let's call it `CustomPermissionService` and extend `PermissionService` from `@abp/ng.core` as follows: + +```js +import { ConfigStateService, PermissionService } from '@abp/ng.core'; +import { Injectable } from '@angular/core'; + +@Injectable({ + providedIn: 'root', +}) +export class CustomPermissionService extends PermissionService { + constructor(configStateService: ConfigStateService) { + super(configStateService); + } + + // This is an example to show how to override the methods + getGrantedPolicy$(key: string) { + return super.getGrantedPolicy$(key); + } +} +``` + +- Then, in `app.module.ts`, provide this service as follows: + +```js +@NgModule({ + // ... + providers: [ + // ... + { + provide: PermissionService, + useExisting: CustomPermissionService, + }, + ], + // ... +}) +export class AppModule {} +``` + +That's it. Now, when a directive/guard asks for `PermissionService` from angular, it will inject your service. diff --git a/docs/en/UI/Angular/images/bar-chart.png b/docs/en/UI/Angular/images/bar-chart.png new file mode 100644 index 0000000000..58e4b85d03 Binary files /dev/null and b/docs/en/UI/Angular/images/bar-chart.png differ diff --git a/docs/en/UI/Angular/images/doughnut-chart.png b/docs/en/UI/Angular/images/doughnut-chart.png new file mode 100644 index 0000000000..8249b30164 Binary files /dev/null and b/docs/en/UI/Angular/images/doughnut-chart.png differ diff --git a/docs/en/UI/Angular/images/pie-chart.png b/docs/en/UI/Angular/images/pie-chart.png new file mode 100644 index 0000000000..c4a9c86750 Binary files /dev/null and b/docs/en/UI/Angular/images/pie-chart.png differ diff --git a/docs/en/UI/Angular/images/radar-chart.gif b/docs/en/UI/Angular/images/radar-chart.gif new file mode 100644 index 0000000000..8f8eae042b Binary files /dev/null and b/docs/en/UI/Angular/images/radar-chart.gif differ diff --git a/docs/en/docs-nav.json b/docs/en/docs-nav.json index 398da988e4..76e3f70d1c 100644 --- a/docs/en/docs-nav.json +++ b/docs/en/docs-nav.json @@ -1079,6 +1079,10 @@ { "text": "Page", "path": "UI/Angular/Page-Component.md" + }, + { + "text": "Chart", + "path": "UI/Angular/Chart-Component.md" } ] } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Pages/Abp/MultiTenancy/AbpTenantController.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Pages/Abp/MultiTenancy/AbpTenantController.cs index 712a768137..c0dfeecfc1 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Pages/Abp/MultiTenancy/AbpTenantController.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Pages/Abp/MultiTenancy/AbpTenantController.cs @@ -2,6 +2,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Volo.Abp; +using Volo.Abp.AspNetCore; using Volo.Abp.AspNetCore.Mvc; using Volo.Abp.AspNetCore.Mvc.MultiTenancy; @@ -10,7 +11,7 @@ namespace Pages.Abp.MultiTenancy [Area("abp")] [RemoteService(Name = "abp")] [Route("api/abp/multi-tenancy")] - public class AbpTenantController : AbpController, IAbpTenantAppService + public class AbpTenantController : AbpControllerBase, IAbpTenantAppService { private readonly IAbpTenantAppService _abpTenantAppService; diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpControllerBase.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpControllerBase.cs new file mode 100644 index 0000000000..20ad62991f --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpControllerBase.cs @@ -0,0 +1,105 @@ +using System; +using System.Collections.Generic; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Localization; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using Volo.Abp.Aspects; +using Volo.Abp.AspNetCore.Mvc.Validation; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Features; +using Volo.Abp.Guids; +using Volo.Abp.Localization; +using Volo.Abp.MultiTenancy; +using Volo.Abp.ObjectMapping; +using Volo.Abp.Timing; +using Volo.Abp.Uow; +using Volo.Abp.Users; + +namespace Volo.Abp.AspNetCore.Mvc +{ + public abstract class AbpControllerBase : ControllerBase, IAvoidDuplicateCrossCuttingConcerns + { + public IAbpLazyServiceProvider LazyServiceProvider { get; set; } + + protected IUnitOfWorkManager UnitOfWorkManager => LazyServiceProvider.LazyGetRequiredService(); + + protected Type ObjectMapperContext { get; set; } + protected IObjectMapper ObjectMapper => LazyServiceProvider.LazyGetService(provider => + ObjectMapperContext == null + ? provider.GetRequiredService() + : (IObjectMapper) provider.GetRequiredService(typeof(IObjectMapper<>).MakeGenericType(ObjectMapperContext))); + + protected IGuidGenerator GuidGenerator => LazyServiceProvider.LazyGetService(SimpleGuidGenerator.Instance); + + protected ILoggerFactory LoggerFactory => LazyServiceProvider.LazyGetRequiredService(); + + protected ILogger Logger => LazyServiceProvider.LazyGetService(provider => LoggerFactory?.CreateLogger(GetType().FullName) ?? NullLogger.Instance); + + protected ICurrentUser CurrentUser => LazyServiceProvider.LazyGetRequiredService(); + + protected ICurrentTenant CurrentTenant => LazyServiceProvider.LazyGetRequiredService(); + + protected IAuthorizationService AuthorizationService => LazyServiceProvider.LazyGetRequiredService(); + + protected IUnitOfWork CurrentUnitOfWork => UnitOfWorkManager?.Current; + + protected IClock Clock => LazyServiceProvider.LazyGetRequiredService(); + + protected IModelStateValidator ModelValidator => LazyServiceProvider.LazyGetRequiredService(); + + protected IFeatureChecker FeatureChecker => LazyServiceProvider.LazyGetRequiredService(); + + protected IStringLocalizerFactory StringLocalizerFactory => LazyServiceProvider.LazyGetRequiredService(); + + protected IStringLocalizer L + { + get + { + if (_localizer == null) + { + _localizer = CreateLocalizer(); + } + + return _localizer; + } + } + private IStringLocalizer _localizer; + + protected Type LocalizationResource + { + get => _localizationResource; + set + { + _localizationResource = value; + _localizer = null; + } + } + private Type _localizationResource = typeof(DefaultResource); + + public List AppliedCrossCuttingConcerns { get; } = new List(); + + protected virtual IStringLocalizer CreateLocalizer() + { + if (LocalizationResource != null) + { + return StringLocalizerFactory.Create(LocalizationResource); + } + + var localizer = StringLocalizerFactory.CreateDefaultOrNull(); + if (localizer == null) + { + throw new AbpException($"Set {nameof(LocalizationResource)} or define the default localization resource type (by configuring the {nameof(AbpLocalizationOptions)}.{nameof(AbpLocalizationOptions.DefaultResourceType)}) to be able to use the {nameof(L)} object!"); + } + + return localizer; + } + + protected virtual void ValidateModel() + { + ModelValidator?.Validate(ModelState); + } + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationController.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationController.cs index 89282110b9..4947008411 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationController.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationController.cs @@ -7,7 +7,7 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations [Area("abp")] [RemoteService(Name = "abp")] [Route("api/abp/application-configuration")] - public class AbpApplicationConfigurationController : AbpController, IAbpApplicationConfigurationAppService + public class AbpApplicationConfigurationController : AbpControllerBase, IAbpApplicationConfigurationAppService { private readonly IAbpApplicationConfigurationAppService _applicationConfigurationAppService; private readonly IAbpAntiForgeryManager _antiForgeryManager; diff --git a/framework/src/Volo.Abp.EventBus.Kafka/Volo/Abp/EventBus/Kafka/KafkaDistributedEventBus.cs b/framework/src/Volo.Abp.EventBus.Kafka/Volo/Abp/EventBus/Kafka/KafkaDistributedEventBus.cs index b747a858d2..ad857ad967 100644 --- a/framework/src/Volo.Abp.EventBus.Kafka/Volo/Abp/EventBus/Kafka/KafkaDistributedEventBus.cs +++ b/framework/src/Volo.Abp.EventBus.Kafka/Volo/Abp/EventBus/Kafka/KafkaDistributedEventBus.cs @@ -6,7 +6,6 @@ using System.Threading.Tasks; using Confluent.Kafka; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; -using Volo.Abp.Data; using Volo.Abp.DependencyInjection; using Volo.Abp.EventBus.Distributed; using Volo.Abp.Guids; @@ -22,7 +21,6 @@ namespace Volo.Abp.EventBus.Kafka [ExposeServices(typeof(IDistributedEventBus), typeof(KafkaDistributedEventBus))] public class KafkaDistributedEventBus : DistributedEventBusBase, ISingletonDependency { - protected AbpEventBusOptions AbpEventBusOptions { get; } protected AbpKafkaEventBusOptions AbpKafkaEventBusOptions { get; } protected IKafkaMessageConsumerFactory MessageConsumerFactory { get; } protected IKafkaSerializer Serializer { get; } @@ -30,7 +28,6 @@ namespace Volo.Abp.EventBus.Kafka protected ConcurrentDictionary> HandlerFactories { get; } protected ConcurrentDictionary EventTypes { get; } protected IKafkaMessageConsumer Consumer { get; private set; } - protected string DeadLetterTopicName { get; } public KafkaDistributedEventBus( IServiceScopeFactory serviceScopeFactory, @@ -41,26 +38,20 @@ namespace Volo.Abp.EventBus.Kafka IOptions abpDistributedEventBusOptions, IKafkaSerializer serializer, IProducerPool producerPool, - IEventErrorHandler errorHandler, - IOptions abpEventBusOptions, IGuidGenerator guidGenerator, IClock clock) : base( serviceScopeFactory, currentTenant, unitOfWorkManager, - errorHandler, abpDistributedEventBusOptions, guidGenerator, clock) { AbpKafkaEventBusOptions = abpKafkaEventBusOptions.Value; - AbpEventBusOptions = abpEventBusOptions.Value; MessageConsumerFactory = messageConsumerFactory; Serializer = serializer; ProducerPool = producerPool; - DeadLetterTopicName = - AbpEventBusOptions.DeadLetterName ?? AbpKafkaEventBusOptions.TopicName + "_dead_letter"; HandlerFactories = new ConcurrentDictionary>(); EventTypes = new ConcurrentDictionary(); @@ -70,7 +61,6 @@ namespace Volo.Abp.EventBus.Kafka { Consumer = MessageConsumerFactory.Create( AbpKafkaEventBusOptions.TopicName, - DeadLetterTopicName, AbpKafkaEventBusOptions.GroupId, AbpKafkaEventBusOptions.ConnectionName); Consumer.OnMessageReceived(ProcessEventAsync); @@ -88,12 +78,12 @@ namespace Volo.Abp.EventBus.Kafka } string messageId = null; - + if (message.Headers.TryGetLastBytes("messageId", out var messageIdBytes)) { messageId = System.Text.Encoding.UTF8.GetString(messageIdBytes); } - + if (await AddToInboxAsync(messageId, eventName, eventType, message.Value)) { return; @@ -101,18 +91,7 @@ namespace Volo.Abp.EventBus.Kafka var eventData = Serializer.Deserialize(message.Value, eventType); - await TriggerHandlersAsync(eventType, eventData, errorContext => - { - var retryAttempt = 0; - if (message.Headers.TryGetLastBytes(EventErrorHandlerBase.RetryAttemptKey, out var retryAttemptBytes)) - { - retryAttempt = Serializer.Deserialize(retryAttemptBytes); - } - - errorContext.EventData = Serializer.Deserialize(message.Value, eventType); - errorContext.SetProperty(EventErrorHandlerBase.HeadersKey, message.Headers); - errorContext.SetProperty(EventErrorHandlerBase.RetryAttemptKey, retryAttempt); - }); + await TriggerHandlersAsync(eventType, eventData); } public override IDisposable Subscribe(Type eventType, IEventHandlerFactory factory) @@ -226,7 +205,7 @@ namespace Volo.Abp.EventBus.Kafka { return; } - + var eventData = Serializer.Deserialize(incomingEvent.EventData, eventType); var exceptions = new List(); await TriggerHandlersAsync(eventType, eventData, exceptions, inboxConfig); @@ -252,11 +231,6 @@ namespace Volo.Abp.EventBus.Kafka ); } - public virtual async Task PublishToDeadLetterAsync(Type eventType, object eventData, Headers headers, Dictionary headersArguments) - { - await PublishAsync(DeadLetterTopicName, eventType, eventData, headers, headersArguments); - } - private Task PublishAsync(string topicName, Type eventType, object eventData, Headers headers, Dictionary headersArguments) { var eventName = EventNameAttribute.GetNameOrDefault(eventType); @@ -264,7 +238,7 @@ namespace Volo.Abp.EventBus.Kafka return PublishAsync(topicName, eventName, body, headers, headersArguments); } - + private async Task PublishAsync(string topicName, string eventName, byte[] body, Headers headers, Dictionary headersArguments) { var producer = ProducerPool.Get(AbpKafkaEventBusOptions.ConnectionName); diff --git a/framework/src/Volo.Abp.EventBus.Kafka/Volo/Abp/EventBus/Kafka/KafkaEventErrorHandler.cs b/framework/src/Volo.Abp.EventBus.Kafka/Volo/Abp/EventBus/Kafka/KafkaEventErrorHandler.cs deleted file mode 100644 index aee21f75a9..0000000000 --- a/framework/src/Volo.Abp.EventBus.Kafka/Volo/Abp/EventBus/Kafka/KafkaEventErrorHandler.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Confluent.Kafka; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Logging.Abstractions; -using Microsoft.Extensions.Options; -using Volo.Abp.Data; -using Volo.Abp.DependencyInjection; - -namespace Volo.Abp.EventBus.Kafka -{ - public class KafkaEventErrorHandler : EventErrorHandlerBase, ISingletonDependency - { - protected ILogger Logger { get; set; } - - public KafkaEventErrorHandler( - IOptions options) : base(options) - { - Logger = NullLogger.Instance; - } - - protected override async Task RetryAsync(EventExecutionErrorContext context) - { - if (Options.RetryStrategyOptions.IntervalMillisecond > 0) - { - await Task.Delay(Options.RetryStrategyOptions.IntervalMillisecond); - } - - context.TryGetRetryAttempt(out var retryAttempt); - - await context.EventBus.As().PublishAsync( - context.EventType, - context.EventData, - context.GetProperty(HeadersKey).As(), - new Dictionary {{RetryAttemptKey, ++retryAttempt}}); - } - - protected override async Task MoveToDeadLetterAsync(EventExecutionErrorContext context) - { - Logger.LogException( - context.Exceptions.Count == 1 ? context.Exceptions.First() : new AggregateException(context.Exceptions), - LogLevel.Error); - - await context.EventBus.As().PublishToDeadLetterAsync( - context.EventType, - context.EventData, - context.GetProperty(HeadersKey).As(), - new Dictionary {{"exceptions", context.Exceptions.Select(x => x.ToString()).ToList()}}); - } - } -} diff --git a/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/RabbitMqDistributedEventBus.cs b/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/RabbitMqDistributedEventBus.cs index ceba890234..3188b9bcf1 100644 --- a/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/RabbitMqDistributedEventBus.cs +++ b/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/RabbitMqDistributedEventBus.cs @@ -7,7 +7,6 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using RabbitMQ.Client; using RabbitMQ.Client.Events; -using Volo.Abp.Data; using Volo.Abp.DependencyInjection; using Volo.Abp.EventBus.Distributed; using Volo.Abp.Guids; @@ -26,7 +25,6 @@ namespace Volo.Abp.EventBus.RabbitMq public class RabbitMqDistributedEventBus : DistributedEventBusBase, ISingletonDependency { protected AbpRabbitMqEventBusOptions AbpRabbitMqEventBusOptions { get; } - protected AbpEventBusOptions AbpEventBusOptions { get; } protected IConnectionPool ConnectionPool { get; } protected IRabbitMqSerializer Serializer { get; } @@ -45,15 +43,12 @@ namespace Volo.Abp.EventBus.RabbitMq IRabbitMqMessageConsumerFactory messageConsumerFactory, ICurrentTenant currentTenant, IUnitOfWorkManager unitOfWorkManager, - IEventErrorHandler errorHandler, - IOptions abpEventBusOptions, IGuidGenerator guidGenerator, IClock clock) : base( - serviceScopeFactory, + serviceScopeFactory, currentTenant, unitOfWorkManager, - errorHandler, distributedEventBusOptions, guidGenerator, clock) @@ -61,7 +56,6 @@ namespace Volo.Abp.EventBus.RabbitMq ConnectionPool = connectionPool; Serializer = serializer; MessageConsumerFactory = messageConsumerFactory; - AbpEventBusOptions = abpEventBusOptions.Value; AbpRabbitMqEventBusOptions = options.Value; HandlerFactories = new ConcurrentDictionary>(); @@ -70,21 +64,17 @@ namespace Volo.Abp.EventBus.RabbitMq public void Initialize() { - const string suffix = "_dead_letter"; - Consumer = MessageConsumerFactory.Create( new ExchangeDeclareConfiguration( AbpRabbitMqEventBusOptions.ExchangeName, type: "direct", - durable: true, - deadLetterExchangeName: AbpRabbitMqEventBusOptions.ExchangeName + suffix + durable: true ), new QueueDeclareConfiguration( AbpRabbitMqEventBusOptions.ClientName, durable: true, exclusive: false, - autoDelete: false, - AbpEventBusOptions.DeadLetterName ?? AbpRabbitMqEventBusOptions.ClientName + suffix + autoDelete: false ), AbpRabbitMqEventBusOptions.ConnectionName ); @@ -104,27 +94,15 @@ namespace Volo.Abp.EventBus.RabbitMq } var eventBytes = ea.Body.ToArray(); - + if (await AddToInboxAsync(ea.BasicProperties.MessageId, eventName, eventType, eventBytes)) { return; } - - var eventData = Serializer.Deserialize(eventBytes, eventType); - await TriggerHandlersAsync(eventType, eventData, errorContext => - { - var retryAttempt = 0; - if (ea.BasicProperties.Headers != null && - ea.BasicProperties.Headers.ContainsKey(EventErrorHandlerBase.RetryAttemptKey)) - { - retryAttempt = (int)ea.BasicProperties.Headers[EventErrorHandlerBase.RetryAttemptKey]; - } + var eventData = Serializer.Deserialize(eventBytes, eventType); - errorContext.EventData = Serializer.Deserialize(eventBytes, eventType); - errorContext.SetProperty(EventErrorHandlerBase.HeadersKey, ea.BasicProperties); - errorContext.SetProperty(EventErrorHandlerBase.RetryAttemptKey, retryAttempt); - }); + await TriggerHandlersAsync(eventType, eventData); } public override IDisposable Subscribe(Type eventType, IEventHandlerFactory factory) @@ -226,7 +204,7 @@ namespace Volo.Abp.EventBus.RabbitMq { return; } - + var eventData = Serializer.Deserialize(incomingEvent.EventData, eventType); var exceptions = new List(); await TriggerHandlersAsync(eventType, eventData, exceptions, inboxConfig); @@ -235,7 +213,7 @@ namespace Volo.Abp.EventBus.RabbitMq ThrowOriginalExceptions(eventType, exceptions); } } - + protected override byte[] Serialize(object eventData) { return Serializer.Serialize(eventData); @@ -248,7 +226,7 @@ namespace Volo.Abp.EventBus.RabbitMq return PublishAsync(eventName, body, properties, headersArguments); } - + protected Task PublishAsync( string eventName, byte[] body, @@ -274,7 +252,7 @@ namespace Volo.Abp.EventBus.RabbitMq { properties.MessageId = (eventId ?? GuidGenerator.Create()).ToString("N"); } - + SetEventMessageHeaders(properties, headersArguments); channel.BasicPublish( diff --git a/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/RabbitMqEventErrorHandler.cs b/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/RabbitMqEventErrorHandler.cs deleted file mode 100644 index e8848bee72..0000000000 --- a/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/RabbitMqEventErrorHandler.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.Extensions.Options; -using RabbitMQ.Client; -using Volo.Abp.Data; -using Volo.Abp.DependencyInjection; - -namespace Volo.Abp.EventBus.RabbitMq -{ - public class RabbitMqEventErrorHandler : EventErrorHandlerBase, ISingletonDependency - { - public RabbitMqEventErrorHandler( - IOptions options) - : base(options) - { - } - - protected override async Task RetryAsync(EventExecutionErrorContext context) - { - if (Options.RetryStrategyOptions.IntervalMillisecond > 0) - { - await Task.Delay(Options.RetryStrategyOptions.IntervalMillisecond); - } - - context.TryGetRetryAttempt(out var retryAttempt); - - await context.EventBus.As().PublishAsync( - context.EventType, - context.EventData, - context.GetProperty(HeadersKey).As(), - new Dictionary - { - {RetryAttemptKey, ++retryAttempt}, - {"exceptions", context.Exceptions.Select(x => x.ToString()).ToList()} - }); - } - - protected override Task MoveToDeadLetterAsync(EventExecutionErrorContext context) - { - ThrowOriginalExceptions(context); - - return Task.CompletedTask; - } - } -} diff --git a/framework/src/Volo.Abp.EventBus.Rebus/Volo/Abp/EventBus/Rebus/AbpEventBusRebusModule.cs b/framework/src/Volo.Abp.EventBus.Rebus/Volo/Abp/EventBus/Rebus/AbpEventBusRebusModule.cs index a13f964d3f..1ad835c122 100644 --- a/framework/src/Volo.Abp.EventBus.Rebus/Volo/Abp/EventBus/Rebus/AbpEventBusRebusModule.cs +++ b/framework/src/Volo.Abp.EventBus.Rebus/Volo/Abp/EventBus/Rebus/AbpEventBusRebusModule.cs @@ -1,6 +1,5 @@ using Microsoft.Extensions.DependencyInjection; using Rebus.Handlers; -using Rebus.Retry.Simple; using Rebus.ServiceProvider; using Volo.Abp.Modularity; @@ -12,7 +11,6 @@ namespace Volo.Abp.EventBus.Rebus { public override void ConfigureServices(ServiceConfigurationContext context) { - var abpEventBusOptions = context.Services.ExecutePreConfiguredActions(); var options = context.Services.ExecutePreConfiguredActions();; context.Services.AddTransient(typeof(IHandleMessages<>), typeof(RebusDistributedEventHandlerAdapter<>)); @@ -24,14 +22,6 @@ namespace Volo.Abp.EventBus.Rebus context.Services.AddRebus(configure => { - if (abpEventBusOptions.RetryStrategyOptions != null) - { - configure.Options(b => - b.SimpleRetryStrategy( - errorQueueAddress: abpEventBusOptions.DeadLetterName ?? options.InputQueueName + "_dead_letter", - maxDeliveryAttempts: abpEventBusOptions.RetryStrategyOptions.MaxRetryAttempts)); - } - options.Configurer?.Invoke(configure); return configure; }); diff --git a/framework/src/Volo.Abp.EventBus.Rebus/Volo/Abp/EventBus/Rebus/RebusDistributedEventBus.cs b/framework/src/Volo.Abp.EventBus.Rebus/Volo/Abp/EventBus/Rebus/RebusDistributedEventBus.cs index 1cb380679f..c0d75330cb 100644 --- a/framework/src/Volo.Abp.EventBus.Rebus/Volo/Abp/EventBus/Rebus/RebusDistributedEventBus.cs +++ b/framework/src/Volo.Abp.EventBus.Rebus/Volo/Abp/EventBus/Rebus/RebusDistributedEventBus.cs @@ -36,7 +36,6 @@ namespace Volo.Abp.EventBus.Rebus IBus rebus, IOptions abpDistributedEventBusOptions, IOptions abpEventBusRebusOptions, - IEventErrorHandler errorHandler, IRebusSerializer serializer, IGuidGenerator guidGenerator, IClock clock) : @@ -44,7 +43,6 @@ namespace Volo.Abp.EventBus.Rebus serviceScopeFactory, currentTenant, unitOfWorkManager, - errorHandler, abpDistributedEventBusOptions, guidGenerator, clock) diff --git a/framework/src/Volo.Abp.EventBus.Rebus/Volo/Abp/EventBus/Rebus/RebusEventErrorHandler.cs b/framework/src/Volo.Abp.EventBus.Rebus/Volo/Abp/EventBus/Rebus/RebusEventErrorHandler.cs deleted file mode 100644 index 8fe6a53dbb..0000000000 --- a/framework/src/Volo.Abp.EventBus.Rebus/Volo/Abp/EventBus/Rebus/RebusEventErrorHandler.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System.Threading.Tasks; -using Microsoft.Extensions.Options; -using Volo.Abp.DependencyInjection; - -namespace Volo.Abp.EventBus.Rebus -{ - /// - /// Rebus will automatic retries and error handling: https://github.com/rebus-org/Rebus/wiki/Automatic-retries-and-error-handling - /// - public class RebusEventErrorHandler : EventErrorHandlerBase, ISingletonDependency - { - public RebusEventErrorHandler( - IOptions options) - : base(options) - { - } - - protected override Task RetryAsync(EventExecutionErrorContext context) - { - ThrowOriginalExceptions(context); - - return Task.CompletedTask; - } - - protected override Task MoveToDeadLetterAsync(EventExecutionErrorContext context) - { - ThrowOriginalExceptions(context); - - return Task.CompletedTask; - } - } -} diff --git a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/AbpEventBusModule.cs b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/AbpEventBusModule.cs index bd86f14703..3bbdf3d72b 100644 --- a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/AbpEventBusModule.cs +++ b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/AbpEventBusModule.cs @@ -25,14 +25,6 @@ namespace Volo.Abp.EventBus AddEventHandlers(context.Services); } - public override void ConfigureServices(ServiceConfigurationContext context) - { - Configure(options => - { - context.Services.ExecutePreConfiguredActions(options); - }); - } - private static void AddEventHandlers(IServiceCollection services) { var localHandlers = new List(); diff --git a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/AbpEventBusOptions.cs b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/AbpEventBusOptions.cs deleted file mode 100644 index 39631c7e18..0000000000 --- a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/AbpEventBusOptions.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; - -namespace Volo.Abp.EventBus -{ - public class AbpEventBusOptions - { - public bool EnabledErrorHandle { get; set; } - - public Func ErrorHandleSelector { get; set; } - - public string DeadLetterName { get; set; } - - public AbpEventBusRetryStrategyOptions RetryStrategyOptions { get; set; } - - public void UseRetryStrategy(Action action = null) - { - EnabledErrorHandle = true; - RetryStrategyOptions = new AbpEventBusRetryStrategyOptions(); - action?.Invoke(RetryStrategyOptions); - } - } -} diff --git a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/AbpEventBusRetryStrategyOptions.cs b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/AbpEventBusRetryStrategyOptions.cs deleted file mode 100644 index 4b5b722e96..0000000000 --- a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/AbpEventBusRetryStrategyOptions.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Volo.Abp.EventBus -{ - public class AbpEventBusRetryStrategyOptions - { - public int IntervalMillisecond { get; set; } = 3000; - - public int MaxRetryAttempts { get; set; } = 3; - } -} diff --git a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Distributed/DistributedEventBusBase.cs b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Distributed/DistributedEventBusBase.cs index 70c5bd5533..6745327f7d 100644 --- a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Distributed/DistributedEventBusBase.cs +++ b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Distributed/DistributedEventBusBase.cs @@ -20,15 +20,13 @@ namespace Volo.Abp.EventBus.Distributed IServiceScopeFactory serviceScopeFactory, ICurrentTenant currentTenant, IUnitOfWorkManager unitOfWorkManager, - IEventErrorHandler errorHandler, IOptions abpDistributedEventBusOptions, IGuidGenerator guidGenerator, IClock clock ) : base( serviceScopeFactory, currentTenant, - unitOfWorkManager, - errorHandler) + unitOfWorkManager) { GuidGenerator = guidGenerator; Clock = clock; @@ -84,7 +82,7 @@ namespace Volo.Abp.EventBus.Distributed OutgoingEventInfo outgoingEvent, OutboxConfig outboxConfig ); - + public abstract Task ProcessFromInboxAsync( IncomingEventInfo incomingEvent, InboxConfig inboxConfig); @@ -144,7 +142,7 @@ namespace Volo.Abp.EventBus.Distributed continue; } } - + await eventInbox.EnqueueAsync( new IncomingEventInfo( GuidGenerator.Create(), @@ -163,4 +161,4 @@ namespace Volo.Abp.EventBus.Distributed protected abstract byte[] Serialize(object eventData); } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventBusBase.cs b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventBusBase.cs index 694166b1bc..46d6ecce3c 100644 --- a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventBusBase.cs +++ b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventBusBase.cs @@ -22,18 +22,14 @@ namespace Volo.Abp.EventBus protected IUnitOfWorkManager UnitOfWorkManager { get; } - protected IEventErrorHandler ErrorHandler { get; } - protected EventBusBase( IServiceScopeFactory serviceScopeFactory, ICurrentTenant currentTenant, - IUnitOfWorkManager unitOfWorkManager, - IEventErrorHandler errorHandler) + IUnitOfWorkManager unitOfWorkManager) { ServiceScopeFactory = serviceScopeFactory; CurrentTenant = currentTenant; UnitOfWorkManager = unitOfWorkManager; - ErrorHandler = errorHandler; } /// @@ -120,7 +116,7 @@ namespace Volo.Abp.EventBus protected abstract void AddToUnitOfWork(IUnitOfWork unitOfWork, UnitOfWorkEventRecord eventRecord); - public virtual async Task TriggerHandlersAsync(Type eventType, object eventData, Action onErrorAction = null) + public virtual async Task TriggerHandlersAsync(Type eventType, object eventData) { var exceptions = new List(); @@ -128,9 +124,7 @@ namespace Volo.Abp.EventBus if (exceptions.Any()) { - var context = new EventExecutionErrorContext(exceptions, eventType, this); - onErrorAction?.Invoke(context); - await ErrorHandler.HandleAsync(context); + ThrowOriginalExceptions(eventType, exceptions); } } @@ -162,7 +156,7 @@ namespace Volo.Abp.EventBus } } } - + protected void ThrowOriginalExceptions(Type eventType, List exceptions) { if (exceptions.Count == 1) diff --git a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventErrorHandlerBase.cs b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventErrorHandlerBase.cs deleted file mode 100644 index ba4527fc70..0000000000 --- a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventErrorHandlerBase.cs +++ /dev/null @@ -1,76 +0,0 @@ -using System; -using System.Threading.Tasks; -using Microsoft.Extensions.Options; - -namespace Volo.Abp.EventBus -{ - public abstract class EventErrorHandlerBase : IEventErrorHandler - { - public const string HeadersKey = "headers"; - public const string RetryAttemptKey = "retryAttempt"; - - protected AbpEventBusOptions Options { get; } - - protected EventErrorHandlerBase(IOptions options) - { - Options = options.Value; - } - - public virtual async Task HandleAsync(EventExecutionErrorContext context) - { - if (!await ShouldHandleAsync(context)) - { - ThrowOriginalExceptions(context); - } - - if (await ShouldRetryAsync(context)) - { - await RetryAsync(context); - return; - } - - await MoveToDeadLetterAsync(context); - } - - protected abstract Task RetryAsync(EventExecutionErrorContext context); - - protected abstract Task MoveToDeadLetterAsync(EventExecutionErrorContext context); - - protected virtual Task ShouldHandleAsync(EventExecutionErrorContext context) - { - if (!Options.EnabledErrorHandle) - { - return Task.FromResult(false); - } - - return Task.FromResult(Options.ErrorHandleSelector == null || Options.ErrorHandleSelector.Invoke(context.EventType)); - } - - protected virtual Task ShouldRetryAsync(EventExecutionErrorContext context) - { - if (Options.RetryStrategyOptions == null) - { - return Task.FromResult(false); - } - - if (!context.TryGetRetryAttempt(out var retryAttempt)) - { - return Task.FromResult(false); - } - - return Task.FromResult(Options.RetryStrategyOptions.MaxRetryAttempts > retryAttempt); - } - - protected virtual void ThrowOriginalExceptions(EventExecutionErrorContext context) - { - if (context.Exceptions.Count == 1) - { - context.Exceptions[0].ReThrow(); - } - - throw new AggregateException( - "More than one error has occurred while triggering the event: " + context.EventType, - context.Exceptions); - } - } -} diff --git a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventExecutionErrorContext.cs b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventExecutionErrorContext.cs deleted file mode 100644 index e192f61cbe..0000000000 --- a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventExecutionErrorContext.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System; -using System.Collections.Generic; -using Volo.Abp.Data; -using Volo.Abp.ObjectExtending; - -namespace Volo.Abp.EventBus -{ - public class EventExecutionErrorContext : ExtensibleObject - { - public IReadOnlyList Exceptions { get; } - - public object EventData { get; set; } - - public Type EventType { get; } - - public IEventBus EventBus { get; } - - public EventExecutionErrorContext(List exceptions, Type eventType, IEventBus eventBus) - { - Exceptions = exceptions; - EventType = eventType; - EventBus = eventBus; - } - - public bool TryGetRetryAttempt(out int retryAttempt) - { - retryAttempt = 0; - if (!this.HasProperty(EventErrorHandlerBase.RetryAttemptKey)) - { - return false; - } - - retryAttempt = this.GetProperty(EventErrorHandlerBase.RetryAttemptKey); - return true; - - } - } -} diff --git a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/IEventErrorHandler.cs b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/IEventErrorHandler.cs deleted file mode 100644 index f1b4a40f15..0000000000 --- a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/IEventErrorHandler.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Threading.Tasks; - -namespace Volo.Abp.EventBus -{ - public interface IEventErrorHandler - { - Task HandleAsync(EventExecutionErrorContext context); - } -} diff --git a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Local/LocalEventBus.cs b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Local/LocalEventBus.cs index 77bf5b43bd..4da09bf608 100644 --- a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Local/LocalEventBus.cs +++ b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Local/LocalEventBus.cs @@ -7,11 +7,9 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; -using Volo.Abp.Data; using Volo.Abp.DependencyInjection; using Volo.Abp.MultiTenancy; using Volo.Abp.Threading; -using Volo.Abp.Json; using Volo.Abp.Uow; namespace Volo.Abp.EventBus.Local @@ -35,9 +33,8 @@ namespace Volo.Abp.EventBus.Local IOptions options, IServiceScopeFactory serviceScopeFactory, ICurrentTenant currentTenant, - IUnitOfWorkManager unitOfWorkManager, - IEventErrorHandler errorHandler) - : base(serviceScopeFactory, currentTenant, unitOfWorkManager, errorHandler) + IUnitOfWorkManager unitOfWorkManager) + : base(serviceScopeFactory, currentTenant, unitOfWorkManager) { Options = options.Value; Logger = NullLogger.Instance; @@ -134,11 +131,7 @@ namespace Volo.Abp.EventBus.Local public virtual async Task PublishAsync(LocalEventMessage localEventMessage) { - await TriggerHandlersAsync(localEventMessage.EventType, localEventMessage.EventData, errorContext => - { - errorContext.EventData = localEventMessage.EventData; - errorContext.SetProperty(nameof(LocalEventMessage.MessageId), localEventMessage.MessageId); - }); + await TriggerHandlersAsync(localEventMessage.EventType, localEventMessage.EventData); } protected override IEnumerable GetHandlerFactories(Type eventType) diff --git a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Local/LocalEventErrorHandler.cs b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Local/LocalEventErrorHandler.cs deleted file mode 100644 index c08bca019f..0000000000 --- a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Local/LocalEventErrorHandler.cs +++ /dev/null @@ -1,60 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using Microsoft.Extensions.Options; -using Volo.Abp.Data; -using Volo.Abp.DependencyInjection; - -namespace Volo.Abp.EventBus.Local -{ - [ExposeServices(typeof(LocalEventErrorHandler), typeof(IEventErrorHandler))] - public class LocalEventErrorHandler : EventErrorHandlerBase, ISingletonDependency - { - protected Dictionary RetryTracking { get; } - - public LocalEventErrorHandler( - IOptions options) - : base(options) - { - RetryTracking = new Dictionary(); - } - - protected override async Task RetryAsync(EventExecutionErrorContext context) - { - if (Options.RetryStrategyOptions.IntervalMillisecond > 0) - { - await Task.Delay(Options.RetryStrategyOptions.IntervalMillisecond); - } - - var messageId = context.GetProperty(nameof(LocalEventMessage.MessageId)); - - context.TryGetRetryAttempt(out var retryAttempt); - RetryTracking[messageId] = ++retryAttempt; - - await context.EventBus.As().PublishAsync(new LocalEventMessage(messageId, context.EventData, context.EventType)); - - RetryTracking.Remove(messageId); - } - - protected override Task MoveToDeadLetterAsync(EventExecutionErrorContext context) - { - ThrowOriginalExceptions(context); - - return Task.CompletedTask; - } - - protected override async Task ShouldRetryAsync(EventExecutionErrorContext context) - { - var messageId = context.GetProperty(nameof(LocalEventMessage.MessageId)); - context.SetProperty(RetryAttemptKey, RetryTracking.GetOrDefault(messageId)); - - if (await base.ShouldRetryAsync(context)) - { - return true; - } - - RetryTracking.Remove(messageId); - return false; - } - } -} diff --git a/framework/src/Volo.Abp.Kafka/Volo/Abp/Kafka/IKafkaMessageConsumerFactory.cs b/framework/src/Volo.Abp.Kafka/Volo/Abp/Kafka/IKafkaMessageConsumerFactory.cs index 96ec753dc2..2b01b5a935 100644 --- a/framework/src/Volo.Abp.Kafka/Volo/Abp/Kafka/IKafkaMessageConsumerFactory.cs +++ b/framework/src/Volo.Abp.Kafka/Volo/Abp/Kafka/IKafkaMessageConsumerFactory.cs @@ -8,13 +8,11 @@ /// not disposed until end of the application. /// /// - /// /// /// /// IKafkaMessageConsumer Create( string topicName, - string deadLetterTopicName, string groupId, string connectionName = null); } diff --git a/framework/src/Volo.Abp.Kafka/Volo/Abp/Kafka/KafkaMessageConsumer.cs b/framework/src/Volo.Abp.Kafka/Volo/Abp/Kafka/KafkaMessageConsumer.cs index d1bad00533..afed026402 100644 --- a/framework/src/Volo.Abp.Kafka/Volo/Abp/Kafka/KafkaMessageConsumer.cs +++ b/framework/src/Volo.Abp.Kafka/Volo/Abp/Kafka/KafkaMessageConsumer.cs @@ -39,8 +39,6 @@ namespace Volo.Abp.Kafka protected string TopicName { get; private set; } - protected string DeadLetterTopicName { get; private set; } - public KafkaMessageConsumer( IConsumerPool consumerPool, IExceptionNotifier exceptionNotifier, @@ -64,15 +62,12 @@ namespace Volo.Abp.Kafka public virtual void Initialize( [NotNull] string topicName, - [NotNull] string deadLetterTopicName, [NotNull] string groupId, string connectionName = null) { Check.NotNull(topicName, nameof(topicName)); - Check.NotNull(deadLetterTopicName, nameof(deadLetterTopicName)); Check.NotNull(groupId, nameof(groupId)); TopicName = topicName; - DeadLetterTopicName = deadLetterTopicName; ConnectionName = connectionName ?? KafkaConnections.DefaultConnectionName; GroupId = groupId; Timer.Start(); @@ -94,30 +89,18 @@ namespace Volo.Abp.Kafka { using (var adminClient = new AdminClientBuilder(Options.Connections.GetOrDefault(ConnectionName)).Build()) { - var topics = new List + var topic = new TopicSpecification { - new() - { - Name = TopicName, - NumPartitions = 1, - ReplicationFactor = 1 - }, - new() - { - Name = DeadLetterTopicName, - NumPartitions = 1, - ReplicationFactor = 1 - } + Name = TopicName, + NumPartitions = 1, + ReplicationFactor = 1 }; - topics.ForEach(topic => - { - Options.ConfigureTopic?.Invoke(topic); - }); + Options.ConfigureTopic?.Invoke(topic); try { - await adminClient.CreateTopicsAsync(topics); + await adminClient.CreateTopicsAsync(new[] {topic}); } catch (CreateTopicsException e) { diff --git a/framework/src/Volo.Abp.Kafka/Volo/Abp/Kafka/KafkaMessageConsumerFactory.cs b/framework/src/Volo.Abp.Kafka/Volo/Abp/Kafka/KafkaMessageConsumerFactory.cs index 4a22fd04f6..9d199b15f9 100644 --- a/framework/src/Volo.Abp.Kafka/Volo/Abp/Kafka/KafkaMessageConsumerFactory.cs +++ b/framework/src/Volo.Abp.Kafka/Volo/Abp/Kafka/KafkaMessageConsumerFactory.cs @@ -1,5 +1,4 @@ using System; -using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Volo.Abp.DependencyInjection; @@ -16,12 +15,11 @@ namespace Volo.Abp.Kafka public IKafkaMessageConsumer Create( string topicName, - string deadLetterTopicName, string groupId, string connectionName = null) { var consumer = ServiceScope.ServiceProvider.GetRequiredService(); - consumer.Initialize(topicName, deadLetterTopicName, groupId, connectionName); + consumer.Initialize(topicName, groupId, connectionName); return consumer; } diff --git a/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/ExchangeDeclareConfiguration.cs b/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/ExchangeDeclareConfiguration.cs index b9e762abbe..8ea919484a 100644 --- a/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/ExchangeDeclareConfiguration.cs +++ b/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/ExchangeDeclareConfiguration.cs @@ -6,8 +6,6 @@ namespace Volo.Abp.RabbitMQ { public string ExchangeName { get; } - public string DeadLetterExchangeName { get; set; } - public string Type { get; } public bool Durable { get; set; } @@ -20,11 +18,9 @@ namespace Volo.Abp.RabbitMQ string exchangeName, string type, bool durable = false, - bool autoDelete = false, - string deadLetterExchangeName = null) + bool autoDelete = false) { ExchangeName = exchangeName; - DeadLetterExchangeName = deadLetterExchangeName; Type = type; Durable = durable; AutoDelete = autoDelete; diff --git a/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/QueueDeclareConfiguration.cs b/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/QueueDeclareConfiguration.cs index b84f08ec42..211dc3d7b2 100644 --- a/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/QueueDeclareConfiguration.cs +++ b/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/QueueDeclareConfiguration.cs @@ -8,8 +8,6 @@ namespace Volo.Abp.RabbitMQ { [NotNull] public string QueueName { get; } - public string DeadLetterQueueName { get; set; } - public bool Durable { get; set; } public bool Exclusive { get; set; } @@ -22,11 +20,9 @@ namespace Volo.Abp.RabbitMQ [NotNull] string queueName, bool durable = true, bool exclusive = false, - bool autoDelete = false, - string deadLetterQueueName = null) + bool autoDelete = false) { QueueName = queueName; - DeadLetterQueueName = deadLetterQueueName; Durable = durable; Exclusive = exclusive; AutoDelete = autoDelete; diff --git a/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/RabbitMqMessageConsumer.cs b/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/RabbitMqMessageConsumer.cs index 671445e00d..a0c1251c6c 100644 --- a/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/RabbitMqMessageConsumer.cs +++ b/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/RabbitMqMessageConsumer.cs @@ -157,29 +157,7 @@ namespace Volo.Abp.RabbitMQ arguments: Exchange.Arguments ); - if (!Exchange.DeadLetterExchangeName.IsNullOrWhiteSpace() && - !Queue.DeadLetterQueueName.IsNullOrWhiteSpace()) - { - Channel.ExchangeDeclare( - Exchange.DeadLetterExchangeName, - Exchange.Type, - Exchange.Durable, - Exchange.AutoDelete - ); - - Channel.QueueDeclare( - Queue.DeadLetterQueueName, - Queue.Durable, - Queue.Exclusive, - Queue.AutoDelete); - - Queue.Arguments["x-dead-letter-exchange"] = Exchange.DeadLetterExchangeName; - Queue.Arguments["x-dead-letter-routing-key"] = Queue.DeadLetterQueueName; - - Channel.QueueBind(Queue.DeadLetterQueueName, Exchange.DeadLetterExchangeName, Queue.DeadLetterQueueName); - } - - var result = Channel.QueueDeclare( + Channel.QueueDeclare( queue: Queue.QueueName, durable: Queue.Durable, exclusive: Queue.Exclusive, @@ -202,11 +180,8 @@ namespace Volo.Abp.RabbitMQ operationInterruptedException.ShutdownReason.ReplyCode == 406 && operationInterruptedException.Message.Contains("arg 'x-dead-letter-exchange'")) { - Exchange.DeadLetterExchangeName = null; - Queue.DeadLetterQueueName = null; - Queue.Arguments.Remove("x-dead-letter-exchange"); - Queue.Arguments.Remove("x-dead-letter-routing-key"); - Logger.LogWarning("Unable to bind the dead letter queue to an existing queue. You can delete the queue or add policy. See: https://www.rabbitmq.com/parameters.html"); + Logger.LogException(ex, LogLevel.Warning); + await ExceptionNotifier.NotifyAsync(ex, logLevel: LogLevel.Warning); } Logger.LogException(ex, LogLevel.Warning); @@ -229,8 +204,13 @@ namespace Volo.Abp.RabbitMQ { try { - Channel.BasicReject(basicDeliverEventArgs.DeliveryTag, false); + Channel.BasicNack( + basicDeliverEventArgs.DeliveryTag, + multiple: false, + requeue: true + ); } + // ReSharper disable once EmptyGeneralCatchClause catch { } Logger.LogException(ex); diff --git a/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/EventBusTestModule.cs b/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/EventBusTestModule.cs index f260fecbea..9a4258c621 100644 --- a/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/EventBusTestModule.cs +++ b/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/EventBusTestModule.cs @@ -5,17 +5,5 @@ namespace Volo.Abp.EventBus [DependsOn(typeof(AbpEventBusModule))] public class EventBusTestModule : AbpModule { - public override void PreConfigureServices(ServiceConfigurationContext context) - { - PreConfigure(options => - { - options.UseRetryStrategy(retryStrategyOptions => - { - retryStrategyOptions.IntervalMillisecond = 0; - }); - - options.ErrorHandleSelector = type => type == typeof(MyExceptionHandleEventData); - }); - } } } diff --git a/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Local/EventBus_Exception_Handler_Tests.cs b/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Local/EventBus_Exception_Handler_Tests.cs deleted file mode 100644 index 3ed0ff19f9..0000000000 --- a/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Local/EventBus_Exception_Handler_Tests.cs +++ /dev/null @@ -1,72 +0,0 @@ -using System; -using System.Threading.Tasks; -using Shouldly; -using Xunit; - -namespace Volo.Abp.EventBus.Local -{ - public class EventBus_Exception_Handler_Tests : EventBusTestBase - { - [Fact] - public async Task Should_Not_Handle_Exception() - { - var retryAttempt = 0; - LocalEventBus.Subscribe(eventData => - { - retryAttempt++; - throw new Exception("This exception is intentionally thrown!"); - }); - - var appException = await Assert.ThrowsAsync(async () => - { - await LocalEventBus.PublishAsync(new MySimpleEventData(1)); - }); - - retryAttempt.ShouldBe(1); - appException.Message.ShouldBe("This exception is intentionally thrown!"); - } - - [Fact] - public async Task Should_Handle_Exception() - { - var retryAttempt = 0; - LocalEventBus.Subscribe(eventData => - { - eventData.Value.ShouldBe(0); - retryAttempt++; - if (retryAttempt < 2) - { - throw new Exception("This exception is intentionally thrown!"); - } - - return Task.CompletedTask; - - }); - - await LocalEventBus.PublishAsync(new MyExceptionHandleEventData(0)); - retryAttempt.ShouldBe(2); - } - - [Fact] - public async Task Should_Throw_Exception_After_Error_Handle() - { - var retryAttempt = 0; - LocalEventBus.Subscribe(eventData => - { - eventData.Value.ShouldBe(0); - - retryAttempt++; - - throw new Exception("This exception is intentionally thrown!"); - }); - - var appException = await Assert.ThrowsAsync(async () => - { - await LocalEventBus.PublishAsync(new MyExceptionHandleEventData(0)); - }); - - retryAttempt.ShouldBe(4); - appException.Message.ShouldBe("This exception is intentionally thrown!"); - } - } -} diff --git a/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/MyExceptionHandleEventData.cs b/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/MyExceptionHandleEventData.cs deleted file mode 100644 index f490d58211..0000000000 --- a/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/MyExceptionHandleEventData.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Volo.Abp.EventBus -{ - public class MyExceptionHandleEventData - { - public int Value { get; set; } - - public MyExceptionHandleEventData(int value) - { - Value = value; - } - } -} diff --git a/modules/account/src/Volo.Abp.Account.HttpApi/Volo/Abp/Account/AccountController.cs b/modules/account/src/Volo.Abp.Account.HttpApi/Volo/Abp/Account/AccountController.cs index d1f22587e8..13910ac6ab 100644 --- a/modules/account/src/Volo.Abp.Account.HttpApi/Volo/Abp/Account/AccountController.cs +++ b/modules/account/src/Volo.Abp.Account.HttpApi/Volo/Abp/Account/AccountController.cs @@ -8,7 +8,7 @@ namespace Volo.Abp.Account [RemoteService(Name = AccountRemoteServiceConsts.RemoteServiceName)] [Area("account")] [Route("api/account")] - public class AccountController : AbpController, IAccountAppService + public class AccountController : AbpControllerBase, IAccountAppService { protected IAccountAppService AccountAppService { get; } diff --git a/modules/account/src/Volo.Abp.Account.Web/Areas/Account/Controllers/AccountController.cs b/modules/account/src/Volo.Abp.Account.Web/Areas/Account/Controllers/AccountController.cs index ec9f26179d..dd8a853350 100644 --- a/modules/account/src/Volo.Abp.Account.Web/Areas/Account/Controllers/AccountController.cs +++ b/modules/account/src/Volo.Abp.Account.Web/Areas/Account/Controllers/AccountController.cs @@ -22,7 +22,7 @@ namespace Volo.Abp.Account.Web.Areas.Account.Controllers [ControllerName("Login")] [Area("account")] [Route("api/account")] - public class AccountController : AbpController + public class AccountController : AbpControllerBase { protected SignInManager SignInManager { get; } protected IdentityUserManager UserManager { get; } diff --git a/modules/blogging/src/Volo.Blogging.Admin.HttpApi/Volo/Blogging/Admin/BlogManagementController.cs b/modules/blogging/src/Volo.Blogging.Admin.HttpApi/Volo/Blogging/Admin/BlogManagementController.cs index ce6457dcc7..4ee705551e 100644 --- a/modules/blogging/src/Volo.Blogging.Admin.HttpApi/Volo/Blogging/Admin/BlogManagementController.cs +++ b/modules/blogging/src/Volo.Blogging.Admin.HttpApi/Volo/Blogging/Admin/BlogManagementController.cs @@ -13,7 +13,7 @@ namespace Volo.Blogging.Admin [RemoteService(Name = BloggingAdminRemoteServiceConsts.RemoteServiceName)] [Area("bloggingAdmin")] [Route("api/blogging/blogs/admin")] - public class BlogManagementController : AbpController, IBlogManagementAppService + public class BlogManagementController : AbpControllerBase, IBlogManagementAppService { private readonly IBlogManagementAppService _blogManagementAppService; diff --git a/modules/blogging/src/Volo.Blogging.HttpApi/Volo/Blogging/BlogFilesController.cs b/modules/blogging/src/Volo.Blogging.HttpApi/Volo/Blogging/BlogFilesController.cs index 12bedc3e6c..898d3fe09b 100644 --- a/modules/blogging/src/Volo.Blogging.HttpApi/Volo/Blogging/BlogFilesController.cs +++ b/modules/blogging/src/Volo.Blogging.HttpApi/Volo/Blogging/BlogFilesController.cs @@ -10,7 +10,7 @@ namespace Volo.Blogging [RemoteService(Name = BloggingRemoteServiceConsts.RemoteServiceName)] [Area("blogging")] [Route("api/blogging/files")] - public class BlogFilesController : AbpController, IFileAppService + public class BlogFilesController : AbpControllerBase, IFileAppService { private readonly IFileAppService _fileAppService; diff --git a/modules/blogging/src/Volo.Blogging.HttpApi/Volo/Blogging/BlogsController.cs b/modules/blogging/src/Volo.Blogging.HttpApi/Volo/Blogging/BlogsController.cs index 9ef141b3de..af46d0784a 100644 --- a/modules/blogging/src/Volo.Blogging.HttpApi/Volo/Blogging/BlogsController.cs +++ b/modules/blogging/src/Volo.Blogging.HttpApi/Volo/Blogging/BlogsController.cs @@ -12,7 +12,7 @@ namespace Volo.Blogging [RemoteService(Name = BloggingRemoteServiceConsts.RemoteServiceName)] [Area("blogging")] [Route("api/blogging/blogs")] - public class BlogsController : AbpController, IBlogAppService + public class BlogsController : AbpControllerBase, IBlogAppService { private readonly IBlogAppService _blogAppService; diff --git a/modules/blogging/src/Volo.Blogging.HttpApi/Volo/Blogging/CommentsController.cs b/modules/blogging/src/Volo.Blogging.HttpApi/Volo/Blogging/CommentsController.cs index caea1cfa2f..73d6a115f4 100644 --- a/modules/blogging/src/Volo.Blogging.HttpApi/Volo/Blogging/CommentsController.cs +++ b/modules/blogging/src/Volo.Blogging.HttpApi/Volo/Blogging/CommentsController.cs @@ -12,7 +12,7 @@ namespace Volo.Blogging [RemoteService(Name = BloggingRemoteServiceConsts.RemoteServiceName)] [Area("blogging")] [Route("api/blogging/comments")] - public class CommentsController : AbpController, ICommentAppService + public class CommentsController : AbpControllerBase, ICommentAppService { private readonly ICommentAppService _commentAppService; diff --git a/modules/blogging/src/Volo.Blogging.HttpApi/Volo/Blogging/PostsController.cs b/modules/blogging/src/Volo.Blogging.HttpApi/Volo/Blogging/PostsController.cs index f3d67af815..66f8f7afab 100644 --- a/modules/blogging/src/Volo.Blogging.HttpApi/Volo/Blogging/PostsController.cs +++ b/modules/blogging/src/Volo.Blogging.HttpApi/Volo/Blogging/PostsController.cs @@ -11,7 +11,7 @@ namespace Volo.Blogging [RemoteService(Name = BloggingRemoteServiceConsts.RemoteServiceName)] [Area("blogging")] [Route("api/blogging/posts")] - public class PostsController : AbpController, IPostAppService + public class PostsController : AbpControllerBase, IPostAppService { private readonly IPostAppService _postAppService; diff --git a/modules/blogging/src/Volo.Blogging.HttpApi/Volo/Blogging/TagsController.cs b/modules/blogging/src/Volo.Blogging.HttpApi/Volo/Blogging/TagsController.cs index 4c2c34db44..262e5ac801 100644 --- a/modules/blogging/src/Volo.Blogging.HttpApi/Volo/Blogging/TagsController.cs +++ b/modules/blogging/src/Volo.Blogging.HttpApi/Volo/Blogging/TagsController.cs @@ -12,7 +12,7 @@ namespace Volo.Blogging [RemoteService(Name = BloggingRemoteServiceConsts.RemoteServiceName)] [Area("blogging")] [Route("api/blogging/tags")] - public class TagsController : AbpController, ITagAppService + public class TagsController : AbpControllerBase, ITagAppService { private readonly ITagAppService _tagAppService; diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/CmsKitAdminController.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/CmsKitAdminController.cs index f4303c0245..fc89a0c63b 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/CmsKitAdminController.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/CmsKitAdminController.cs @@ -3,7 +3,7 @@ using Volo.CmsKit.Localization; namespace Volo.CmsKit.Admin { - public abstract class CmsKitAdminController : AbpController + public abstract class CmsKitAdminController : AbpControllerBase { protected CmsKitAdminController() { diff --git a/modules/cms-kit/src/Volo.CmsKit.Common.HttpApi/Volo/CmsKit/CmsKitControllerBase.cs b/modules/cms-kit/src/Volo.CmsKit.Common.HttpApi/Volo/CmsKit/CmsKitControllerBase.cs index 70a68c7611..4ac5d5423b 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Common.HttpApi/Volo/CmsKit/CmsKitControllerBase.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Common.HttpApi/Volo/CmsKit/CmsKitControllerBase.cs @@ -3,7 +3,7 @@ using Volo.CmsKit.Localization; namespace Volo.CmsKit { - public abstract class CmsKitControllerBase : AbpController + public abstract class CmsKitControllerBase : AbpControllerBase { protected CmsKitControllerBase() { diff --git a/modules/docs/src/Volo.Docs.Admin.HttpApi/Volo/Docs/Admin/DocumentsAdminController.cs b/modules/docs/src/Volo.Docs.Admin.HttpApi/Volo/Docs/Admin/DocumentsAdminController.cs index 88b1d99d1d..f08c8e8f71 100644 --- a/modules/docs/src/Volo.Docs.Admin.HttpApi/Volo/Docs/Admin/DocumentsAdminController.cs +++ b/modules/docs/src/Volo.Docs.Admin.HttpApi/Volo/Docs/Admin/DocumentsAdminController.cs @@ -13,7 +13,7 @@ namespace Volo.Docs.Admin [Area("docs-admin")] [ControllerName("DocumentsAdmin")] [Route("api/docs/admin/documents")] - public class DocumentsAdminController : AbpController, IDocumentAdminAppService + public class DocumentsAdminController : AbpControllerBase, IDocumentAdminAppService { private readonly IDocumentAdminAppService _documentAdminAppService; diff --git a/modules/docs/src/Volo.Docs.Admin.HttpApi/Volo/Docs/Admin/ProjectsAdminController.cs b/modules/docs/src/Volo.Docs.Admin.HttpApi/Volo/Docs/Admin/ProjectsAdminController.cs index 2e09342175..968e60adb7 100644 --- a/modules/docs/src/Volo.Docs.Admin.HttpApi/Volo/Docs/Admin/ProjectsAdminController.cs +++ b/modules/docs/src/Volo.Docs.Admin.HttpApi/Volo/Docs/Admin/ProjectsAdminController.cs @@ -12,7 +12,7 @@ namespace Volo.Docs.Admin [Area("docs-admin")] [ControllerName("ProjectsAdmin")] [Route("api/docs/admin/projects")] - public class ProjectsAdminController : AbpController, IProjectAdminAppService + public class ProjectsAdminController : AbpControllerBase, IProjectAdminAppService { private readonly IProjectAdminAppService _projectAppService; diff --git a/modules/docs/src/Volo.Docs.HttpApi/Volo/Docs/Projects/DocsProjectController.cs b/modules/docs/src/Volo.Docs.HttpApi/Volo/Docs/Projects/DocsProjectController.cs index 602cc970dd..24d9a51491 100644 --- a/modules/docs/src/Volo.Docs.HttpApi/Volo/Docs/Projects/DocsProjectController.cs +++ b/modules/docs/src/Volo.Docs.HttpApi/Volo/Docs/Projects/DocsProjectController.cs @@ -11,7 +11,7 @@ namespace Volo.Docs.Projects [Area("docs")] [ControllerName("Project")] [Route("api/docs/projects")] - public class DocsProjectController : AbpController, IProjectAppService + public class DocsProjectController : AbpControllerBase, IProjectAppService { protected IProjectAppService ProjectAppService { get; } diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.HttpApi/Volo/Abp/FeatureManagement/FeaturesController.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.HttpApi/Volo/Abp/FeatureManagement/FeaturesController.cs index c7dff4d8a3..4a70fefdd9 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.HttpApi/Volo/Abp/FeatureManagement/FeaturesController.cs +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.HttpApi/Volo/Abp/FeatureManagement/FeaturesController.cs @@ -7,7 +7,7 @@ namespace Volo.Abp.FeatureManagement [RemoteService(Name = FeatureManagementRemoteServiceConsts.RemoteServiceName)] [Area("featureManagement")] [Route("api/feature-management/features")] - public class FeaturesController : AbpController, IFeatureAppService + public class FeaturesController : AbpControllerBase, IFeatureAppService { protected IFeatureAppService FeatureAppService { get; } diff --git a/modules/identity/src/Volo.Abp.Identity.HttpApi/Volo/Abp/Identity/IdentityRoleController.cs b/modules/identity/src/Volo.Abp.Identity.HttpApi/Volo/Abp/Identity/IdentityRoleController.cs index 150256badd..38d5f68a41 100644 --- a/modules/identity/src/Volo.Abp.Identity.HttpApi/Volo/Abp/Identity/IdentityRoleController.cs +++ b/modules/identity/src/Volo.Abp.Identity.HttpApi/Volo/Abp/Identity/IdentityRoleController.cs @@ -10,7 +10,7 @@ namespace Volo.Abp.Identity [Area("identity")] [ControllerName("Role")] [Route("api/identity/roles")] - public class IdentityRoleController : AbpController, IIdentityRoleAppService + public class IdentityRoleController : AbpControllerBase, IIdentityRoleAppService { protected IIdentityRoleAppService RoleAppService { get; } diff --git a/modules/identity/src/Volo.Abp.Identity.HttpApi/Volo/Abp/Identity/IdentityUserController.cs b/modules/identity/src/Volo.Abp.Identity.HttpApi/Volo/Abp/Identity/IdentityUserController.cs index c02ea23e9f..7de9de2826 100644 --- a/modules/identity/src/Volo.Abp.Identity.HttpApi/Volo/Abp/Identity/IdentityUserController.cs +++ b/modules/identity/src/Volo.Abp.Identity.HttpApi/Volo/Abp/Identity/IdentityUserController.cs @@ -10,7 +10,7 @@ namespace Volo.Abp.Identity [Area("identity")] [ControllerName("User")] [Route("api/identity/users")] - public class IdentityUserController : AbpController, IIdentityUserAppService + public class IdentityUserController : AbpControllerBase, IIdentityUserAppService { protected IIdentityUserAppService UserAppService { get; } diff --git a/modules/identity/src/Volo.Abp.Identity.HttpApi/Volo/Abp/Identity/IdentityUserLookupController.cs b/modules/identity/src/Volo.Abp.Identity.HttpApi/Volo/Abp/Identity/IdentityUserLookupController.cs index 75fc20a520..d0676ffb7d 100644 --- a/modules/identity/src/Volo.Abp.Identity.HttpApi/Volo/Abp/Identity/IdentityUserLookupController.cs +++ b/modules/identity/src/Volo.Abp.Identity.HttpApi/Volo/Abp/Identity/IdentityUserLookupController.cs @@ -11,7 +11,7 @@ namespace Volo.Abp.Identity [Area("identity")] [ControllerName("UserLookup")] [Route("api/identity/users/lookup")] - public class IdentityUserLookupController : AbpController, IIdentityUserLookupAppService + public class IdentityUserLookupController : AbpControllerBase, IIdentityUserLookupAppService { protected IIdentityUserLookupAppService LookupAppService { get; } diff --git a/modules/identity/src/Volo.Abp.Identity.HttpApi/Volo/Abp/Identity/ProfileController.cs b/modules/identity/src/Volo.Abp.Identity.HttpApi/Volo/Abp/Identity/ProfileController.cs index 91b1bc8325..f16c780d93 100644 --- a/modules/identity/src/Volo.Abp.Identity.HttpApi/Volo/Abp/Identity/ProfileController.cs +++ b/modules/identity/src/Volo.Abp.Identity.HttpApi/Volo/Abp/Identity/ProfileController.cs @@ -8,7 +8,7 @@ namespace Volo.Abp.Identity [Area("identity")] [ControllerName("Profile")] [Route("/api/identity/my-profile")] - public class ProfileController : AbpController, IProfileAppService + public class ProfileController : AbpControllerBase, IProfileAppService { protected IProfileAppService ProfileAppService { get; } diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.HttpApi/Volo/Abp/PermissionManagement/PermissionsController.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.HttpApi/Volo/Abp/PermissionManagement/PermissionsController.cs index bb9db51f98..a9a6096053 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.HttpApi/Volo/Abp/PermissionManagement/PermissionsController.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.HttpApi/Volo/Abp/PermissionManagement/PermissionsController.cs @@ -7,7 +7,7 @@ namespace Volo.Abp.PermissionManagement [RemoteService(Name = PermissionManagementRemoteServiceConsts.RemoteServiceName)] [Area("permissionManagement")] [Route("api/permission-management/permissions")] - public class PermissionsController : AbpController, IPermissionAppService + public class PermissionsController : AbpControllerBase, IPermissionAppService { protected IPermissionAppService PermissionAppService { get; } diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.HttpApi/Volo/Abp/SettingManagement/EmailSettingsController.cs b/modules/setting-management/src/Volo.Abp.SettingManagement.HttpApi/Volo/Abp/SettingManagement/EmailSettingsController.cs index 7ddb284c64..5e01f5b984 100644 --- a/modules/setting-management/src/Volo.Abp.SettingManagement.HttpApi/Volo/Abp/SettingManagement/EmailSettingsController.cs +++ b/modules/setting-management/src/Volo.Abp.SettingManagement.HttpApi/Volo/Abp/SettingManagement/EmailSettingsController.cs @@ -7,7 +7,7 @@ namespace Volo.Abp.SettingManagement [RemoteService(Name = SettingManagementRemoteServiceConsts.RemoteServiceName)] [Area("settingManagement")] [Route("api/setting-management/emailing")] - public class EmailSettingsController : AbpController, IEmailSettingsAppService + public class EmailSettingsController : AbpControllerBase, IEmailSettingsAppService { private readonly IEmailSettingsAppService _emailSettingsAppService; diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.HttpApi/Volo/Abp/TenantManagement/TenantController.cs b/modules/tenant-management/src/Volo.Abp.TenantManagement.HttpApi/Volo/Abp/TenantManagement/TenantController.cs index 317e7e62d0..9c5062f96e 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.HttpApi/Volo/Abp/TenantManagement/TenantController.cs +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.HttpApi/Volo/Abp/TenantManagement/TenantController.cs @@ -10,7 +10,7 @@ namespace Volo.Abp.TenantManagement [RemoteService(Name = TenantManagementRemoteServiceConsts.RemoteServiceName)] [Area("multi-tenancy")] [Route("api/multi-tenancy/tenants")] - public class TenantController : AbpController, ITenantAppService //TODO: Throws exception on validation if we inherit from Controller + public class TenantController : AbpControllerBase, ITenantAppService //TODO: Throws exception on validation if we inherit from Controller { protected ITenantAppService TenantAppService { get; } diff --git a/npm/ng-packs/packages/components/chart.js/src/chart.component.ts b/npm/ng-packs/packages/components/chart.js/src/chart.component.ts index 670ba01f42..2ac9e1d057 100644 --- a/npm/ng-packs/packages/components/chart.js/src/chart.component.ts +++ b/npm/ng-packs/packages/components/chart.js/src/chart.component.ts @@ -88,7 +88,7 @@ export class ChartComponent implements AfterViewInit, OnDestroy, OnChanges { } } - initChart = () => { + private initChart = () => { const opts = this.options || {}; opts.responsive = this.responsive; diff --git a/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/extensible-table/extensible-table.component.html b/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/extensible-table/extensible-table.component.html index 4544d1022a..83314c22f2 100644 --- a/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/extensible-table/extensible-table.component.html +++ b/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/extensible-table/extensible-table.component.html @@ -25,14 +25,24 @@ > -
+ +
+
+ + +
diff --git a/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/extensible-table/extensible-table.component.ts b/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/extensible-table/extensible-table.component.ts index 1c1757a410..8e1d2752be 100644 --- a/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/extensible-table/extensible-table.component.ts +++ b/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/extensible-table/extensible-table.component.ts @@ -1,4 +1,5 @@ import { + ABP, ConfigStateService, getShortDateFormat, getShortDateShortTimeFormat, @@ -29,7 +30,8 @@ import { EntityActionList } from '../../models/entity-actions'; import { EntityProp, EntityPropList } from '../../models/entity-props'; import { PropData } from '../../models/props'; import { ExtensionsService } from '../../services/extensions.service'; -import { EXTENSIONS_IDENTIFIER } from '../../tokens/extensions.token'; +import { EXTENSIONS_IDENTIFIER, PROP_DATA_STREAM } from '../../tokens/extensions.token'; + const DEFAULT_ACTIONS_COLUMN_WIDTH = 150; @Component({ @@ -71,7 +73,7 @@ export class ExtensibleTableComponent implements OnChanges { constructor( @Inject(LOCALE_ID) private locale: string, private config: ConfigStateService, - injector: Injector, + private injector: Injector, ) { this.getInjected = injector.get.bind(injector); const extensions = injector.get(ExtensionsService); @@ -106,6 +108,12 @@ export class ExtensibleTableComponent implements OnChanges { : '
'; } + private getEnum(rowValue: any, list: Array>) { + if (!list) return rowValue; + const { key } = list.find(({ value }) => value === rowValue); + return key; + } + getContent(prop: EntityProp, data: PropData): Observable { return prop.valueResolver(data).pipe( map(value => { @@ -118,6 +126,8 @@ export class ExtensibleTableComponent implements OnChanges { return this.getDate(value, getShortTimeFormat(this.config)); case ePropType.DateTime: return this.getDate(value, getShortDateShortTimeFormat(this.config)); + case ePropType.Enum: + return this.getEnum(value, prop.enumList); default: return value; // More types can be handled in the future @@ -132,10 +142,26 @@ export class ExtensibleTableComponent implements OnChanges { this.data = data.currentValue.map((record, index) => { this.propList.forEach(prop => { const propData = { getInjected: this.getInjected, record, index } as any; - record[`_${prop.value.name}`] = { + const value = this.getContent(prop.value, propData); + + const propKey = `_${prop.value.name}`; + record[propKey] = { visible: prop.value.visible(propData), - value: this.getContent(prop.value, propData), + value, }; + if (prop.value.component) { + const injector = Injector.create( + [ + { + provide: PROP_DATA_STREAM, + useValue: value, + }, + ], + this.injector, + ); + record[propKey].injector = injector; + record[propKey].component = prop.value.component; + } }); return record; diff --git a/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/entity-props.ts b/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/entity-props.ts index 1342480cd8..fad8c29ade 100644 --- a/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/entity-props.ts +++ b/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/entity-props.ts @@ -1,6 +1,7 @@ import { Type } from '@angular/core'; import { Observable, of } from 'rxjs'; import { O } from 'ts-toolbelt'; +import { ABP } from '@abp/ng.core'; import { ActionCallback } from './actions'; import { Prop, @@ -27,6 +28,8 @@ export class EntityProp extends Prop { readonly sortable: boolean; readonly valueResolver: PropCallback>; readonly action: ActionCallback; + readonly component: Type; + readonly enumList: Array>; constructor(options: EntityPropOptions) { super( @@ -42,6 +45,8 @@ export class EntityProp extends Prop { this.sortable = options.sortable || false; this.valueResolver = options.valueResolver || (data => of(data.record[this.name])); this.action = options.action; + this.component = options.component; + this.enumList = options.enumList; } static create(options: EntityPropOptions) { @@ -63,6 +68,8 @@ export type EntityPropOptions = O.Optional< | 'sortable' | 'valueResolver' | 'action' + | 'component' + | 'enumList' >; export type EntityPropDefaults = Record[]>; diff --git a/npm/ng-packs/packages/theme-shared/extensions/src/lib/tokens/extensions.token.ts b/npm/ng-packs/packages/theme-shared/extensions/src/lib/tokens/extensions.token.ts index ba504756aa..f0343169c1 100644 --- a/npm/ng-packs/packages/theme-shared/extensions/src/lib/tokens/extensions.token.ts +++ b/npm/ng-packs/packages/theme-shared/extensions/src/lib/tokens/extensions.token.ts @@ -1,6 +1,7 @@ import { InjectionToken } from '@angular/core'; import { ActionCallback, ReadonlyActionData as ActionData } from '../models/actions'; import { ExtensionsService } from '../services/extensions.service'; +import { Observable } from 'rxjs'; export const EXTENSIONS_IDENTIFIER = new InjectionToken('EXTENSIONS_IDENTIFIER'); export type ActionKeys = Extract<'entityActions' | 'toolbarActions', keyof ExtensionsService>; @@ -11,3 +12,4 @@ export const EXTENSIONS_ACTION_DATA = new InjectionToken('EXTENSIONS export const EXTENSIONS_ACTION_CALLBACK = new InjectionToken>( 'EXTENSIONS_ACTION_DATA', ); +export const PROP_DATA_STREAM = new InjectionToken>('PROP_DATA_STREAM'); diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/breadcrumb-items/breadcrumb-items.component.html b/npm/ng-packs/packages/theme-shared/src/lib/components/breadcrumb-items/breadcrumb-items.component.html new file mode 100644 index 0000000000..b4c45b7a17 --- /dev/null +++ b/npm/ng-packs/packages/theme-shared/src/lib/components/breadcrumb-items/breadcrumb-items.component.html @@ -0,0 +1,23 @@ + + + + {{ item.name | abpLocalization }} + + + + {{ item.name | abpLocalization }} + diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/breadcrumb-items/breadcrumb-items.component.ts b/npm/ng-packs/packages/theme-shared/src/lib/components/breadcrumb-items/breadcrumb-items.component.ts new file mode 100644 index 0000000000..1bba2e9ece --- /dev/null +++ b/npm/ng-packs/packages/theme-shared/src/lib/components/breadcrumb-items/breadcrumb-items.component.ts @@ -0,0 +1,9 @@ +import { Component, Input } from '@angular/core'; + +@Component({ + selector: 'abp-breadcrumb-items', + templateUrl: './breadcrumb-items.component.html', +}) +export class BreadcrumbItemsComponent { + @Input() items = []; +} diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/breadcrumb/breadcrumb.component.html b/npm/ng-packs/packages/theme-shared/src/lib/components/breadcrumb/breadcrumb.component.html index da17512ea1..b23fdc598e 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/components/breadcrumb/breadcrumb.component.html +++ b/npm/ng-packs/packages/theme-shared/src/lib/components/breadcrumb/breadcrumb.component.html @@ -1,13 +1 @@ - + diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/breadcrumb/breadcrumb.component.ts b/npm/ng-packs/packages/theme-shared/src/lib/components/breadcrumb/breadcrumb.component.ts index 69a5c81af2..68ac0212ff 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/components/breadcrumb/breadcrumb.component.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/components/breadcrumb/breadcrumb.component.ts @@ -1,11 +1,4 @@ -import { - ABP, - getRoutePath, - RouterEvents, - RoutesService, - SubscriptionService, - TreeNode, -} from '@abp/ng.core'; +import { ABP, getRoutePath, RouterEvents, RoutesService, SubscriptionService, TreeNode } from '@abp/ng.core'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit } from '@angular/core'; import { Router } from '@angular/router'; import { map, startWith } from 'rxjs/operators'; @@ -41,7 +34,7 @@ export class BreadcrumbComponent implements OnInit { while (node.parent) { node = node.parent; - const { parent, children, isLeaf, ...segment } = node; + const { parent, children, isLeaf, path, ...segment } = node; if (!isAdministration(segment)) this.segments.unshift(segment); } @@ -52,6 +45,6 @@ export class BreadcrumbComponent implements OnInit { } } -function isAdministration(route: ABP.Route) { +function isAdministration(route: Pick) { return route.name === eThemeSharedRouteNames.Administration; } diff --git a/npm/ng-packs/packages/theme-shared/src/lib/theme-shared.module.ts b/npm/ng-packs/packages/theme-shared/src/lib/theme-shared.module.ts index 8575e834ed..0dcbb525db 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/theme-shared.module.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/theme-shared.module.ts @@ -11,6 +11,7 @@ import { } from '@ngx-validate/core'; import { NgxDatatableModule } from '@swimlane/ngx-datatable'; import { BreadcrumbComponent } from './components/breadcrumb/breadcrumb.component'; +import { BreadcrumbItemsComponent } from './components/breadcrumb-items/breadcrumb-items.component'; import { ButtonComponent } from './components/button/button.component'; import { ConfirmationComponent } from './components/confirmation/confirmation.component'; import { HttpErrorWrapperComponent } from './components/http-error-wrapper/http-error-wrapper.component'; @@ -36,6 +37,7 @@ import { DateParserFormatter } from './utils/date-parser-formatter'; const declarationsWithExports = [ BreadcrumbComponent, + BreadcrumbItemsComponent, ButtonComponent, ConfirmationComponent, LoaderBarComponent, diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi/Controllers/MyProjectNameController.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi/Controllers/MyProjectNameController.cs index 7fff0ecbc5..346f27f7a3 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi/Controllers/MyProjectNameController.cs +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi/Controllers/MyProjectNameController.cs @@ -5,7 +5,7 @@ namespace MyCompanyName.MyProjectName.Controllers { /* Inherit your controllers from this class. */ - public abstract class MyProjectNameController : AbpController + public abstract class MyProjectNameController : AbpControllerBase { protected MyProjectNameController() { diff --git a/templates/module/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi/MyProjectNameController.cs b/templates/module/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi/MyProjectNameController.cs index 1dd9a6c8b2..699cc3df56 100644 --- a/templates/module/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi/MyProjectNameController.cs +++ b/templates/module/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi/MyProjectNameController.cs @@ -3,7 +3,7 @@ using Volo.Abp.AspNetCore.Mvc; namespace MyCompanyName.MyProjectName { - public abstract class MyProjectNameController : AbpController + public abstract class MyProjectNameController : AbpControllerBase { protected MyProjectNameController() {