(tickerFunctionContext, request);
await service.CleanupLogsAsync(genericContext, cancellationToken);
})));
diff --git a/docs/en/framework/ui/angular/hybrid-localization.md b/docs/en/framework/ui/angular/hybrid-localization.md
new file mode 100644
index 0000000000..f71025237c
--- /dev/null
+++ b/docs/en/framework/ui/angular/hybrid-localization.md
@@ -0,0 +1,162 @@
+```json
+//[doc-seo]
+{
+ "Description": "Combine backend and UI localizations in Angular: use JSON files to override or extend server-sidtexts with the same key format and abpLocalization pipe."
+}
+```
+
+# Hybrid Localization
+
+Hybrid localization lets you combine **backend localizations** (from the ABP server) with **UI localizations** (JSON files in your Angular app). UI values take priority over backend values for the same key, so you can override or extend server-side texts without changing the backend.
+
+## How It Works
+
+- **Backend localizations**: Loaded from the server (e.g. `ApplicationLocalizationResourceDto`). Keys use the format `ResourceName::Key`.
+- **UI localizations**: Loaded from static JSON files under your app's assets (e.g. `/assets/localization/en.json`). The same key format `ResourceName::Key` is used.
+- **Priority**: When a key exists in both backend and UI, the **UI value is used** (UI overrides backend).
+
+The existing `abpLocalization` pipe and localization APIs work unchanged; they resolve keys from the merged set (backend + UI), with UI winning on conflicts.
+
+## Configuration
+
+Enable hybrid localization in your app config via `provideAbpCore` and `withOptions`:
+
+```typescript
+// app.config.ts
+import { provideAbpCore, withOptions } from "@abp/ng.core";
+
+export const appConfig: ApplicationConfig = {
+ providers: [
+ provideAbpCore(
+ withOptions({
+ // ...other options
+ uiLocalization: {
+ enabled: true,
+ basePath: "/assets/localization", // optional; default is '/assets/localization'
+ },
+ }),
+ ),
+ // ...
+ ],
+};
+```
+
+| Option | Description | Default |
+| ---------- | ---------------------------------------------------------------------------- | ------------------------ |
+| `enabled` | Turn on UI localization loading from `{basePath}/{culture}.json`. | — |
+| `basePath` | Base path for JSON files. Files are loaded from `{basePath}/{culture}.json`. | `'/assets/localization'` |
+
+When `enabled` is `true`, the app loads a JSON file for the current language (e.g. `en`, `tr`) whenever the user changes language. Loaded data is merged with backend localizations (UI overrides backend for the same key).
+
+## UI Localization File Format
+
+Place one JSON file per culture under your `basePath`. File name must be `{culture}.json` (e.g. `en.json`, `tr.json`).
+
+Structure: **resource name → key → value**.
+
+```json
+{
+ "MyProjectName": {
+ "Welcome": "Welcome from UI (en.json)",
+ "CustomKey": "This is a UI-only localization",
+ "TestMessage": "UI localization is working!"
+ },
+ "AbpAccount": {
+ "Login": "Sign In (UI Override)"
+ }
+}
+```
+
+- Top-level keys are **resource names** (e.g. `MyProjectName`, `AbpAccount`).
+- Nested keys are **localization keys**; values are the display strings for that culture.
+
+In templates you keep using the same key format: `ResourceName::Key`.
+
+## Using in Templates
+
+Use the `abpLocalization` pipe as usual. Keys can come from backend only, UI only, or both (UI wins):
+
+```html
+
+{%{{ 'MyProjectName::Welcome' | abpLocalization }}%}
+
+
+{%{{ 'MyProjectName::CustomKey' | abpLocalization }}%}
+
+
+{%{{ 'AbpAccount::Login' | abpLocalization }}%}
+```
+
+No template changes are needed; only the configuration and the JSON files.
+
+## UILocalizationService
+
+The `UILocalizationService` (`@abp/ng.core`) manages UI localizations and merges them with backend data.
+
+### Get loaded UI data
+
+To inspect what was loaded from the UI JSON files (e.g. for debugging or display):
+
+```typescript
+import { UILocalizationService, SessionStateService } from "@abp/ng.core";
+
+export class MyComponent {
+ private uiLocalizationService = inject(UILocalizationService);
+ private sessionState = inject(SessionStateService);
+
+ currentLanguage$ = this.sessionState.getLanguage$();
+
+ ngOnInit() {
+ // All loaded UI resources for current language
+ const loaded = this.uiLocalizationService.getLoadedLocalizations();
+ // Or for a specific culture
+ const loadedEn = this.uiLocalizationService.getLoadedLocalizations("en");
+ }
+}
+```
+
+`getLoadedLocalizations(culture?: string)` returns an object of the form `{ [resourceName: string]: Record }` for the given culture (or current language if omitted).
+
+### Add translations at runtime
+
+You can also add or merge UI translations programmatically (e.g. from another source or lazy-loaded module):
+
+```typescript
+this.uiLocalizationService.addAngularLocalizeLocalization(
+ 'en', // culture
+ 'MyProjectName', // resource name
+ { MyKey: 'My value' }, // key-value map
+);
+```
+
+This merges into the existing UI localizations and is taken into account by the `abpLocalization` pipe with the same UI-over-backend priority.
+
+## Example: Dev App
+
+The ABP dev app demonstrates hybrid localization:
+
+1. **Config** (`app.config.ts`):
+
+```typescript
+uiLocalization: {
+ enabled: true,
+ basePath: '/assets/localization',
+},
+```
+
+2. **Files**: `src/assets/localization/en.json` and `src/assets/localization/tr.json` with the structure shown above.
+
+3. **Component** (`localization-test.component.ts`): Uses `abpLocalization` for backend keys, UI-only keys, and overrides; and uses `UILocalizationService.getLoadedLocalizations()` to show loaded UI data.
+
+See `apps/dev-app/src/app/localization-test/localization-test.component.ts` and `apps/dev-app/src/assets/localization/*.json` in the repository for the full example.
+
+## Summary
+
+| Topic | Description |
+|------------------|-------------|
+| **Purpose** | Combine backend and UI localizations; UI overrides backend for the same key. |
+| **Config** | `provideAbpCore(withOptions({ uiLocalization: { enabled: true, basePath?: string } }))`. |
+| **File location**| `{basePath}/{culture}.json` (e.g. `/assets/localization/en.json`). |
+| **JSON format** | `{ "ResourceName": { "Key": "Value", ... }, ... }`. |
+| **Template usage** | Same as before: `{%{{ 'ResourceName::Key' \| abpLocalization }}%}`. |
+| **API** | `UILocalizationService`: `getLoadedLocalizations(culture?)`, `addAngularLocalizeLocalization(culture, resourceName, translations)`. |
diff --git a/docs/en/package-version-changes.md b/docs/en/package-version-changes.md
index c4d8b0722f..bb31239a3c 100644
--- a/docs/en/package-version-changes.md
+++ b/docs/en/package-version-changes.md
@@ -8,6 +8,10 @@
| Blazorise.Components | 1.8.8 | 2.0.0 | #24906 |
| Blazorise.DataGrid | 1.8.8 | 2.0.0 | #24906 |
| Blazorise.Snackbar | 1.8.8 | 2.0.0 | #24906 |
+| TickerQ | 2.5.3 | 10.1.1 | #24916 |
+| TickerQ.Dashboard | 2.5.3 | 10.1.1 | #24916 |
+| TickerQ.EntityFrameworkCore | 2.5.3 | 10.1.1 | #24916 |
+| TickerQ.Utilities | 2.5.3 | 10.1.1 | #24916 |
## 10.1.0
@@ -15,4 +19,3 @@
|---------|-------------|-------------|-----|
| Microsoft.SemanticKernel | 1.67.1 | 1.71.0 | #24891 |
| Microsoft.SemanticKernel.Abstractions | 1.67.1 | 1.71.0 | #24891 |
-
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/ClientProxies/AbpApplicationConfigurationClientProxy.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/ClientProxies/AbpApplicationConfigurationClientProxy.cs
index 62b582b01b..8b2001a17f 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/ClientProxies/AbpApplicationConfigurationClientProxy.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/ClientProxies/AbpApplicationConfigurationClientProxy.cs
@@ -1,12 +1,9 @@
// This file is part of AbpApplicationConfigurationClientProxy, you can customize it here
// ReSharper disable once CheckNamespace
-using Volo.Abp.DependencyInjection;
-
namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ClientProxies;
[RemoteService(false)]
-[DisableConventionalRegistration]
public partial class AbpApplicationConfigurationClientProxy
{
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/ClientProxies/AbpTenantClientProxy.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/ClientProxies/AbpTenantClientProxy.cs
index 8ca24d1317..f8bf2389e0 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/ClientProxies/AbpTenantClientProxy.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/ClientProxies/AbpTenantClientProxy.cs
@@ -2,13 +2,10 @@
// ReSharper disable once CheckNamespace
using Volo.Abp;
-using Volo.Abp.DependencyInjection;
namespace Pages.Abp.MultiTenancy.ClientProxies;
[RemoteService(false)]
-[DisableConventionalRegistration]
public partial class AbpTenantClientProxy
{
}
-
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/AbpAspNetCoreMvcClientCommonModule.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/AbpAspNetCoreMvcClientCommonModule.cs
index b7cd9d3a30..a9ab95cbc0 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/AbpAspNetCoreMvcClientCommonModule.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/AbpAspNetCoreMvcClientCommonModule.cs
@@ -1,6 +1,4 @@
using Microsoft.Extensions.DependencyInjection;
-using Pages.Abp.MultiTenancy.ClientProxies;
-using Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ClientProxies;
using Volo.Abp.Authorization;
using Volo.Abp.Caching;
using Volo.Abp.Features;
@@ -39,9 +37,6 @@ public class AbpAspNetCoreMvcClientCommonModule : AbpModule
options.GlobalContributors.Add();
});
- context.Services.AddTransient();
- context.Services.AddTransient();
-
var abpClaimsPrincipalFactoryOptions = context.Services.ExecutePreConfiguredActions();
if (abpClaimsPrincipalFactoryOptions.IsRemoteRefreshEnabled)
{
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationScriptController.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationScriptController.cs
index de38e89104..8910ce1ce7 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationScriptController.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationScriptController.cs
@@ -17,14 +17,14 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations;
[ApiExplorerSettings(IgnoreApi = true)]
public class AbpApplicationConfigurationScriptController : AbpController
{
- protected readonly AbpApplicationConfigurationAppService ConfigurationAppService;
+ protected readonly IAbpApplicationConfigurationAppService ConfigurationAppService;
protected readonly IJsonSerializer JsonSerializer;
protected readonly AbpAspNetCoreMvcOptions Options;
protected readonly IJavascriptMinifier JavascriptMinifier;
protected readonly IAbpAntiForgeryManager AntiForgeryManager;
public AbpApplicationConfigurationScriptController(
- AbpApplicationConfigurationAppService configurationAppService,
+ IAbpApplicationConfigurationAppService configurationAppService,
IJsonSerializer jsonSerializer,
IOptions options,
IJavascriptMinifier javascriptMinifier,
diff --git a/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Builder/AbpApplicationBuilderExtensions.cs b/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Builder/AbpApplicationBuilderExtensions.cs
index 3a283cbe36..aab5b5cc2b 100644
--- a/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Builder/AbpApplicationBuilderExtensions.cs
+++ b/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Builder/AbpApplicationBuilderExtensions.cs
@@ -38,6 +38,18 @@ public static class AbpApplicationBuilderExtensions
Check.NotNull(app, nameof(app));
app.ApplicationServices.GetRequiredService>().Value = app;
+ if (app is WebApplication webApplication)
+ {
+ app.ApplicationServices.GetRequiredService>().Value = webApplication;
+ }
+ if (app is IHost host)
+ {
+ app.ApplicationServices.GetRequiredService>().Value = host;
+ }
+ if (app is IEndpointRouteBuilder endpointRouteBuilder)
+ {
+ app.ApplicationServices.GetRequiredService>().Value = endpointRouteBuilder;
+ }
var application = app.ApplicationServices.GetRequiredService();
var applicationLifetime = app.ApplicationServices.GetRequiredService();
@@ -59,6 +71,18 @@ public static class AbpApplicationBuilderExtensions
Check.NotNull(app, nameof(app));
app.ApplicationServices.GetRequiredService>().Value = app;
+ if (app is WebApplication webApplication)
+ {
+ app.ApplicationServices.GetRequiredService>().Value = webApplication;
+ }
+ if (app is IHost host)
+ {
+ app.ApplicationServices.GetRequiredService>().Value = host;
+ }
+ if (app is IEndpointRouteBuilder endpointRouteBuilder)
+ {
+ app.ApplicationServices.GetRequiredService>().Value = endpointRouteBuilder;
+ }
var application = app.ApplicationServices.GetRequiredService();
var applicationLifetime = app.ApplicationServices.GetRequiredService();
diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/ApplicationInitializationContextExtensions.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/ApplicationInitializationContextExtensions.cs
index 1e361d1587..930b081df0 100644
--- a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/ApplicationInitializationContextExtensions.cs
+++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/ApplicationInitializationContextExtensions.cs
@@ -1,7 +1,9 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Volo.Abp.DependencyInjection;
@@ -21,6 +23,42 @@ public static class ApplicationInitializationContextExtensions
return context.ServiceProvider.GetRequiredService>().Value;
}
+ public static IHost GetHost(this ApplicationInitializationContext context)
+ {
+ var host = context.ServiceProvider.GetRequiredService>().Value;
+ Check.NotNull(host, nameof(host));
+ return host;
+ }
+
+ public static IHost? GetHostOrNull(this ApplicationInitializationContext context)
+ {
+ return context.ServiceProvider.GetRequiredService>().Value;
+ }
+
+ public static IEndpointRouteBuilder GetEndpointRouteBuilder(this ApplicationInitializationContext context)
+ {
+ var endpointRouteBuilder = context.ServiceProvider.GetRequiredService>().Value;
+ Check.NotNull(endpointRouteBuilder, nameof(endpointRouteBuilder));
+ return endpointRouteBuilder;
+ }
+
+ public static IEndpointRouteBuilder? GetEndpointRouteBuilderOrNull(this ApplicationInitializationContext context)
+ {
+ return context.ServiceProvider.GetRequiredService>().Value;
+ }
+
+ public static WebApplication GetWebApplication(this ApplicationInitializationContext context)
+ {
+ var webApplication = context.ServiceProvider.GetRequiredService>().Value;
+ Check.NotNull(webApplication, nameof(webApplication));
+ return webApplication;
+ }
+
+ public static WebApplication? GetWebApplicationOrNull(this ApplicationInitializationContext context)
+ {
+ return context.ServiceProvider.GetRequiredService>().Value;
+ }
+
public static IWebHostEnvironment GetEnvironment(this ApplicationInitializationContext context)
{
return context.ServiceProvider.GetRequiredService();
diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/AbpAspNetCoreModule.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/AbpAspNetCoreModule.cs
index 405e49753c..a457d3b1eb 100644
--- a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/AbpAspNetCoreModule.cs
+++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/AbpAspNetCoreModule.cs
@@ -2,7 +2,9 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting.StaticWebAssets;
using Microsoft.AspNetCore.RequestLocalization;
+using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.FileProviders;
using MyCSharp.HttpUserAgentParser.DependencyInjection;
using Volo.Abp.AspNetCore.Auditing;
@@ -57,6 +59,9 @@ public class AbpAspNetCoreModule : AbpModule
AddAspNetServices(context.Services);
context.Services.AddObjectAccessor();
+ context.Services.AddObjectAccessor();
+ context.Services.AddObjectAccessor();
+ context.Services.AddObjectAccessor();
context.Services.AddAbpDynamicOptions();
StaticWebAssetsLoader.UseStaticWebAssets(context.Services.GetHostingEnvironment(), context.Services.GetConfiguration());
diff --git a/framework/src/Volo.Abp.BackgroundJobs.TickerQ/Volo.Abp.BackgroundJobs.TickerQ.csproj b/framework/src/Volo.Abp.BackgroundJobs.TickerQ/Volo.Abp.BackgroundJobs.TickerQ.csproj
index df450f5ff6..41d70914a4 100644
--- a/framework/src/Volo.Abp.BackgroundJobs.TickerQ/Volo.Abp.BackgroundJobs.TickerQ.csproj
+++ b/framework/src/Volo.Abp.BackgroundJobs.TickerQ/Volo.Abp.BackgroundJobs.TickerQ.csproj
@@ -4,7 +4,7 @@
- netstandard2.1;net8.0;net9.0;net10.0
+ net10.0
enable
Nullable
Volo.Abp.BackgroundJobs.TickerQ
diff --git a/framework/src/Volo.Abp.BackgroundJobs.TickerQ/Volo/Abp/BackgroundJobs/TickerQ/AbpBackgroundJobsTickerQModule.cs b/framework/src/Volo.Abp.BackgroundJobs.TickerQ/Volo/Abp/BackgroundJobs/TickerQ/AbpBackgroundJobsTickerQModule.cs
index b5ed598932..3d93fc68a1 100644
--- a/framework/src/Volo.Abp.BackgroundJobs.TickerQ/Volo/Abp/BackgroundJobs/TickerQ/AbpBackgroundJobsTickerQModule.cs
+++ b/framework/src/Volo.Abp.BackgroundJobs.TickerQ/Volo/Abp/BackgroundJobs/TickerQ/AbpBackgroundJobsTickerQModule.cs
@@ -65,7 +65,7 @@ public class AbpBackgroundJobsTickerQModule : AbpModule
using (var scope = serviceProvider.CreateScope())
{
var jobExecuter = serviceProvider.GetRequiredService();
- var args = await TickerRequestProvider.GetRequestAsync(serviceProvider, context.Id, context.Type);
+ var args = await TickerRequestProvider.GetRequestAsync(context, cancellationToken);
var jobType = options.GetJob(typeof(TArgs)).JobType;
var jobExecutionContext = new JobExecutionContext(scope.ServiceProvider, jobType, args!, cancellationToken: cancellationToken);
await jobExecuter.ExecuteAsync(jobExecutionContext);
diff --git a/framework/src/Volo.Abp.BackgroundJobs.TickerQ/Volo/Abp/BackgroundJobs/TickerQ/AbpBackgroundJobsTimeTickerConfiguration.cs b/framework/src/Volo.Abp.BackgroundJobs.TickerQ/Volo/Abp/BackgroundJobs/TickerQ/AbpBackgroundJobsTimeTickerConfiguration.cs
index 65b150ea48..ecceaeb28a 100644
--- a/framework/src/Volo.Abp.BackgroundJobs.TickerQ/Volo/Abp/BackgroundJobs/TickerQ/AbpBackgroundJobsTimeTickerConfiguration.cs
+++ b/framework/src/Volo.Abp.BackgroundJobs.TickerQ/Volo/Abp/BackgroundJobs/TickerQ/AbpBackgroundJobsTimeTickerConfiguration.cs
@@ -1,4 +1,3 @@
-using System;
using TickerQ.Utilities.Enums;
namespace Volo.Abp.BackgroundJobs.TickerQ;
@@ -11,7 +10,5 @@ public class AbpBackgroundJobsTimeTickerConfiguration
public TickerTaskPriority? Priority { get; set; }
- public Guid? BatchParent { get; set; }
-
- public BatchRunCondition? BatchRunCondition { get; set; }
+ public RunCondition? RunCondition { get; set; }
}
diff --git a/framework/src/Volo.Abp.BackgroundJobs.TickerQ/Volo/Abp/BackgroundJobs/TickerQ/AbpTickerQBackgroundJobManager.cs b/framework/src/Volo.Abp.BackgroundJobs.TickerQ/Volo/Abp/BackgroundJobs/TickerQ/AbpTickerQBackgroundJobManager.cs
index b1a2dbe36d..638c1845f2 100644
--- a/framework/src/Volo.Abp.BackgroundJobs.TickerQ/Volo/Abp/BackgroundJobs/TickerQ/AbpTickerQBackgroundJobManager.cs
+++ b/framework/src/Volo.Abp.BackgroundJobs.TickerQ/Volo/Abp/BackgroundJobs/TickerQ/AbpTickerQBackgroundJobManager.cs
@@ -2,8 +2,8 @@
using System.Threading.Tasks;
using Microsoft.Extensions.Options;
using TickerQ.Utilities;
+using TickerQ.Utilities.Entities;
using TickerQ.Utilities.Interfaces.Managers;
-using TickerQ.Utilities.Models.Ticker;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.BackgroundJobs.TickerQ;
@@ -11,12 +11,12 @@ namespace Volo.Abp.BackgroundJobs.TickerQ;
[Dependency(ReplaceServices = true)]
public class AbpTickerQBackgroundJobManager : IBackgroundJobManager, ITransientDependency
{
- protected ITimeTickerManager TimeTickerManager { get; }
+ protected ITimeTickerManager TimeTickerManager { get; }
protected AbpBackgroundJobOptions Options { get; }
protected AbpBackgroundJobsTickerQOptions TickerQOptions { get; }
public AbpTickerQBackgroundJobManager(
- ITimeTickerManager timeTickerManager,
+ ITimeTickerManager timeTickerManager,
IOptions options,
IOptions tickerQOptions)
{
@@ -28,7 +28,7 @@ public class AbpTickerQBackgroundJobManager : IBackgroundJobManager, ITransientD
public virtual async Task EnqueueAsync(TArgs args, BackgroundJobPriority priority = BackgroundJobPriority.Normal, TimeSpan? delay = null)
{
var job = Options.GetJob(typeof(TArgs));
- var timeTicker = new TimeTicker
+ var timeTicker = new TimeTickerEntity
{
Id = Guid.NewGuid(),
Function = job.JobName,
@@ -41,11 +41,10 @@ public class AbpTickerQBackgroundJobManager : IBackgroundJobManager, ITransientD
{
timeTicker.Retries = config.Retries ?? timeTicker.Retries;
timeTicker.RetryIntervals = config.RetryIntervals ?? timeTicker.RetryIntervals;
- timeTicker.BatchParent = config.BatchParent ?? timeTicker.BatchParent;
- timeTicker.BatchRunCondition = config.BatchRunCondition ?? timeTicker.BatchRunCondition;
+ timeTicker.RunCondition = config.RunCondition ?? timeTicker.RunCondition;
}
var result = await TimeTickerManager.AddAsync(timeTicker);
- return !result.IsSucceded ? timeTicker.Id.ToString() : result.Result.Id.ToString();
+ return !result.IsSucceeded ? timeTicker.Id.ToString() : result.Result.Id.ToString();
}
}
diff --git a/framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo.Abp.BackgroundWorkers.TickerQ.csproj b/framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo.Abp.BackgroundWorkers.TickerQ.csproj
index 2c4ab29c97..b62024131d 100644
--- a/framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo.Abp.BackgroundWorkers.TickerQ.csproj
+++ b/framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo.Abp.BackgroundWorkers.TickerQ.csproj
@@ -4,7 +4,7 @@
- netstandard2.1;net8.0;net9.0;net10.0
+ net10.0
enable
Nullable
Volo.Abp.BackgroundWorkers.TickerQ
diff --git a/framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo/Abp/BackgroundWorkers/TickerQ/AbpBackgroundWorkersTickerQModule.cs b/framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo/Abp/BackgroundWorkers/TickerQ/AbpBackgroundWorkersTickerQModule.cs
index 3fb15a50b8..788eee1759 100644
--- a/framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo/Abp/BackgroundWorkers/TickerQ/AbpBackgroundWorkersTickerQModule.cs
+++ b/framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo/Abp/BackgroundWorkers/TickerQ/AbpBackgroundWorkersTickerQModule.cs
@@ -1,8 +1,8 @@
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
+using TickerQ.Utilities.Entities;
using TickerQ.Utilities.Interfaces.Managers;
-using TickerQ.Utilities.Models.Ticker;
using Volo.Abp.Modularity;
using Volo.Abp.TickerQ;
@@ -14,11 +14,11 @@ public class AbpBackgroundWorkersTickerQModule : AbpModule
public override async Task OnPostApplicationInitializationAsync(ApplicationInitializationContext context)
{
var abpTickerQBackgroundWorkersProvider = context.ServiceProvider.GetRequiredService();
- var cronTickerManager = context.ServiceProvider.GetRequiredService>();
+ var cronTickerManager = context.ServiceProvider.GetRequiredService>();
var abpBackgroundWorkersTickerQOptions = context.ServiceProvider.GetRequiredService>().Value;
foreach (var backgroundWorker in abpTickerQBackgroundWorkersProvider.BackgroundWorkers)
{
- var cronTicker = new CronTicker
+ var cronTicker = new CronTickerEntity
{
Function = backgroundWorker.Value.Function,
Expression = backgroundWorker.Value.CronExpression
diff --git a/framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo/Abp/BackgroundWorkers/TickerQ/AbpTickerQPeriodicBackgroundWorkerInvoker.cs b/framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo/Abp/BackgroundWorkers/TickerQ/AbpTickerQPeriodicBackgroundWorkerInvoker.cs
index 17cf7cdc87..f09a271017 100644
--- a/framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo/Abp/BackgroundWorkers/TickerQ/AbpTickerQPeriodicBackgroundWorkerInvoker.cs
+++ b/framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo/Abp/BackgroundWorkers/TickerQ/AbpTickerQPeriodicBackgroundWorkerInvoker.cs
@@ -3,7 +3,7 @@ using System.Linq.Expressions;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
-using TickerQ.Utilities.Models;
+using TickerQ.Utilities.Base;
namespace Volo.Abp.BackgroundWorkers.TickerQ;
diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EfCoreRepositoryExtensions.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EfCoreRepositoryExtensions.cs
index 614ba135ff..d054733785 100644
--- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EfCoreRepositoryExtensions.cs
+++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EfCoreRepositoryExtensions.cs
@@ -49,6 +49,6 @@ public static class EfCoreRepositoryExtensions
public static IQueryable AsNoTrackingIf(this IQueryable queryable, bool condition)
where TEntity : class, IEntity
{
- return condition ? queryable.AsNoTracking() : queryable;
+ return condition ? queryable.AsNoTracking() : queryable.AsTracking();
}
}
diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/EfCoreRepository.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/EfCoreRepository.cs
index ff4aeabc44..cf8f994d42 100644
--- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/EfCoreRepository.cs
+++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/EfCoreRepository.cs
@@ -478,9 +478,7 @@ public class EfCoreRepository : EfCoreRepository e.Id).FirstOrDefaultAsync(e => e.Id!.Equals(id), GetCancellationToken(cancellationToken))
- : !ShouldTrackingEntityChange()
- ? await (await GetQueryableAsync()).OrderBy(e => e.Id).FirstOrDefaultAsync(e => e.Id!.Equals(id), GetCancellationToken(cancellationToken))
- : await (await GetDbSetAsync()).FindAsync(new object[] { id! }, GetCancellationToken(cancellationToken));
+ : await (await GetQueryableAsync()).OrderBy(e => e.Id).FirstOrDefaultAsync(e => e.Id!.Equals(id), GetCancellationToken(cancellationToken));
}
public virtual async Task DeleteAsync(TKey id, bool autoSave = false, CancellationToken cancellationToken = default)
diff --git a/framework/src/Volo.Abp.ObjectMapping/Volo/Abp/ObjectMapping/ObjectMappingHelper.cs b/framework/src/Volo.Abp.ObjectMapping/Volo/Abp/ObjectMapping/ObjectMappingHelper.cs
index 5949edaba9..3bc1a1389b 100644
--- a/framework/src/Volo.Abp.ObjectMapping/Volo/Abp/ObjectMapping/ObjectMappingHelper.cs
+++ b/framework/src/Volo.Abp.ObjectMapping/Volo/Abp/ObjectMapping/ObjectMappingHelper.cs
@@ -55,10 +55,17 @@ public static class ObjectMappingHelper
return true;
}
- if (type.IsGenericType &&
- supportedCollectionTypes.Contains(type.GetGenericTypeDefinition()) ||
+ if ((type.IsGenericType &&
+ supportedCollectionTypes.Contains(type.GetGenericTypeDefinition())) ||
type.GetInterfaces().Any(i => i.IsGenericType && supportedCollectionTypes.Contains(i.GetGenericTypeDefinition())))
{
+ if (!type.IsGenericType)
+ {
+ elementType = null!;
+ definitionGenericType = null!;
+ return false;
+ }
+
elementType = type.GetGenericArguments()[0];
definitionGenericType = type.GetGenericTypeDefinition();
if (definitionGenericType == typeof(IEnumerable<>) ||
diff --git a/framework/src/Volo.Abp.Swashbuckle/Microsoft/Extensions/DependencyInjection/AbpSwaggerGenServiceCollectionExtensions.cs b/framework/src/Volo.Abp.Swashbuckle/Microsoft/Extensions/DependencyInjection/AbpSwaggerGenServiceCollectionExtensions.cs
index d63ca833eb..b81aa8bf77 100644
--- a/framework/src/Volo.Abp.Swashbuckle/Microsoft/Extensions/DependencyInjection/AbpSwaggerGenServiceCollectionExtensions.cs
+++ b/framework/src/Volo.Abp.Swashbuckle/Microsoft/Extensions/DependencyInjection/AbpSwaggerGenServiceCollectionExtensions.cs
@@ -77,7 +77,8 @@ public static class AbpSwaggerGenServiceCollectionExtensions
string[]? scopes = null,
string[]? flows = null,
string? discoveryEndpoint = null,
- Action? setupAction = null)
+ Action? setupAction = null,
+ string oidcAuthenticationScheme = "oidc")
{
var discoveryUrl = discoveryEndpoint != null ?
$"{discoveryEndpoint.TrimEnd('/')}/.well-known/openid-configuration":
@@ -96,7 +97,7 @@ public static class AbpSwaggerGenServiceCollectionExtensions
.AddSwaggerGen(
options =>
{
- options.AddSecurityDefinition("oidc", new OpenApiSecurityScheme
+ options.AddSecurityDefinition(oidcAuthenticationScheme, new OpenApiSecurityScheme
{
Type = SecuritySchemeType.OpenIdConnect,
OpenIdConnectUrl = new Uri(RemoveTenantPlaceholders(discoveryUrl))
@@ -104,7 +105,7 @@ public static class AbpSwaggerGenServiceCollectionExtensions
options.AddSecurityRequirement(document => new OpenApiSecurityRequirement()
{
- [new OpenApiSecuritySchemeReference("oauth2", document)] = []
+ [new OpenApiSecuritySchemeReference(oidcAuthenticationScheme, document)] = []
});
setupAction?.Invoke(options);
diff --git a/framework/src/Volo.Abp.TickerQ/Microsoft/AspNetCore/Builder/AbpTickerQApplicationBuilderExtensions.cs b/framework/src/Volo.Abp.TickerQ/Microsoft/Extensions/Hosting/AbpTickerQApplicationBuilderExtensions.cs
similarity index 61%
rename from framework/src/Volo.Abp.TickerQ/Microsoft/AspNetCore/Builder/AbpTickerQApplicationBuilderExtensions.cs
rename to framework/src/Volo.Abp.TickerQ/Microsoft/Extensions/Hosting/AbpTickerQApplicationBuilderExtensions.cs
index 4e81565e99..4d1897b200 100644
--- a/framework/src/Volo.Abp.TickerQ/Microsoft/AspNetCore/Builder/AbpTickerQApplicationBuilderExtensions.cs
+++ b/framework/src/Volo.Abp.TickerQ/Microsoft/Extensions/Hosting/AbpTickerQApplicationBuilderExtensions.cs
@@ -1,16 +1,17 @@
using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
using TickerQ.DependencyInjection;
using TickerQ.Utilities;
using TickerQ.Utilities.Enums;
using Volo.Abp.TickerQ;
-namespace Microsoft.AspNetCore.Builder;
+namespace Microsoft.Extensions.Hosting;
public static class AbpTickerQApplicationBuilderExtensions
{
- public static IApplicationBuilder UseAbpTickerQ(this IApplicationBuilder app, TickerQStartMode qStartMode = TickerQStartMode.Immediate)
+ public static IHost UseAbpTickerQ(this IHost app, TickerQStartMode qStartMode = TickerQStartMode.Immediate)
{
- var abpTickerQFunctionProvider = app.ApplicationServices.GetRequiredService();
+ var abpTickerQFunctionProvider = app.Services.GetRequiredService();
TickerFunctionProvider.RegisterFunctions(abpTickerQFunctionProvider.Functions);
TickerFunctionProvider.RegisterRequestType(abpTickerQFunctionProvider.RequestTypes);
diff --git a/framework/src/Volo.Abp.TickerQ/Volo.Abp.TickerQ.csproj b/framework/src/Volo.Abp.TickerQ/Volo.Abp.TickerQ.csproj
index 89a037bab7..51649a9a86 100644
--- a/framework/src/Volo.Abp.TickerQ/Volo.Abp.TickerQ.csproj
+++ b/framework/src/Volo.Abp.TickerQ/Volo.Abp.TickerQ.csproj
@@ -4,7 +4,7 @@
- netstandard2.1;net8.0;net9.0;net10.0
+ net10.0
enable
Nullable
Volo.Abp.TickerQ
diff --git a/framework/src/Volo.Abp.TickerQ/Volo/Abp/TickerQ/AbpTickerQModule.cs b/framework/src/Volo.Abp.TickerQ/Volo/Abp/TickerQ/AbpTickerQModule.cs
index b6c140e962..82b47294e1 100644
--- a/framework/src/Volo.Abp.TickerQ/Volo/Abp/TickerQ/AbpTickerQModule.cs
+++ b/framework/src/Volo.Abp.TickerQ/Volo/Abp/TickerQ/AbpTickerQModule.cs
@@ -10,7 +10,10 @@ public class AbpTickerQModule : AbpModule
{
context.Services.AddTickerQ(options =>
{
- options.SetInstanceIdentifier(context.Services.GetApplicationName());
+ options.ConfigureScheduler(scheduler =>
+ {
+ scheduler.NodeIdentifier = context.Services.GetApplicationName();
+ });
});
}
}
diff --git a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/ChangeTracking/ChangeTrackingInterceptor_Tests.cs b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/ChangeTracking/ChangeTrackingInterceptor_Tests.cs
index 87b487b68a..9581df3a19 100644
--- a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/ChangeTracking/ChangeTrackingInterceptor_Tests.cs
+++ b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/ChangeTracking/ChangeTrackingInterceptor_Tests.cs
@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
+using Microsoft.EntityFrameworkCore;
using Shouldly;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.ChangeTracking;
@@ -83,6 +84,96 @@ public class ChangeTrackingInterceptor_Tests : TestAppTestBase>();
+
+ Guid personId = default;
+ await WithUnitOfWorkAsync(async () =>
+ {
+ var p = await repository.FindAsync(x => x.Name == "people1");
+ p.ShouldNotBeNull();
+ personId = p.Id;
+ });
+
+ // Simulate global NoTracking configured on DbContext (e.g. optionsBuilder.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking))
+ await WithUnitOfWorkAsync(async () =>
+ {
+ var db = await repository.GetDbContextAsync();
+ db.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
+ db.ChangeTracker.Entries().Count().ShouldBe(0);
+
+ // FindAsync(id): ShouldTrackingEntityChange()=true, GetQueryableAsync() uses AsTracking() to override global NoTracking
+ var person = await repository.FindAsync(personId, includeDetails: false);
+ person.ShouldNotBeNull();
+ db.ChangeTracker.Entries().Count().ShouldBe(1);
+ db.Entry(person).State.ShouldBe(EntityState.Unchanged);
+ });
+
+ await WithUnitOfWorkAsync(async () =>
+ {
+ var db = await repository.GetDbContextAsync();
+ db.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
+ db.ChangeTracker.Entries().Count().ShouldBe(0);
+
+ // FindAsync(predicate): same - AsTracking() overrides global NoTracking
+ var person = await repository.FindAsync(x => x.Name == "people1");
+ person.ShouldNotBeNull();
+ db.ChangeTracker.Entries().Count().ShouldBe(1);
+ db.Entry(person).State.ShouldBe(EntityState.Unchanged);
+ });
+
+ await WithUnitOfWorkAsync(async () =>
+ {
+ var db = await repository.GetDbContextAsync();
+ db.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
+ db.ChangeTracker.Entries().Count().ShouldBe(0);
+
+ // GetListAsync: same - AsTracking() overrides global NoTracking
+ var list = await repository.GetListAsync();
+ list.Count.ShouldBeGreaterThan(0);
+ db.ChangeTracker.Entries().Count().ShouldBe(list.Count);
+ });
+ }
+
+ [Fact]
+ public async Task Repository_Should_Respect_NoTracking_When_EntityChangeTracking_Is_Disabled_With_Global_NoTracking()
+ {
+ await AddSomePeopleAsync();
+
+ var repository = GetRequiredService>();
+
+ Guid personId = default;
+ await WithUnitOfWorkAsync(async () =>
+ {
+ var p = await repository.FindAsync(x => x.Name == "people1");
+ p.ShouldNotBeNull();
+ personId = p.Id;
+ });
+
+ await WithUnitOfWorkAsync(async () =>
+ {
+ var db = await repository.GetDbContextAsync();
+ db.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
+ db.ChangeTracker.Entries().Count().ShouldBe(0);
+
+ // When tracking is explicitly disabled, entity should NOT be tracked regardless of global setting
+ using (repository.DisableTracking())
+ {
+ var person = await repository.FindAsync(personId, includeDetails: false);
+ person.ShouldNotBeNull();
+ db.ChangeTracker.Entries().Count().ShouldBe(0);
+
+ var list = await repository.GetListAsync();
+ list.Count.ShouldBeGreaterThan(0);
+ db.ChangeTracker.Entries().Count().ShouldBe(0);
+ }
+ });
+ }
+
private async Task AddSomePeopleAsync()
{
var repository = GetRequiredService>();
diff --git a/framework/test/Volo.Abp.ObjectMapping.Tests/Volo/Abp/ObjectMapping/ObjectMappingHelper_Tests.cs b/framework/test/Volo.Abp.ObjectMapping.Tests/Volo/Abp/ObjectMapping/ObjectMappingHelper_Tests.cs
new file mode 100644
index 0000000000..c262dad81a
--- /dev/null
+++ b/framework/test/Volo.Abp.ObjectMapping.Tests/Volo/Abp/ObjectMapping/ObjectMappingHelper_Tests.cs
@@ -0,0 +1,84 @@
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using Shouldly;
+using Xunit;
+
+namespace Volo.Abp.ObjectMapping;
+
+public class ObjectMappingHelper_Tests
+{
+ [Fact]
+ public void IsCollectionGenericType_Should_Return_True_For_Standard_GenericCollection()
+ {
+ var result = ObjectMappingHelper.IsCollectionGenericType, List>(
+ out var sourceArg, out var destArg, out var defGenericType);
+
+ result.ShouldBeTrue();
+ sourceArg.ShouldBe(typeof(MappingTestSource));
+ destArg.ShouldBe(typeof(MappingTestDestination));
+ defGenericType.ShouldBe(typeof(List<>));
+ }
+
+ [Fact]
+ public void IsCollectionGenericType_Should_Return_True_For_Array()
+ {
+ var result = ObjectMappingHelper.IsCollectionGenericType(
+ out var sourceArg, out var destArg, out _);
+
+ result.ShouldBeTrue();
+ sourceArg.ShouldBe(typeof(MappingTestSource));
+ destArg.ShouldBe(typeof(MappingTestDestination));
+ }
+
+ [Fact]
+ public void IsCollectionGenericType_Should_Normalize_IEnumerable_To_List()
+ {
+ var result = ObjectMappingHelper.IsCollectionGenericType, IEnumerable>(
+ out _, out _, out var defGenericType);
+
+ result.ShouldBeTrue();
+ defGenericType.ShouldBe(typeof(List<>));
+ }
+
+ [Fact]
+ public void IsCollectionGenericType_Should_Normalize_ICollection_To_Collection()
+ {
+ var result = ObjectMappingHelper.IsCollectionGenericType, ICollection>(
+ out _, out _, out var defGenericType);
+
+ result.ShouldBeTrue();
+ defGenericType.ShouldBe(typeof(Collection<>));
+ }
+
+ [Fact]
+ public void IsCollectionGenericType_Should_Return_False_For_NonCollection()
+ {
+ var result = ObjectMappingHelper.IsCollectionGenericType(
+ out _, out _, out _);
+
+ result.ShouldBeFalse();
+ }
+
+ [Fact]
+ public void IsCollectionGenericType_Should_Return_False_For_NonGeneric_DerivedCollection()
+ {
+ var result = ObjectMappingHelper.IsCollectionGenericType, MappingTestDestinationList>(
+ out _, out _, out _);
+
+ result.ShouldBeFalse();
+ }
+}
+
+public class MappingTestSource
+{
+ public string Value { get; set; } = "";
+}
+
+public class MappingTestDestination
+{
+ public string Value { get; set; } = "";
+}
+
+public class MappingTestDestinationList : List
+{
+}
diff --git a/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.TickerQ/CleanupJobs.cs b/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.TickerQ/CleanupJobs.cs
index 6eca55e09f..3b9da774ae 100644
--- a/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.TickerQ/CleanupJobs.cs
+++ b/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.TickerQ/CleanupJobs.cs
@@ -1,7 +1,7 @@
using System;
using System.Threading;
using System.Threading.Tasks;
-using TickerQ.Utilities.Models;
+using TickerQ.Utilities.Base;
namespace Volo.Abp.BackgroundJobs.DemoApp.TickerQ;
diff --git a/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.TickerQ/DemoAppTickerQModule.cs b/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.TickerQ/DemoAppTickerQModule.cs
index c9a3b957de..de3ef3c05d 100644
--- a/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.TickerQ/DemoAppTickerQModule.cs
+++ b/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.TickerQ/DemoAppTickerQModule.cs
@@ -3,13 +3,14 @@ using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
using TickerQ.Dashboard.DependencyInjection;
using TickerQ.DependencyInjection;
using TickerQ.Utilities;
using TickerQ.Utilities.Enums;
using TickerQ.Utilities.Interfaces.Managers;
-using TickerQ.Utilities.Models;
-using TickerQ.Utilities.Models.Ticker;
+using TickerQ.Utilities.Base;
+using TickerQ.Utilities.Entities;
using Volo.Abp.AspNetCore;
using Volo.Abp.Autofac;
using Volo.Abp.BackgroundJobs.DemoApp.Shared;
@@ -35,13 +36,14 @@ public class DemoAppTickerQModule : AbpModule
{
context.Services.AddTickerQ(options =>
{
- options.UpdateMissedJobCheckDelay(TimeSpan.FromSeconds(30));
+ options.ConfigureScheduler(scheduler =>
+ {
+ scheduler.FallbackIntervalChecker = TimeSpan.FromSeconds(30);
+ });
options.AddDashboard(x =>
{
- x.BasePath = "/tickerq-dashboard";
-
- x.UseHostAuthentication = true;
+ x.SetBasePath("/tickerq-dashboard");
});
});
@@ -78,7 +80,7 @@ public class DemoAppTickerQModule : AbpModule
abpTickerQFunctionProvider.Functions.TryAdd(nameof(CleanupJobs), (string.Empty, TickerTaskPriority.Normal, new TickerFunctionDelegate(async (cancellationToken, serviceProvider, tickerFunctionContext) =>
{
var service = new CleanupJobs();
- var request = await TickerRequestProvider.GetRequestAsync(serviceProvider, tickerFunctionContext.Id, tickerFunctionContext.Type);
+ var request = await TickerRequestProvider.GetRequestAsync(tickerFunctionContext, cancellationToken);
var genericContext = new TickerFunctionContext(tickerFunctionContext, request);
await service.CleanupLogsAsync(genericContext, cancellationToken);
})));
@@ -92,10 +94,11 @@ public class DemoAppTickerQModule : AbpModule
await backgroundWorkerManager.AddAsync(context.ServiceProvider.GetRequiredService());
var app = context.GetApplicationBuilder();
- app.UseAbpTickerQ();
- var timeTickerManager = context.ServiceProvider.GetRequiredService>();
- await timeTickerManager.AddAsync(new TimeTicker
+ context.GetHost().UseAbpTickerQ();
+
+ var timeTickerManager = context.ServiceProvider.GetRequiredService>();
+ await timeTickerManager.AddAsync(new TimeTickerEntity
{
Function = nameof(CleanupJobs),
ExecutionTime = DateTime.UtcNow.AddSeconds(5),
@@ -104,8 +107,8 @@ public class DemoAppTickerQModule : AbpModule
RetryIntervals = new[] { 30, 60, 120 }, // Retry after 30s, 60s, then 2min
});
- var cronTickerManager = context.ServiceProvider.GetRequiredService>();
- await cronTickerManager.AddAsync(new CronTicker
+ var cronTickerManager = context.ServiceProvider.GetRequiredService>();
+ await cronTickerManager.AddAsync(new CronTickerEntity
{
Function = nameof(CleanupJobs),
Expression = "* * * * *", // Every minute
@@ -134,7 +137,7 @@ public class DemoAppTickerQModule : AbpModule
await Task.Delay(1000);
- var timeTickerManager = serviceProvider.GetRequiredService>();
+ var timeTickerManager = serviceProvider.GetRequiredService>();
var result = await timeTickerManager.DeleteAsync(Guid.Parse(jobId));
}
}
diff --git a/npm/ng-packs/packages/permission-management/src/lib/components/permission-management.component.ts b/npm/ng-packs/packages/permission-management/src/lib/components/permission-management.component.ts
index 26b9a49349..3ed4794990 100644
--- a/npm/ng-packs/packages/permission-management/src/lib/components/permission-management.component.ts
+++ b/npm/ng-packs/packages/permission-management/src/lib/components/permission-management.component.ts
@@ -1,3 +1,4 @@
+import { NgStyle } from '@angular/common';
import { ConfigStateService, CurrentUserDto, LocalizationPipe } from '@abp/ng.core';
import {
ButtonComponent,
@@ -99,6 +100,7 @@ type PermissionWithGroupName = PermissionGrantInfoDto & {
],
imports: [
FormsModule,
+ NgStyle,
ModalComponent,
LocalizationPipe,
ButtonComponent,