Browse Source

Merge remote-tracking branch 'origin/dev' into issue/cms-kit-angular

pull/24234/head
sumeyye 10 months ago
parent
commit
1cc23ef11f
  1. 2
      Directory.Packages.props
  2. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json
  3. 173
      docs/en/Blog-Posts/2025-12-24-Announcing-Aspire-For-Microservice-Template/POST.md
  4. BIN
      docs/en/Blog-Posts/2025-12-24-Announcing-Aspire-For-Microservice-Template/aspire-apphost-topology.png
  5. BIN
      docs/en/Blog-Posts/2025-12-24-Announcing-Aspire-For-Microservice-Template/aspire-configuration.png
  6. BIN
      docs/en/Blog-Posts/2025-12-24-Announcing-Aspire-For-Microservice-Template/aspire-dashboard-console.png
  7. BIN
      docs/en/Blog-Posts/2025-12-24-Announcing-Aspire-For-Microservice-Template/aspire-dashboard-metrics.png
  8. BIN
      docs/en/Blog-Posts/2025-12-24-Announcing-Aspire-For-Microservice-Template/aspire-dashboard-resources.png
  9. BIN
      docs/en/Blog-Posts/2025-12-24-Announcing-Aspire-For-Microservice-Template/aspire-dashboard-structured-logs.png
  10. BIN
      docs/en/Blog-Posts/2025-12-24-Announcing-Aspire-For-Microservice-Template/aspire-dashboard-traces.png
  11. BIN
      docs/en/Blog-Posts/2025-12-24-Announcing-Aspire-For-Microservice-Template/aspire-database-postgre-pgadmin.png
  12. BIN
      docs/en/Blog-Posts/2025-12-24-Announcing-Aspire-For-Microservice-Template/aspire-grafana-dashboard.png
  13. BIN
      docs/en/Blog-Posts/2025-12-24-Announcing-Aspire-For-Microservice-Template/aspire-jaeger-traces.png
  14. BIN
      docs/en/Blog-Posts/2025-12-24-Announcing-Aspire-For-Microservice-Template/aspire-kibana-dashboard.png
  15. BIN
      docs/en/Blog-Posts/2025-12-24-Announcing-Aspire-For-Microservice-Template/aspire-prometheus-dashboard.png
  16. BIN
      docs/en/Blog-Posts/2025-12-24-Announcing-Aspire-For-Microservice-Template/aspire-rabbitmq-management.png
  17. BIN
      docs/en/Blog-Posts/2025-12-24-Announcing-Aspire-For-Microservice-Template/aspire-redis-insight.png
  18. BIN
      docs/en/Blog-Posts/2025-12-24-Announcing-Aspire-For-Microservice-Template/aspire-solution-structure.png
  19. BIN
      docs/en/Blog-Posts/2025-12-24-Announcing-Aspire-For-Microservice-Template/solution-runner-aspire-profile.png
  20. BIN
      docs/en/Community-Articles/2025-12-18-Announcement-AIMAnagement/cover.png
  21. BIN
      docs/en/Community-Articles/2025-12-18-Announcement-AIMAnagement/images/abp-studio-ai-management.png
  22. BIN
      docs/en/Community-Articles/2025-12-18-Announcement-AIMAnagement/images/ai-management-workspace-playground.png
  23. BIN
      docs/en/Community-Articles/2025-12-18-Announcement-AIMAnagement/images/ai-management-workspace-widget.png
  24. BIN
      docs/en/Community-Articles/2025-12-18-Announcement-AIMAnagement/images/aimanagement-workspace-geminiasopenai.png
  25. 106
      docs/en/Community-Articles/2025-12-18-Announcement-AIMAnagement/post.md
  26. 38
      docs/en/Community-Articles/2025-12-23-Referral-Program-Announcement/post.md
  27. 26
      docs/en/docs-nav.json
  28. 4
      docs/en/framework/architecture/multi-tenancy/index.md
  29. 2
      docs/en/framework/fundamentals/dependency-injection.md
  30. 4
      docs/en/framework/fundamentals/exception-handling.md
  31. 2
      docs/en/framework/fundamentals/validation.md
  32. 4
      docs/en/framework/infrastructure/artificial-intelligence/index.md
  33. 218
      docs/en/framework/infrastructure/artificial-intelligence/microsoft-agent-framework.md
  34. 1
      docs/en/framework/infrastructure/artificial-intelligence/microsoft-extensions-ai.md
  35. 2
      docs/en/framework/infrastructure/audit-logging.md
  36. 2
      docs/en/framework/infrastructure/background-workers/hangfire.md
  37. 2
      docs/en/framework/infrastructure/background-workers/quartz.md
  38. 2
      docs/en/framework/infrastructure/current-user.md
  39. 4
      docs/en/framework/infrastructure/emailing.md
  40. 23
      docs/en/framework/infrastructure/features.md
  41. 2
      docs/en/framework/infrastructure/settings.md
  42. 262
      docs/en/framework/ui/angular/ai-config.md
  43. 384
      docs/en/framework/ui/angular/ssr-configuration.md
  44. 126
      docs/en/framework/ui/common/leptonx-css-variables.md
  45. BIN
      docs/en/get-started/images/abp-studio-new-microservice-solution-dialog-optional-modules.png
  46. BIN
      docs/en/get-started/images/abp-studio-new-microservice-solution-dialog-properties.png
  47. BIN
      docs/en/get-started/images/abp-studio-new-solution-dialog-additional-options-microservice.png
  48. BIN
      docs/en/get-started/images/abp-studio-new-solution-dialog-additional-services.png
  49. BIN
      docs/en/get-started/images/abp-studio-new-solution-dialog-aspire-configuration-microservice.png
  50. BIN
      docs/en/get-started/images/abp-studio-new-solution-dialog-database-configurations-microservice.png
  51. BIN
      docs/en/get-started/images/abp-studio-new-solution-dialog-database-provider-microservice.png
  52. BIN
      docs/en/get-started/images/abp-studio-new-solution-dialog-dynamic-localization.png
  53. BIN
      docs/en/get-started/images/abp-studio-new-solution-dialog-languages-microservice.png
  54. BIN
      docs/en/get-started/images/abp-studio-new-solution-dialog-microservice.png
  55. BIN
      docs/en/get-started/images/abp-studio-new-solution-dialog-mobile-framework-microservice.png
  56. BIN
      docs/en/get-started/images/abp-studio-new-solution-dialog-multi-tenancy.png
  57. BIN
      docs/en/get-started/images/abp-studio-new-solution-dialog-public-web-site.png
  58. BIN
      docs/en/get-started/images/abp-studio-new-solution-dialog-ui-framework-microservice.png
  59. BIN
      docs/en/get-started/images/abp-studio-new-solution-dialog-ui-theme-microservice.png
  60. 19
      docs/en/get-started/microservice.md
  61. BIN
      docs/en/images/add-passkey.png
  62. BIN
      docs/en/images/my-passkey.png
  63. BIN
      docs/en/images/passkey-login.png
  64. BIN
      docs/en/images/passkey-login2.png
  65. BIN
      docs/en/images/passkey-setting.png
  66. BIN
      docs/en/images/pen-test-alert-list-10.1.png
  67. 1
      docs/en/modules/account-pro.md
  68. 2
      docs/en/modules/account/impersonation.md
  69. 63
      docs/en/modules/account/passkey.md
  70. 3
      docs/en/modules/ai-management/index.md
  71. 3
      docs/en/modules/feature-management.md
  72. 2
      docs/en/modules/saas.md
  73. 88
      docs/en/others/penetration-test-report.md
  74. 372
      docs/en/solution-templates/microservice/aspire-integration.md
  75. 4
      docs/en/solution-templates/microservice/helm-charts-and-kubernetes.md
  76. BIN
      docs/en/solution-templates/microservice/images/aspire-apphost-topology.png
  77. BIN
      docs/en/solution-templates/microservice/images/aspire-configuration.png
  78. BIN
      docs/en/solution-templates/microservice/images/aspire-dashboard-console.png
  79. BIN
      docs/en/solution-templates/microservice/images/aspire-dashboard-login.png
  80. BIN
      docs/en/solution-templates/microservice/images/aspire-dashboard-metrics.png
  81. BIN
      docs/en/solution-templates/microservice/images/aspire-dashboard-resources.png
  82. BIN
      docs/en/solution-templates/microservice/images/aspire-dashboard-structured-logs.png
  83. BIN
      docs/en/solution-templates/microservice/images/aspire-dashboard-traces.png
  84. BIN
      docs/en/solution-templates/microservice/images/aspire-database-postgre-pgadmin.png
  85. BIN
      docs/en/solution-templates/microservice/images/aspire-grafana-dashboard.png
  86. BIN
      docs/en/solution-templates/microservice/images/aspire-jaeger-traces.png
  87. BIN
      docs/en/solution-templates/microservice/images/aspire-kibana-dashboard.png
  88. BIN
      docs/en/solution-templates/microservice/images/aspire-prometheus-dashboard.png
  89. BIN
      docs/en/solution-templates/microservice/images/aspire-rabbitmq-management.png
  90. BIN
      docs/en/solution-templates/microservice/images/aspire-redis-insight.png
  91. BIN
      docs/en/solution-templates/microservice/images/aspire-solution-structure.png
  92. BIN
      docs/en/solution-templates/microservice/images/solution-runner-aspire-profile.png
  93. BIN
      docs/en/solution-templates/microservice/images/solution-runner-default-profile.png
  94. 9
      framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/StaticPermissionDefinitionChangedEvent.cs
  95. 134
      framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/StaticPermissionDefinitionStore.cs
  96. 3
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Utils/ProjectNameValidator.cs
  97. 3
      framework/src/Volo.Abp.Core/Volo/Abp/Internal/InternalServiceCollectionExtensions.cs
  98. 11
      framework/src/Volo.Abp.Core/Volo/Abp/StaticDefinitions/IStaticDefinitionCache.cs
  99. 30
      framework/src/Volo.Abp.Core/Volo/Abp/StaticDefinitions/StaticDefinitionCache.cs
  100. 7
      framework/src/Volo.Abp.EntityFrameworkCore.Sqlite/Volo/Abp/EntityFrameworkCore/Sqlite/AbpEntityFrameworkCoreSqliteModule.cs

2
Directory.Packages.props

@ -149,7 +149,7 @@
<PackageVersion Include="RabbitMQ.Client" Version="7.1.2" />
<PackageVersion Include="Rebus" Version="8.8.0" />
<PackageVersion Include="Rebus.ServiceProvider" Version="10.5.0" />
<PackageVersion Include="Riok.Mapperly" Version="4.3.0" />
<PackageVersion Include="Riok.Mapperly" Version="4.3.1" />
<PackageVersion Include="Scriban" Version="6.3.0" />
<PackageVersion Include="Serilog" Version="4.3.0" />
<PackageVersion Include="Serilog.AspNetCore" Version="9.0.0" />

2
abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json

@ -783,7 +783,7 @@
"Enum:SourceChannel:1": "Studio",
"Enum:SourceChannel:2": "Support Site",
"Enum:SourceChannel:3": "Suite",
"Menu:OrganizationTokenUsage": "Organization Token Usage",
"Menu:AITokens": "AI Tokens",
"Permission:OrganizationTokenUsage": "Organization Token Usage"
}
}

173
docs/en/Blog-Posts/2025-12-24-Announcing-Aspire-For-Microservice-Template/POST.md

@ -0,0 +1,173 @@
# Announcing .NET Aspire Integration for ABP Microservice Template
We are excited to announce the integration of **.NET Aspire** into the ABP microservice solution, available starting with **ABP Studio v2.0.0**. This integration brings a unified development experience for building, running, debugging, and deploying distributed applications. With Aspire, you can now orchestrate your entire microservice ecosystem with a single command, eliminating complex configurations and making local development effortless.
## What is .NET Aspire?
[Aspire](https://aspire.dev/get-started/what-is-aspire/) is a cloud-ready stack designed to streamline the development of distributed applications. It provides:
- **Orchestration**: A code-first approach to defining and running distributed applications, managing dependencies, and launch order.
- **Integrations**: Pre-built components for common services (databases, caches, message brokers) with automatic configuration.
- **Tooling**: A developer dashboard for real-time monitoring of logs, traces, metrics, and resource health.
- **Service Discovery**: Automatic service-to-service communication without hardcoded endpoints.
- **Observability**: Built-in OpenTelemetry support for distributed tracing, metrics, and structured logging.
## How Does It Work with ABP?
When you enable .NET Aspire in an ABP microservice solution, you get a fully integrated development experience where:
- All microservices, gateways, and applications are orchestrated through a single entry point (AppHost).
- Infrastructure containers (databases, Redis, RabbitMQ, Elasticsearch, etc.) are managed as code.
- OpenTelemetry, health checks, and service discovery are automatically configured for all projects via the shared ServiceDefaults project.
## Enabling Aspire in Your Solution
When creating a new microservice solution via ABP Studio:
1. In the solution creation wizard, look for the **".NET Aspire Integration"** step.
2. Toggle the option to **enable .NET Aspire**.
3. Complete the wizard—Aspire projects will be generated along with your solution.
![Enable Aspire in ABP Studio](aspire-configuration.png)
## Solution Structure Changes
When Aspire is enabled, two additional projects are added to your solution:
![Aspire Solution Structure](aspire-solution-structure.png)
### AppHost (Orchestrator)
[`AppHost`](https://aspire.dev/get-started/app-host/) is the .NET Aspire orchestrator project that declares all resources (services, databases, containers, applications) and their dependencies in C# code. It provides:
- **Centralized orchestration**: Start your entire microservice ecosystem with a single command.
- **Code-first infrastructure**: Databases, Redis, RabbitMQ, Elasticsearch, and observability tools are defined programmatically.
- **Dependency management**: Services start in the correct order using `WaitFor()` declarations.
- **Automatic configuration**: Connection strings, endpoints, and environment variables are injected automatically.
### ServiceDefaults
[`ServiceDefaults`](https://aspire.dev/fundamentals/service-defaults/) is a shared library that provides common cloud-native configuration for all projects in the solution. Every service uses the same observability, health check, and resilience patterns.
| Feature | Description |
|---------|-------------|
| OpenTelemetry | Tracing, metrics, and structured logging with automatic instrumentation |
| Health Checks | `/health` and `/alive` endpoints for Kubernetes-style probes |
| Service Discovery | Automatic resolution of service endpoints |
| HTTP Resilience | Retry policies, timeouts, and circuit breakers for HTTP clients |
## Running the Solution with Aspire
Running your microservice solution has never been easier:
1. Open **Solution Runner** in ABP Studio.
2. Select the **Aspire** profile.
3. Run `AppHost`.
![Solution Runner with Aspire](solution-runner-aspire-profile.png)
AppHost automatically:
- Starts all infrastructure containers (database, Redis, RabbitMQ, Elasticsearch, etc.).
- Launches all microservices, gateways, and applications in dependency order.
- Injects connection strings and environment variables.
- Opens the Aspire Dashboard for monitoring.
![Aspire AppHost Resource Topology](aspire-apphost-topology.png)
## Aspire Dashboard
The Aspire Dashboard provides real-time tracking of your application's state. It enables you to monitor logs, traces, metrics, and environment configurations in an intuitive UI.
![Aspire Dashboard Resources](aspire-dashboard-resources.png)
### Key Dashboard Features
#### Console Logs
Display console logs from all resources in real-time. Filter by resource and log level to quickly find relevant information during development and debugging.
![Aspire Dashboard Console](aspire-dashboard-console.png)
#### Structured Logs
View structured logs from all resources with advanced filtering capabilities. Search and filter logs by resource, log level, timestamp, and custom properties.
![Aspire Dashboard Structured Logs](aspire-dashboard-structured-logs.png)
#### Distributed Traces
Explore distributed traces across your microservices to understand request flows and identify performance bottlenecks.
![Aspire Dashboard Traces](aspire-dashboard-traces.png)
#### Metrics
Monitor real-time metrics including HTTP requests, response times, garbage collection, memory usage, and custom metrics.
![Aspire Dashboard Metrics](aspire-dashboard-metrics.png)
## Pre-Configured Observability Tools
AppHost comes with pre-configured observability and management tools:
### Grafana
Visualization and analytics platform for monitoring metrics with interactive dashboards.
![Grafana Dashboard](aspire-grafana-dashboard.png)
### Jaeger
Distributed tracing system to monitor and troubleshoot problems across microservices.
![Jaeger Traces](aspire-jaeger-traces.png)
### Kibana
Visualization tool for Elasticsearch data with search and data visualization capabilities for logs.
![Kibana Dashboard](aspire-kibana-dashboard.png)
### Prometheus
Monitoring and alerting toolkit that collects and stores metrics as time series data.
![Prometheus Dashboard](aspire-prometheus-dashboard.png)
### RabbitMQ Management
Web-based interface for managing and monitoring the RabbitMQ message broker.
![RabbitMQ Management](aspire-rabbitmq-management.png)
### Redis Insight
Visual tool for Redis that allows you to browse data, run commands, and monitor performance.
![Redis Insight](aspire-redis-insight.png)
### Database Admin Tools
The database management admin tool varies by database type:
| Database | Tool |
|----------|------|
| SQL Server | DBeaver CloudBeaver |
| MySQL | phpMyAdmin |
| PostgreSQL | pgAdmin |
| MongoDB | Mongo Express |
![pgAdmin Dashboard](aspire-database-postgre-pgadmin.png)
## Get Started Today
Ready to experience the power of .NET Aspire with ABP? Create a new microservice solution in ABP Studio and enable the .NET Aspire integration option. For detailed documentation, visit our [.NET Aspire Integration documentation](https://abp.io/docs/latest/solution-templates/microservice/aspire-integration).
To learn more about .NET Aspire, visit: [https://aspire.dev](https://aspire.dev/get-started/what-is-aspire/)
We are excited to bring this integration to you and can't wait to hear your feedback. If you have any questions or suggestions, please drop a comment below.
Happy coding!
**The Volosoft Team**

BIN
docs/en/Blog-Posts/2025-12-24-Announcing-Aspire-For-Microservice-Template/aspire-apphost-topology.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

BIN
docs/en/Blog-Posts/2025-12-24-Announcing-Aspire-For-Microservice-Template/aspire-configuration.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

BIN
docs/en/Blog-Posts/2025-12-24-Announcing-Aspire-For-Microservice-Template/aspire-dashboard-console.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

BIN
docs/en/Blog-Posts/2025-12-24-Announcing-Aspire-For-Microservice-Template/aspire-dashboard-metrics.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

BIN
docs/en/Blog-Posts/2025-12-24-Announcing-Aspire-For-Microservice-Template/aspire-dashboard-resources.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

BIN
docs/en/Blog-Posts/2025-12-24-Announcing-Aspire-For-Microservice-Template/aspire-dashboard-structured-logs.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

BIN
docs/en/Blog-Posts/2025-12-24-Announcing-Aspire-For-Microservice-Template/aspire-dashboard-traces.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

BIN
docs/en/Blog-Posts/2025-12-24-Announcing-Aspire-For-Microservice-Template/aspire-database-postgre-pgadmin.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

BIN
docs/en/Blog-Posts/2025-12-24-Announcing-Aspire-For-Microservice-Template/aspire-grafana-dashboard.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

BIN
docs/en/Blog-Posts/2025-12-24-Announcing-Aspire-For-Microservice-Template/aspire-jaeger-traces.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

BIN
docs/en/Blog-Posts/2025-12-24-Announcing-Aspire-For-Microservice-Template/aspire-kibana-dashboard.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

BIN
docs/en/Blog-Posts/2025-12-24-Announcing-Aspire-For-Microservice-Template/aspire-prometheus-dashboard.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

BIN
docs/en/Blog-Posts/2025-12-24-Announcing-Aspire-For-Microservice-Template/aspire-rabbitmq-management.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

BIN
docs/en/Blog-Posts/2025-12-24-Announcing-Aspire-For-Microservice-Template/aspire-redis-insight.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

BIN
docs/en/Blog-Posts/2025-12-24-Announcing-Aspire-For-Microservice-Template/aspire-solution-structure.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

BIN
docs/en/Blog-Posts/2025-12-24-Announcing-Aspire-For-Microservice-Template/solution-runner-aspire-profile.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

BIN
docs/en/Community-Articles/2025-12-18-Announcement-AIMAnagement/cover.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

BIN
docs/en/Community-Articles/2025-12-18-Announcement-AIMAnagement/images/abp-studio-ai-management.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

BIN
docs/en/Community-Articles/2025-12-18-Announcement-AIMAnagement/images/ai-management-workspace-playground.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

BIN
docs/en/Community-Articles/2025-12-18-Announcement-AIMAnagement/images/ai-management-workspace-widget.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
docs/en/Community-Articles/2025-12-18-Announcement-AIMAnagement/images/aimanagement-workspace-geminiasopenai.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

106
docs/en/Community-Articles/2025-12-18-Announcement-AIMAnagement/post.md

@ -0,0 +1,106 @@
# Introducing the AI Management Module: Manage AI Integration Dynamically
We are excited to announce the **AI Management Module**, a powerful new module to the ABP Platform that makes managing AI capabilities in your applications easier. No need to redeploy your application, now you can configure, test, and manage your AI integrations on the fly through an intuitive user interface!
## What is the AI Management Module?
Built on top of the [ABP Framework's AI infrastructure](https://abp.io/docs/latest/framework/infrastructure/artificial-intelligence), the AI Management Module allows you to manage AI workspaces dynamically without touching your code. Whether you're building a customer support chatbot, adding AI-powered search, or creating intelligent automation workflows, this module provides everything you need to manage AI integrations through a user-friendly interface.
> **Note**: The AI Management Module is currently in **preview** and available to ABP Team or higher license holders.
## What it offers?
### Manage AI Without Redeployment
Create, configure, and update AI workspaces directly from the UI. Switch between different AI providers (OpenAI, Azure OpenAI, Ollama, etc.), change models, adjust prompts, and test configurations, all without restarting your application or deploying new code.
### Built-In Chat Interface
Test your AI workspaces immediately with the included chat interface in playground pages. Verify your configurations work correctly before using them in production. Perfect for experimenting with different models, prompts, and settings.
![AI Management Playground](./images/ai-management-workspace-playground.png)
### Flexible for Any Architecture
Whether you're building a monolith, microservices, or something in between, the module adapts to your needs:
- Host AI management directly in your application with full UI and database
- Deploy a centralized AI service that multiple applications can consume
- Use it as an API gateway pattern for your microservices
### Works with Any AI Provider
Even AI Management module doesn't implement all the providers by default, it provides extensibility options with a good abstraction for other providers like Azure, Anthropic Claude, Google Gemini, and more. Or you can directly use the OpenAI adapter with LLMs that support OpenAI API.
- Example of using Gemini as an OpenAI provider:
![Using Gemini as an OpenAI provider](./images/aimanagement-workspace-geminiasopenai.png)
You can even add your own custom AI providers: [learn how to implement a custom AI provider factory in the documentation](https://abp.io/docs/latest/modules/ai-management#implementing-custom-ai-provider-factories).
### Ready to Use Chat Widget
Drop a compact, pre-built chat widget into any page with minimal code. It includes streaming support, conversation history, and API integration for customization.
- Simple to use with minimal code
```cs
@await Component.InvokeAsync(typeof(ChatClientChatViewComponent), new ChatClientChatViewModel
{
WorkspaceName = "StoryTeller",
})
```
- And result is a working, pre-integrated widget
![AI Management Chat Widget](./images/ai-management-workspace-widget.png)
- [See the widget documentation](https://abp.io/docs/latest/modules/ai-management#client-usage-mvc-ui) for details and all parameters for customization.
### Security
Control who can manage and use AI workspaces with permission-based access control. Isolate your AI configurations by using workspaces with different permissions. Also, resource based authorization on workspaces is on the way and will be available in the next versions. It'll allow you to manage access to specific workspaces by a user or role.
## Getting Started
Installation is straightforward using the [ABP Studio](https://abp.io/studio). You can just enable **AI Management** module while creating a new project with ABP Studio and configure your preferred AI provider and model in the solution creation wizard.
![ABP Studio AI Management Solution Creation Wizard](./images/abp-studio-ai-management.png)
## Roadmap
### v10.0 ✅
- Workspace Management
- MVC UI
- Playground
- Chat History _(Client-Side)_
- Client Components
- Integration to Startup Templates
### v10.1
- Blazor UI
- Angular UI
- Resource based authorization on Workspaces
- Agent-Framework compatibility examples
### Future Goals
- Microservice templates
- MCP Support
- RAG with file upload _(md, pdf, txt)_
- Chat History _(Server-Side Conversations)_
- OpenAI Compatible Endpoints
- Tenant-Based Configuration
- Extended RAG capabilities, _(ie. providing application data as tools)_
## Ready to Get Started?
The AI Management Module is available now for ABP Team and higher license holders.
**Learn More:**
- [AI Management Module Documentation](https://abp.io/docs/latest/modules/ai-management) - All features, scenarios, and technical details.
- [AI Infrastructure Documentation](https://abp.io/docs/latest/framework/infrastructure/artificial-intelligence) - Understanding AI workspaces in the framework.
- [Usage Scenarios](https://abp.io/docs/latest/modules/ai-management#usage-scenarios) - Examples for different architectures.
---
*The AI Management Module is currently in preview. We're excited to hear your feedback as we continue to improve and add new features!*

38
docs/en/Community-Articles/2025-12-23-Referral-Program-Announcement/post.md

@ -0,0 +1,38 @@
We are happy to share some exciting news. We launched **ABP.IO Referral Program** as a way to thank our customers and community members who help introduce ABP.IO to new professionals and organizations\!
If you already use ABP.IO and believe in it, you can now get benefits by recommending it to others.
## **What is ABP.IO Referral Program?**
<img alt="Referral_Program_-3" src="https://github.com/user-attachments/assets/b4957516-023d-4ea4-95db-173c6fa1e34d" />
ABP.IO Referral Program rewards people who bring new customers to ABP.IO.
When someone you refer purchases an ABP.IO license, you earn a commission as a thank-you for your contribution.
*\*This referral program is available to users who have an organization.*
## **What Benefits Do You Get?**
* Earn **5% commission** on the total sales price of each new license you refer
* Get rewarded for sharing a platform you already know and trust
## **Who Can Join?**
You can participate if:
* You are an existing ABP.IO customer who has purchased a license before
* You are a license owner or a developer
* Your license is active or expired
* The purchase is not made by your own company
## **Start Referring Today**
If you are interested in joining the program, you can get started right away.
👉 [**Start Referring Now**](https://abp.io/my-referrals)
Thank you for being part of our community. Your support helps us grow and now it pays back.

26
docs/en/docs-nav.json

@ -563,7 +563,11 @@
{
"text": "Microsoft.Extensions.AI",
"path": "framework/infrastructure/artificial-intelligence/microsoft-extensions-ai.md"
},
},
{
"text": "Agent Framework",
"path": "framework/infrastructure/artificial-intelligence/microsoft-agent-framework.md"
},
{
"text": "Semantic Kernel",
"path": "framework/infrastructure/artificial-intelligence/microsoft-semantic-kernel.md"
@ -1561,6 +1565,10 @@
"text": "SSR Configuration",
"path": "framework/ui/angular/ssr-configuration.md"
},
{
"text": "AI Tools Configuration",
"path": "framework/ui/angular/ai-config.md"
},
{
"text": "PWA Configuration",
"path": "framework/ui/angular/pwa-configuration.md"
@ -1861,6 +1869,10 @@
"text": "Overriding the User Interface",
"path": "framework/architecture/modularity/extending/overriding-user-interface.md"
},
{
"text": "How to Override LeptonX CSS Variables",
"path": "framework/ui/common/leptonx-css-variables.md"
},
{
"text": "Utilities",
"items": [
@ -2294,6 +2306,10 @@
"text": "Helm Charts and Kubernetes",
"path": "solution-templates/microservice/helm-charts-and-kubernetes.md"
},
{
"text": ".NET Aspire Integration",
"path": "solution-templates/microservice/aspire-integration.md"
},
{
"text": "Guides",
"items": [
@ -2355,13 +2371,17 @@
"path": "modules/account-pro.md",
"isIndex": true
},
{
"text": "Idle Session Timeout",
"path": "modules/account/idle-session-timeout.md"
},
{
"text": "Tenant impersonation & User impersonation",
"path": "modules/account/impersonation.md"
},
{
"text": "Idle Session Timeout",
"path": "modules/account/idle-session-timeout.md"
"text": "Web Authentication API (WebAuthn) passkeys",
"path": "modules/account/passkey.md"
}
]
},

4
docs/en/framework/architecture/multi-tenancy/index.md

@ -47,7 +47,7 @@ ABP supports all the following approaches to store the tenant data in the databa
- **Database per Tenant**: Every tenant has a separate, dedicated database to store the data related to that tenant.
- **Hybrid**: Some tenants share a single database while some tenants may have their own databases.
[Saas module (PRO)](../../../modules/saas.md) allows you to set a connection string for any tenant (as optional), so you can achieve any of the approaches.
[SaaS module (PRO)](../../../modules/saas.md) allows you to set a connection string for any tenant (as optional), so you can achieve any of the approaches.
> You can see the community article *[Multi-Tenancy with Separate Databases in .NET and ABP Framework](https://abp.io/community/articles/multitenancy-with-separate-databases-in-dotnet-and-abp-51nvl4u9)* for more details about different database architectures with practical implementation details.
@ -466,7 +466,7 @@ The [Tenant Management module](../../../modules/tenant-management.md) provides a
### A note about separate database per tenant approach in open source version
While ABP fully supports this option, managing connection strings of tenants from the UI is not available in open source version. You need to have [Saas module (PRO)](../../../modules/saas.md).
While ABP fully supports this option, managing connection strings of tenants from the UI is not available in open source version. You need to have [SaaS module (PRO)](../../../modules/saas.md).
Alternatively, you can implement this feature yourself by customizing the tenant management module and tenant application service to create and migrate the database on the fly.
## See Also

2
docs/en/framework/fundamentals/dependency-injection.md

@ -264,7 +264,7 @@ public class TaxAppService : ApplicationService
``TaxAppService`` gets ``ITaxCalculator`` in its constructor. The dependency injection system automatically provides the requested service at runtime.
Constructor injection is preffered way of injecting dependencies to a class. In that way, the class can not be constructed unless all constructor-injected dependencies are provided. Thus, the class explicitly declares it's required services.
Constructor injection is preferred way of injecting dependencies to a class. In that way, the class can not be constructed unless all constructor-injected dependencies are provided. Thus, the class explicitly declares it's required services.
### Property Injection

4
docs/en/framework/fundamentals/exception-handling.md

@ -88,7 +88,7 @@ Error **details** in an optional field of the JSON error message. Thrown `Except
}
````
`AbpValidationException` implements the `IHasValidationErrors` interface and it is automatically thrown by the framework when a request input is not valid. So, usually you don't need to deal with validation errors unless you have higly customised validation logic.
`AbpValidationException` implements the `IHasValidationErrors` interface and it is automatically thrown by the framework when a request input is not valid. So, usually you don't need to deal with validation errors unless you have highly customized validation logic.
### Logging
@ -289,7 +289,7 @@ The `IHttpExceptionStatusCodeFinder` is used to automatically determine the HTTP
### Custom Mappings
Automatic HTTP status code determination can be overrided by custom mappings. For example:
Automatic HTTP status code determination can be overridden by custom mappings. For example:
````C#
services.Configure<AbpExceptionHttpStatusCodeOptions>(options =>

2
docs/en/framework/fundamentals/validation.md

@ -121,7 +121,7 @@ namespace Acme.BookStore
#### Enabling/Disabling Validation
You can use the `[DisableValidation]` to disable it for methods, classs and properties.
You can use the `[DisableValidation]` to disable it for methods, classes and properties.
````csharp
[DisableValidation]

4
docs/en/framework/infrastructure/artificial-intelligence/index.md

@ -27,12 +27,14 @@ abp add-package Volo.Abp.AI
The `Volo.Abp.AI` package provides integration with the following libraries:
* [Microsoft.Extensions.AI](https://learn.microsoft.com/en-us/dotnet/ai/microsoft-extensions-ai)
* [Microsoft.Agents.AI (Agent Framework)](https://learn.microsoft.com/en-us/agent-framework/overview/agent-framework-overview)
* [Microsoft.SemanticKernel](https://learn.microsoft.com/en-us/semantic-kernel/overview/)
The Microsoft.Extensions.AI library is suggested for library developers to keep the library dependency minimum and simple (since it provides basic abstractions and fundamental AI provider integrations), while Semantic Kernel is suggested for applications that need rich and advanced AI integration features.
The **Microsoft.Extensions.AI** library is suggested for library developers to keep the library dependency minimum and simple (since it provides basic abstractions and fundamental AI provider integrations). For applications, **Microsoft Agent Framework** is the recommended choice as it combines the best of both AutoGen and Semantic Kernel (it's direct successor of these two frameworks), offering simple abstractions for single- and multi-agent patterns along with advanced features like thread-based state management, type safety, filters, and telemetry. **Semantic Kernel** can still be used if you need its specific AI integration features.
Check the following documentation to learn how to use these libraries with the ABP integration:
- [ABP Microsoft.Extensions.AI integration](./microsoft-extensions-ai.md)
- [ABP Microsoft.Agents.AI (Agent Framework) integration](./microsoft-agent-framework.md)
- [ABP Microsoft.SemanticKernel integration](./microsoft-semantic-kernel.md)

218
docs/en/framework/infrastructure/artificial-intelligence/microsoft-agent-framework.md

@ -0,0 +1,218 @@
# Microsoft.Agents.AI (Agent Framework)
[Microsoft Agent Framework](https://learn.microsoft.com/en-us/agent-framework/overview/agent-framework-overview) is an open-source development kit for **building AI agents** and **multi-agent workflows**. It is the direct successor to both *AutoGen* and [*Semantic Kernel*](./microsoft-semantic-kernel.md), combining their strengths while adding new capabilities, and is the suggested framework for building AI agent applications. This documentation is about the usage of this library with ABP Framework. Make sure you have read the [Artificial Intelligence](./index.md) documentation before reading this documentation.
## Usage
**Microsoft Agent Framework** works on top of `IChatClient` from **Microsoft.Extensions.AI**. After obtaining an `IChatClient` instance, you can create an AI agent using the `CreateAIAgent` extension method:
```csharp
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
public class MyService
{
private readonly IChatClient _chatClient;
public MyService(IChatClient chatClient)
{
_chatClient = chatClient;
}
public async Task<string> GetResponseAsync(string userMessage)
{
AIAgent agent = _chatClient.CreateAIAgent(
instructions: "You are a helpful assistant that provides concise answers."
);
AgentRunResponse response = await agent.RunAsync(userMessage);
return response.Text;
}
}
```
You can also use `IChatClientAccessor` to access the `IChatClient` in scenarios where AI capabilities are **optional**, such as when developing a module or a service that may use AI capabilities optionally:
```csharp
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
using Volo.Abp.AI;
public class MyService
{
private readonly IChatClientAccessor _chatClientAccessor;
public MyService(IChatClientAccessor chatClientAccessor)
{
_chatClientAccessor = chatClientAccessor;
}
public async Task<string> GetResponseAsync(string userMessage)
{
var chatClient = _chatClientAccessor.ChatClient;
if (chatClient is null)
{
return "No chat client configured";
}
AIAgent agent = chatClient.CreateAIAgent(
instructions: "You are a helpful assistant that provides concise answers."
);
var response = await agent.RunAsync(userMessage);
return response.Text;
}
}
```
### Workspaces
Workspaces are a way to configure isolated AI configurations for a named scope. You can define a workspace by decorating a class with the `WorkspaceNameAttribute` attribute that carries the workspace name.
- Workspace names must be unique.
- Workspace names cannot contain spaces _(use underscores or camelCase)_.
- Workspace names are case-sensitive.
```csharp
using Volo.Abp.AI;
[WorkspaceName("CommentSummarization")]
public class CommentSummarization
{
}
```
> [!NOTE]
> If you don't specify the workspace name, the full name of the class will be used as the workspace name.
You can resolve generic versions of `IChatClient` and `IChatClientAccessor` services for a specific workspace as generic arguments. If Chat Client is not configured for a workspace, you will get `null` from the accessor services. You should check the accessor before using it. This applies only for specified workspaces. Another workspace may have a configured Chat Client.
`IChatClient<TWorkSpace>` or `IChatClientAccessor<TWorkSpace>` can be resolved to access a specific workspace's chat client. This is a typed chat client and can be configured separately from the default chat client.
Example of resolving a typed chat client for a workspace:
```csharp
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
using Volo.Abp.AI;
public class MyService
{
private readonly IChatClient<CustomerSupport> _chatClient;
public MyService(IChatClient<CustomerSupport> chatClient)
{
_chatClient = chatClient;
}
public async Task<string> GetResponseAsync(string userMessage)
{
AIAgent agent = _chatClient.CreateAIAgent(
instructions: "You are a customer support assistant. Be polite and helpful."
);
var response = await agent.RunAsync(userMessage);
return response.Text;
}
}
```
Example of resolving a typed chat client accessor for a workspace:
```csharp
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
using Volo.Abp.AI;
public class MyService
{
private readonly IChatClientAccessor<CustomerSupport> _chatClientAccessor;
public MyService(IChatClientAccessor<CustomerSupport> chatClientAccessor)
{
_chatClientAccessor = chatClientAccessor;
}
public async Task<string> GetResponseAsync(string userMessage)
{
var chatClient = _chatClientAccessor.ChatClient;
if (chatClient is null)
{
return "No chat client configured";
}
AIAgent agent = chatClient.CreateAIAgent(
instructions: "You are a customer support assistant. Be polite and helpful."
);
var response = await agent.RunAsync(userMessage);
return response.Text;
}
}
```
## Configuration
**Microsoft Agent Framework** uses `IChatClient` from **Microsoft.Extensions.AI** as its foundation. Therefore, the configuration process for workspaces is the same as described in the [Microsoft.Extensions.AI documentation](./microsoft-extensions-ai.md#configuration).
You need to configure the Chat Client for your workspace using `AbpAIWorkspaceOptions`, and then you can use the `CreateAIAgent` extension method to create AI agents from the configured chat client.
To configure a chat client, you'll need a LLM provider package such as [Microsoft.Extensions.AI.OpenAI](https://www.nuget.org/packages/Microsoft.Extensions.AI.OpenAI) or [OllamaSharp](https://www.nuget.org/packages/OllamaSharp/).
_The following example requires [OllamaSharp](https://www.nuget.org/packages/OllamaSharp/) package to be installed._
Demonstration of the default workspace configuration:
```csharp
[DependsOn(typeof(AbpAIModule))]
public class MyProjectModule : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
PreConfigure<AbpAIWorkspaceOptions>(options =>
{
options.Workspaces.ConfigureDefault(configuration =>
{
configuration.ConfigureChatClient(chatClientConfiguration =>
{
chatClientConfiguration.Builder = new ChatClientBuilder(
sp => new OllamaApiClient("http://localhost:11434", "mistral")
);
});
});
});
}
}
```
Demonstration of the isolated workspace configuration:
```csharp
[DependsOn(typeof(AbpAIModule))]
public class MyProjectModule : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
PreConfigure<AbpAIWorkspaceOptions>(options =>
{
options.Workspaces.Configure<CustomerSupport>(configuration =>
{
configuration.ConfigureChatClient(chatClientConfiguration =>
{
chatClientConfiguration.Builder = new ChatClientBuilder(
sp => new OllamaApiClient("http://localhost:11434", "mistral")
);
});
});
});
}
}
```
## See Also
- [Usage of Microsoft.Extensions.AI](./microsoft-extensions-ai.md)
- [Usage of Semantic Kernel](./microsoft-semantic-kernel.md)
- [Microsoft Agent Framework Overview](https://learn.microsoft.com/en-us/agent-framework/overview/agent-framework-overview)
- [AI Samples for .NET](https://learn.microsoft.com/en-us/samples/dotnet/ai-samples/ai-samples/)

1
docs/en/framework/infrastructure/artificial-intelligence/microsoft-extensions-ai.md

@ -172,5 +172,6 @@ public class MyProjectModule : AbpModule
## See Also
- [Usage of Agent Framework](./microsoft-agent-framework.md)
- [Usage of Semantic Kernel](./microsoft-semantic-kernel.md)
- [AI Samples for .NET](https://learn.microsoft.com/en-us/samples/dotnet/ai-samples/ai-samples/)

2
docs/en/framework/infrastructure/audit-logging.md

@ -215,7 +215,7 @@ public class MyUser : Entity<Guid>
public string Email { get; set; }
[DisableAuditing] //Ignore the Passoword on audit logging
[DisableAuditing] //Ignore the Password on audit logging
public string Password { get; set; }
}
````

2
docs/en/framework/infrastructure/background-workers/hangfire.md

@ -61,7 +61,7 @@ After you have installed these NuGet packages, you need to configure your projec
var configuration = context.Services.GetConfiguration();
var hostingEnvironment = context.Services.GetHostingEnvironment();
//... other configarations.
//... other configurations.
ConfigureHangfire(context, configuration);
}

2
docs/en/framework/infrastructure/background-workers/quartz.md

@ -43,7 +43,7 @@ public class YourModule : AbpModule
}
````
> Quartz background worker integration provided `QuartzPeriodicBackgroundWorkerAdapter` to adapt `PeriodicBackgroundWorkerBase` and `AsyncPeriodicBackgroundWorkerBase` derived class. So, you can still fllow the [background workers document](../background-workers) to define the background worker.
> Quartz background worker integration provided `QuartzPeriodicBackgroundWorkerAdapter` to adapt `PeriodicBackgroundWorkerBase` and `AsyncPeriodicBackgroundWorkerBase` derived class. So, you can still follow the [background workers document](../background-workers) to define the background worker.
## Configuration

2
docs/en/framework/infrastructure/current-user.md

@ -101,7 +101,7 @@ For a web application, it gets the `User` property of the current `HttpContext`.
### Basic Usage
You can inject `ICurrentPrincipalAccessor` and use the `Principal` property to the the current principal:
You can inject `ICurrentPrincipalAccessor` and use the `Principal` property to get the current principal:
````csharp
public class MyService : ITransientDependency

4
docs/en/framework/infrastructure/emailing.md

@ -235,7 +235,7 @@ The final rendered message was shown above.
You typically want to replace the standard templates with your own ones, so you can prepare a branded email messages. To do that, you can use the power of the [virtual file system](../infrastructure/virtual-file-system.md) (VFS) or replace them in your own template definition provider.
Pathes of the templates in the virtual file system are shown below:
Paths of the templates in the virtual file system are shown below:
* `/Volo/Abp/Emailing/Templates/Layout.tpl`
* `/Volo/Abp/Emailing/Templates/Message.tpl`
@ -250,7 +250,7 @@ See the [text templating system](./text-templating) document for details.
## NullEmailSender
`NullEmailSender` is a built-in class that implements the `IEmailSender`, but writes email contents to the [standard log system](../fundamentals/logging.md), rathen than actually sending the emails.
`NullEmailSender` is a built-in class that implements the `IEmailSender`, but writes email contents to the [standard log system](../fundamentals/logging.md), rather than actually sending the emails.
This class can be useful especially in development time where you generally don't want to send real emails. The [application startup template](../../solution-templates/layered-web-application) already uses this class in the **DEBUG mode** with the following configuration in the domain layer:

23
docs/en/framework/infrastructure/features.md

@ -395,8 +395,31 @@ There are three pre-defined value providers, executed by the given order:
* `TenantFeatureValueProvider` tries to get if the feature value is explicitly set for the **current tenant**.
* `EditionFeatureValueProvider` tries to get the feature value for the current edition. Edition Id is obtained from the current principal identity (`ICurrentPrincipalAccessor`) with the claim name `editionid` (a constant defined as`AbpClaimTypes.EditionId`). Editions are not implemented for the [tenant management](../../modules/tenant-management.md) module. You can implement it yourself or consider to use the [SaaS module](https://abp.io/modules/Volo.Saas) of the ABP Commercial.
* `ConfigurationFeatureValueProvider`: Gets the value from the [IConfiguration service](../fundamentals/configuration.md).
* `DefaultValueFeatureValueProvider` gets the default value of the feature.
#### Feature Values in the Application Configuration
The `ConfigurationFeatureValueProvider` reads the feature values from the `IConfiguration` service, which can read values from the `appsettings.json` by default. So, the easiest way to configure feature values is to define them in the `appsettings.json` file.
For example, you can configure feature values as shown below:
````json
{
"Features": {
"MyApp.Reporting": "true",
"MyApp.PdfReporting": "true",
"MyApp.MaxProductCount": "50"
}
}
````
Feature values should be configured under the `Features` section as like in this example.
> `IConfiguration` is an .NET Core service and it can read values not only from the `appsettings.json`, but also from the environment, user secrets... etc. See [Microsoft's documentation](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/) for more.
#### Custom Feature Value Providers
You can write your own provider by inheriting the `FeatureValueProvider`.
**Example: Enable all features for a user with "SystemAdmin" as a "User_Type" claim value**

2
docs/en/framework/infrastructure/settings.md

@ -43,7 +43,7 @@ ABP automatically discovers this class and registers the setting definitions.
* **DefaultValue**: A setting may have a default value.
* **DisplayName**: A localizable string that can be used to show the setting name on the UI.
* **Description**: A localizable string that can be used to show the setting description on the UI.
* **IsVisibleToClients**: A boolean value indicates that whether this setting value is available in the client side or not. Default value is false to prevent accidently publishing an internal critical setting value.
* **IsVisibleToClients**: A boolean value indicates that whether this setting value is available in the client side or not. Default value is false to prevent accidentally publishing an internal critical setting value.
* **IsInherited**: A boolean value indicates that whether this setting value is inherited from other providers or not. Default value is true and fallbacks to the next provider if the setting value was not set for the requested provider (see the setting value providers section for more).
* **IsEncrypted**: A boolean value indicates that whether this setting value should be encrypted on save and decrypted on read. It makes possible to secure the setting value in the database.
* **Providers**: Can be used to restrict providers available for a particular setting (see the setting value providers section for more).

262
docs/en/framework/ui/angular/ai-config.md

@ -0,0 +1,262 @@
```json
//[doc-seo]
{
"Description": "Learn how to configure AI-powered development tools for ABP Framework Angular applications with automatic setup for Claude, Cursor, Copilot, Gemini, Junie, and Windsurf."
}
```
# AI Configuration
ABP Framework provides an **AI Configuration Generator** that helps developers set up AI-powered coding assistants for their Angular applications. This schematic automatically generates configuration files for popular AI tools with pre-configured ABP best practices and guidelines.
## Overview
The AI Configuration Generator is an Angular schematic that creates standardized configuration files for various AI development tools. These configurations include:
- ABP Framework coding standards and best practices
- Angular development guidelines
- Project-specific rules and conventions
- Full-stack development patterns (ABP .NET + Angular)
## Supported AI Tools
The generator supports the following AI coding assistants:
- **Claude** - Creates `.claude/CLAUDE.md` configuration file
- **Copilot** - Creates `.github/copilot-instructions.md` configuration file
- **Cursor** - Creates `.cursor/rules/cursor.mdc` configuration file
- **Gemini** - Creates `.gemini/GEMINI.md` configuration file
- **Junie** - Creates `.junie/guidelines.md` configuration file
- **Windsurf** - Creates `.windsurf/rules/guidelines.md` configuration file
## Usage
### Basic Usage
Generate AI configuration for a single tool:
```bash
ng g @abp/ng.schematics:ai-config --tool=claude
```
### Multiple Tools
Generate configurations for multiple AI tools at once:
```bash
# Comma-separated
ng g @abp/ng.schematics:ai-config --tool=claude,cursor,copilot
# Space-separated (with quotes)
ng g @abp/ng.schematics:ai-config --tool="claude cursor gemini"
# Multiple --tool flags
ng g @abp/ng.schematics:ai-config --tool=claude --tool=cursor --tool=gemini
```
### Target Specific Project
By default, configurations are generated at the workspace root. To target a specific project:
```bash
ng g @abp/ng.schematics:ai-config --tool=claude --target-project=my-app
```
This creates the configuration files in the `my-app` project root directory.
### Overwrite Existing Files
If configuration files already exist, use the `--overwrite` flag to replace them:
```bash
ng g @abp/ng.schematics:ai-config --tool=cursor --overwrite
```
## Schema Options
The AI Configuration Generator accepts the following options:
### tool
- **Type:** `string`
- **Required:** Yes
- **Description:** Comma-separated list of AI tools to generate configurations for
- **Valid values:** `claude`, `copilot`, `cursor`, `gemini`, `junie`, `windsurf`
- **Example:** `"claude,cursor,copilot"`
### targetProject
- **Type:** `string`
- **Required:** No
- **Description:** The name of the target project in your workspace
- **Default:** Workspace root (`/`)
- **Example:** `"my-angular-app"`
### overwrite
- **Type:** `boolean`
- **Required:** No
- **Default:** `false`
- **Description:** Whether to overwrite existing configuration files
## Configuration Content
All generated configuration files include comprehensive guidelines for:
### General Principles
- Clear separation between backend (ABP/.NET) and frontend (Angular) layers
- Modular architecture patterns
- Official ABP documentation references
- Readability, maintainability, and performance standards
### ABP / .NET Development Rules
- Standard folder structure (`*.Application`, `*.Domain`, `*.EntityFrameworkCore`, `*.HttpApi`)
- C# coding conventions and naming patterns
- Modern C# features (records, pattern matching, null-coalescing)
- ABP module integration (Permissions, Settings, Audit Logging)
- Error handling and validation patterns
### Angular Development Rules
- Angular coding style and best practices
- Component architecture patterns
- Reactive programming with RxJS
- ABP Angular package usage (`@abp/ng.core`, `@abp/ng.theme.shared`)
- State management and service patterns
### Performance and Testing
- Performance optimization techniques
- Unit testing and integration testing guidelines
- Best practices for both backend and frontend
## Examples
### Example 1: Setup Claude for Development
```bash
ng g @abp/ng.schematics:ai-config --tool=claude
```
Output:
```
🚀 Generating AI configuration files...
📁 Target path: /
🤖 Selected tools: claude
✅ AI configuration files generated successfully!
📝 Generated files:
- .claude/CLAUDE.md
💡 Tip: Restart your IDE or AI tool to apply the new configurations.
```
### Example 2: Setup Multiple Tools for a Project
```bash
ng g @abp/ng.schematics:ai-config --tool="cursor,copilot,gemini" --target-project=acme-app
```
Output:
```
🚀 Generating AI configuration files...
📁 Target path: /acme-app
🤖 Selected tools: cursor, copilot, gemini
✅ AI configuration files generated successfully!
📝 Generated files:
- /acme-app/.cursor/rules/cursor.mdc
- /acme-app/.github/copilot-instructions.md
- /acme-app/.gemini/GEMINI.md
💡 Tip: Restart your IDE or AI tool to apply the new configurations.
```
### Example 3: Update Existing Configuration
```bash
ng g @abp/ng.schematics:ai-config --tool=windsurf --overwrite
```
This will regenerate the Windsurf configuration file even if it already exists.
## File Structure
After running the generator, your project will have configuration files in their respective directories:
```
your-project/
├── .claude/
│ └── CLAUDE.md # Claude AI configuration
├── .cursor/
│ └── rules/
│ └── cursor.mdc # Cursor AI configuration
├── .github/
│ └── copilot-instructions.md # GitHub Copilot configuration
├── .gemini/
│ └── GEMINI.md # Gemini AI configuration
├── .junie/
│ └── guidelines.md # Junie AI configuration
└── .windsurf/
└── rules/
└── guidelines.md # Windsurf AI configuration
```
## Best Practices
1. **Generate Early**: Set up AI configurations at the beginning of your project to ensure consistent code quality from the start.
2. **Multiple Tools**: If your team uses different AI assistants, generate configurations for all of them to maintain consistency across the team.
3. **Version Control**: Commit the generated configuration files to your repository so all team members benefit from the same AI guidelines.
4. **Keep Updated**: When ABP releases new best practices or your project evolves, regenerate configurations with the `--overwrite` flag.
5. **Project-Specific**: For monorepos or multi-project workspaces, use `--target-project` to create project-specific configurations.
## Troubleshooting
### Configuration File Already Exists
If you see a warning that a configuration file already exists:
```
⚠️ Configuration file already exists: .claude/CLAUDE.md
Use --overwrite flag to replace existing files.
```
Add the `--overwrite` flag to replace it:
```bash
ng g @abp/ng.schematics:ai-config --tool=claude --overwrite
```
### Invalid Tool Name
If you specify an invalid tool name:
```
Invalid AI tool(s): chatgpt. Valid options are: claude, copilot, cursor, gemini, junie, windsurf
```
Make sure to use only the supported tool names listed above.
### No Tools Selected
If you run the command without specifying any tools:
```bash
ng g @abp/ng.schematics:ai-config
```
You'll see usage examples and available tools:
```
ℹ️ No AI tools selected. Skipping configuration generation.
💡 Usage examples:
ng g @abp/ng.schematics:ai-config --tool=claude,cursor
ng g @abp/ng.schematics:ai-config --tool="claude, cursor"
ng g @abp/ng.schematics:ai-config --tool=gemini --tool=cursor
ng g @abp/ng.schematics:ai-config --tool=gemini --target-project=my-app
Available tools: claude, copilot, cursor, gemini, junie, windsurf
```

384
docs/en/framework/ui/angular/ssr-configuration.md

@ -1,13 +1,13 @@
```json
//[doc-seo]
{
"Description": "Learn how to configure Server-Side Rendering (SSR) for your Angular application in the ABP Framework to improve performance and SEO."
"Description": "Learn how to configure Server-Side Rendering (SSR) for your Angular application in the ABP Framework to improve performance and SEO."
}
```
# SSR Configuration
[Server-Side Rendering (SSR)](https://angular.io/guide/ssr) is a process that involves rendering pages on the server, resulting in initial HTML content that contains the page state. This allows the browser to show the page to the user immediately, before the JavaScript bundles are downloaded and executed.
[Server-Side Rendering (SSR)](https://angular.dev/guide/ssr) is a process that involves rendering pages on the server, resulting in initial HTML content that contains the page state. This allows the browser to show the page to the user immediately, before the JavaScript bundles are downloaded and executed.
SSR improves the **performance** (First Contentful Paint) and **SEO** (Search Engine Optimization) of your application.
@ -105,10 +105,10 @@ If your project uses the **Webpack Builder** (`@angular-devkit/build-angular:bro
```typescript
import {
AngularNodeAppEngine,
createNodeRequestHandler,
isMainModule,
writeResponseToNodeResponse,
AngularNodeAppEngine,
createNodeRequestHandler,
isMainModule,
writeResponseToNodeResponse,
} from '@angular/ssr/node';
import express from 'express';
import { dirname, resolve } from 'node:path';
@ -128,28 +128,28 @@ const angularApp = new AngularNodeAppEngine();
* Serve static files from /browser
*/
app.use(
express.static(browserDistFolder, {
maxAge: '1y',
index: false,
redirect: false,
}),
express.static(browserDistFolder, {
maxAge: '1y',
index: false,
redirect: false,
}),
);
/**
* Handle all other requests by rendering the Angular application.
*/
app.use((req, res, next) => {
angularApp
.handle(req)
.then(response => {
if (response) {
res.cookie('ssr-init', 'true', {...secureCookie, httpOnly: false});
return writeResponseToNodeResponse(response, res);
} else {
return next()
}
})
.catch(next);
angularApp
.handle(req)
.then(response => {
if (response) {
res.cookie('ssr-init', 'true', {...secureCookie, httpOnly: false});
return writeResponseToNodeResponse(response, res);
} else {
return next()
}
})
.catch(next);
});
// ... (Start server logic)
@ -162,10 +162,10 @@ export const reqHandler = createNodeRequestHandler(app);
import { RenderMode, ServerRoute } from '@angular/ssr';
export const serverRoutes: ServerRoute[] = [
{
path: '**',
renderMode: RenderMode.Server
}
{
path: '**',
renderMode: RenderMode.Server
}
];
```
@ -180,16 +180,16 @@ import { serverRoutes } from './app.routes.server';
import { SSR_FLAG } from '@abp/ng.core';
const serverConfig: ApplicationConfig = {
providers: [
provideAppInitializer(() => {
const platformId = inject(PLATFORM_ID);
const transferState = inject<TransferState>(TransferState);
if (isPlatformServer(platformId)) {
transferState.set(SSR_FLAG, true);
}
}),
provideServerRendering(withRoutes(serverRoutes)),
],
providers: [
provideAppInitializer(() => {
const platformId = inject(PLATFORM_ID);
const transferState = inject<TransferState>(TransferState);
if (isPlatformServer(platformId)) {
transferState.set(SSR_FLAG, true);
}
}),
provideServerRendering(withRoutes(serverRoutes)),
],
};
export const config = mergeApplicationConfig(appConfig, serverConfig);
@ -237,13 +237,177 @@ The schematic installs `openid-client` to handle authentication on the server si
> Ensure your OpenID Connect configuration (in `environment.ts` or `app.config.ts`) is compatible with the server environment.
## 5. Deployment
## 5. Render Modes & Hybrid Rendering
To deploy your Angular SSR application to a production server, follow these steps:
Angular 20 provides different rendering modes that you can configure per route in the `app.routes.server.ts` file to optimize performance and SEO.
### 5.1. Build the Application
### 5.1. Available Render Modes
```typescript
import { RenderMode, ServerRoute } from '@angular/ssr';
export const serverRoutes: ServerRoute[] = [
// Server-Side Rendering - renders on every request
{
path: 'dashboard',
renderMode: RenderMode.Server
},
// Prerender (SSG) - renders at build time
{
path: 'about',
renderMode: RenderMode.Prerender
},
// Client-Side Rendering - renders only in browser
{
path: 'admin/**',
renderMode: RenderMode.Client
},
// Default fallback
{
path: '**',
renderMode: RenderMode.Server
}
];
```
#### RenderMode.Server (SSR)
Renders HTML on every request. Best for dynamic content, personalized pages, and pages requiring authentication.
#### RenderMode.Prerender (SSG)
Generates static HTML at build time. Best for marketing pages, blog posts, and content that doesn't change frequently.
For dynamic routes, use `getPrerenderParams`:
```typescript
{
path: 'blog/:slug',
renderMode: RenderMode.Prerender,
getPrerenderParams: async () => {
const posts = await fetchBlogPosts();
return posts.map(post => ({ slug: post.slug }));
}
}
```
#### RenderMode.Client (CSR)
Traditional client-side rendering. Best for highly interactive applications and admin panels that don't need SEO.
### 5.2. Hybrid Rendering
Combine different modes in one application for optimal results:
```typescript
export const serverRoutes: ServerRoute[] = [
// Static pages
{ path: '', renderMode: RenderMode.Prerender },
{ path: 'about', renderMode: RenderMode.Prerender },
Run the build command to generate the production artifacts:
// Dynamic pages
{ path: 'account', renderMode: RenderMode.Server },
{ path: 'orders', renderMode: RenderMode.Server },
// Admin area
{ path: 'admin/**', renderMode: RenderMode.Client },
];
```
## 6. Hydration
Hydration is the process where Angular attaches to server-rendered HTML and makes it interactive. The ABP schematic automatically configures hydration for your application.
### 6.1. Common Hydration Issues
**Problem: Browser APIs on Server**
```typescript
// ❌ Bad - will fail on server
const width = window.innerWidth;
// ✅ Good - check platform
import { isPlatformBrowser } from '@angular/common';
import { PLATFORM_ID, inject } from '@angular/core';
export class MyComponent {
platformId = inject(PLATFORM_ID);
getWidth() {
if (isPlatformBrowser(this.platformId)) {
return window.innerWidth;
}
return 0;
}
}
```
**Problem: Random or Time-Based Values**
```typescript
// ❌ Bad - generates different values on server and client
id = Math.random();
currentTime = new Date();
// ✅ Good - use TransferState for consistent data
import { TransferState, makeStateKey } from '@angular/core';
const TIME_KEY = makeStateKey<string>('time');
constructor(private transferState: TransferState) {
if (isPlatformServer(this.platformId)) {
this.transferState.set(TIME_KEY, new Date().toISOString());
} else {
this.time = this.transferState.get(TIME_KEY, new Date().toISOString());
}
}
```
**Enable Debug Tracing:**
```typescript
// app.config.ts
import { provideClientHydration, withDebugTracing } from '@angular/platform-browser';
export const appConfig: ApplicationConfig = {
providers: [
provideClientHydration(withDebugTracing()),
]
};
```
## 7. Environment Variables
Configure your SSR application using environment variables in `server.ts`:
```typescript
// server.ts
const PORT = process.env['PORT'] || 4000;
const HOST = process.env['HOST'] || 'localhost';
// Start the server
if (isMainModule(import.meta.url)) {
app.listen(PORT, () => {
console.log(`Server running on http://${HOST}:${PORT}`);
});
}
```
For production, set environment variables:
```bash
# .env file or environment configuration
NODE_ENV=production
PORT=4000
HOST=0.0.0.0
API_URL=https://api.yourdomain.com
```
## 8. Deployment
To deploy your Angular SSR application to a production server:
### 8.1. Build the Application
```shell
yarn build
@ -251,30 +415,152 @@ yarn build
yarn run build:ssr
```
### 5.2. Prepare Artifacts
### 8.2. Prepare Artifacts
After the build is complete, you will find the output in the `dist` folder.
For the **Application Builder**, the output structure typically looks like this:
Copy the `dist/MyProjectName` folder to your server:
```
dist/MyProjectName/
├── browser/ # Client-side bundles
└── server/ # Server-side bundles and entry point (server.mjs)
└── server/ # Server-side bundles (server.mjs)
```
You need to copy the entire `dist/MyProjectName` folder to your server.
### 8.3. Install Production Dependencies
On your server, install only the required dependencies (schematic already added them to package.json):
```shell
npm install --production
```
### 5.3. Run the Server
Required dependencies:
- `express`: Web server framework
- `openid-client`: Authentication support
On your server, navigate to the folder where you copied the artifacts and run the server using Node.js:
### 8.4. Run the Server
**Development/Testing:**
```shell
node server/server.mjs
```
> [!TIP]
> It is recommended to use a process manager like [PM2](https://pm2.keymetrics.io/) to keep your application alive and handle restarts.
**Production (with PM2):**
Use [PM2](https://pm2.keymetrics.io/) to keep your application alive and manage restarts:
```shell
npm install -g pm2
pm2 start server/server.mjs --name "my-app"
pm2 startup # Configure PM2 to start on boot
pm2 save # Save current process list
```
## 9. Troubleshooting
### 9.1. "Window/Document is not defined"
Browser APIs don't exist on the server. Always check the platform:
```typescript
import { isPlatformBrowser } from '@angular/common';
if (isPlatformBrowser(this.platformId)) {
// Safe to use window, document, localStorage, etc.
}
```
### 9.2. "LocalStorage is not defined"
ABP Core provides `AbpLocalStorageService` that implements the `Storage` interface and works safely on both server and client:
```typescript
import { AbpLocalStorageService } from '@abp/ng.core';
@Injectable({ providedIn: 'root' })
export class MyService {
private storage = inject(AbpLocalStorageService);
saveData(key: string, value: string): void {
// Safe on both server and client
this.storage.setItem(key, value);
}
getData(key: string): string | null {
// Returns null on server, actual value on client
return this.storage.getItem(key);
}
}
```
`AbpLocalStorageService` implements all `Storage` methods:
- `getItem(key: string): string | null`
- `setItem(key: string, value: string): void`
- `removeItem(key: string): void`
- `clear(): void`
- `key(index: number): string | null`
- `length: number`
### 9.3. Hydration Mismatch Errors
If you see "NG0500" errors in the console:
1. Enable debug tracing (see section 6.1)
2. Check for dynamic content (dates, random IDs)
3. Ensure server and client render the same HTML
4. Use `TransferState` for data consistency
### 9.4. Avoiding Duplicate API Calls
ABP Core provides a `transferStateInterceptor` that automatically prevents duplicate HTTP GET requests during hydration. When you use `provideAbpCore()`, this interceptor is already active.
**How it works:**
- Server: Stores HTTP GET responses in `TransferState`
- Client: Reuses stored responses during hydration
- Automatically cleans up stored data after use
```typescript
// app.config.ts
import { provideAbpCore } from '@abp/ng.core';
export const appConfig: ApplicationConfig = {
providers: [
provideAbpCore(),
// transferStateInterceptor is automatically included
]
};
```
The interceptor works with all HTTP GET requests made through `HttpClient`:
```typescript
// This service automatically benefits from the interceptor
@Injectable({ providedIn: 'root' })
export class UserService {
private http = inject(HttpClient);
getUsers() {
// On server: Response is cached in TransferState
// On client: Cached response is used (no duplicate request)
return this.http.get<User[]>('/api/users');
}
}
```
> [!NOTE]
> The interceptor only works with GET requests. POST, PUT, DELETE, and PATCH requests are not cached.
## Additional Resources
- [Angular SSR Official Guide](https://angular.dev/guide/ssr)
- [Angular Hydration Documentation](https://angular.dev/guide/hydration)
- [PM2 Process Manager](https://pm2.keymetrics.io/)
## Summary
The ABP Angular SSR schematic provides:
- ✅ Automatic SSR setup with necessary dependencies
- ✅ Server-side authentication with OpenID Connect
- ✅ Multiple render modes (Server, Prerender, Client, Hybrid)
- ✅ Hydration support for better performance
Configure render modes based on your needs, handle platform differences properly, and use environment variables for deployment configuration.

126
docs/en/framework/ui/common/leptonx-css-variables.md

@ -0,0 +1,126 @@
```json
//[doc-seo]
{
"Description": "Explore LeptonX CSS Variables to customize theming with ease, controlling colors, spacing, and styles for a cohesive application design."
}
```
# LeptonX CSS Variables Documentation
LeptonX uses CSS custom properties (variables) prefixed with `--lpx-*` to provide a flexible theming system. These variables control colors, spacing, shadows, and component-specific styles throughout the application.
## Brand & Semantic Colors
| Variable | Description |
|----------|-------------|
| `--lpx-brand` | Brand-specific accent color |
| `--lpx-brand-text` | Text color used on brand-colored backgrounds |
## Base Colors
| Variable | Description |
|----------|-------------|
| `--lpx-light` | Light shade for subtle backgrounds or text |
| `--lpx-dark` | Dark shade for contrasting elements |
## Layout & Surface Colors
| Variable | Description |
|----------|-------------|
| `--lpx-content-bg` | Main content area background color |
| `--lpx-content-text` | Default text color for content areas |
| `--lpx-card-bg` | Card component background color |
| `--lpx-card-title-text-color` | Card title text color |
| `--lpx-border-color` | Default border color for dividers and outlines |
| `--lpx-shadow` | Box shadow definition for elevated elements |
## Navigation
| Variable | Description |
|----------|-------------|
| `--lpx-navbar-color` | Navbar background color |
| `--lpx-navbar-text-color` | Navbar default text/icon color |
| `--lpx-navbar-active-text-color` | Navbar active/hover text color |
| `--lpx-navbar-active-bg-color` | Navbar active item background color |
## Utility
| Variable | Description |
|----------|-------------|
| `--lpx-radius` | Global border-radius value for rounded corners |
## Global Override
Applies to all themes and pages:
```css
:root {
/* Brand & Semantic */
--lpx-brand: #f72585;
/* Base Colors */
--lpx-light: #f5f7fb;
--lpx-dark: #0b0f19;
/* Layout & Surface */
--lpx-content-bg: #101018;
--lpx-content-text: #cfd6e4;
--lpx-card-bg: #151a2b;
--lpx-card-title-text-color: #ffffff;
--lpx-border-color: #242836;
--lpx-shadow: 0 10px 30px rgba(0, 0, 0, 0.25);
/* Navigation */
--lpx-navbar-color: #0d1020;
--lpx-navbar-text-color: #aab2c8;
--lpx-navbar-active-text-color: #ffffff;
--lpx-navbar-active-bg-color: rgba(247, 37, 133, 0.15);
/* Utility */
--lpx-radius: 10px;
}
```
## Theme-Scoped Override
Applies only when a specific theme class is active (e.g., `.lpx-theme-dark` on `<html>` or `<body>`):
```css
:root .lpx-theme-dark {
/* Brand & Semantic */
--lpx-brand: #4dd0e1;
/* Base Colors */
--lpx-light: #e0f7fa;
--lpx-dark: #020617;
/* Layout & Surface */
--lpx-content-bg: #0b1118;
--lpx-content-text: #c7d0e0;
--lpx-card-bg: #111a24;
--lpx-card-title-text-color: #e6f1ff;
--lpx-border-color: #1e2a3a;
--lpx-shadow: 0 12px 32px rgba(0, 0, 0, 0.45);
/* Navigation */
--lpx-navbar-color: #0f1a22;
--lpx-navbar-text-color: #9fb3c8;
--lpx-navbar-active-text-color: #ffffff;
--lpx-navbar-active-bg-color: rgba(77, 208, 225, 0.18);
/* Utility */
--lpx-radius: 12px;
}
```
## Component/Page-Specific Override
For targeted customizations that should only affect a specific section:
```css
.my-custom-page {
--lpx-brand: #e91e63;
--lpx-card-bg: #1a1a2e;
}
```

BIN
docs/en/get-started/images/abp-studio-new-microservice-solution-dialog-optional-modules.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 24 KiB

BIN
docs/en/get-started/images/abp-studio-new-microservice-solution-dialog-properties.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 27 KiB

BIN
docs/en/get-started/images/abp-studio-new-solution-dialog-additional-options-microservice.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 34 KiB

BIN
docs/en/get-started/images/abp-studio-new-solution-dialog-additional-services.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 26 KiB

BIN
docs/en/get-started/images/abp-studio-new-solution-dialog-aspire-configuration-microservice.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

BIN
docs/en/get-started/images/abp-studio-new-solution-dialog-database-configurations-microservice.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 20 KiB

BIN
docs/en/get-started/images/abp-studio-new-solution-dialog-database-provider-microservice.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 24 KiB

BIN
docs/en/get-started/images/abp-studio-new-solution-dialog-dynamic-localization.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 30 KiB

BIN
docs/en/get-started/images/abp-studio-new-solution-dialog-languages-microservice.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

BIN
docs/en/get-started/images/abp-studio-new-solution-dialog-microservice.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 41 KiB

BIN
docs/en/get-started/images/abp-studio-new-solution-dialog-mobile-framework-microservice.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 30 KiB

BIN
docs/en/get-started/images/abp-studio-new-solution-dialog-multi-tenancy.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 28 KiB

BIN
docs/en/get-started/images/abp-studio-new-solution-dialog-public-web-site.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 25 KiB

BIN
docs/en/get-started/images/abp-studio-new-solution-dialog-ui-framework-microservice.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 90 KiB

After

Width:  |  Height:  |  Size: 51 KiB

BIN
docs/en/get-started/images/abp-studio-new-solution-dialog-ui-theme-microservice.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 28 KiB

19
docs/en/get-started/microservice.md

@ -94,6 +94,25 @@ Once you select the desired modules, click the *Next* button for the *UI Theme*
LeptonX is the suggested UI theme that is proper for production usage. Select one of the themes and configure the additional options if you want.
Click the Next button to see *Language Selection* selection:
![abp-studio-new-solution-dialog-languages](images/abp-studio-new-solution-dialog-languages-microservice.png)
In this step, you can choose which languages your application will support.
* Default Language: Select the main language for your app.
* Localizable User Interface: Turn this on to support multiple languages.
* Available Languages: Check the languages you want to include.
* Click Add Custom Language if you want to add a language that is not listed.
Click the Next button to see *.NET Aspire* configuration selection:
![abp-studio-new-solution-dialog-aspire-configuration](images/abp-studio-new-solution-dialog-aspire-configuration-microservice.png)
In this step, you can enable or disable the .NET Aspire integration for your solution. If you enable it, the solution will be pre-configured to work with .NET Aspire for easier microservice development and deployment. See the [Aspire Integration](../solution-templates/microservice/aspire-integration.md) document for more information about this feature.
Click the Next button to see *Additional Options* selection:

BIN
docs/en/images/add-passkey.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

BIN
docs/en/images/my-passkey.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

BIN
docs/en/images/passkey-login.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

BIN
docs/en/images/passkey-login2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

BIN
docs/en/images/passkey-setting.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

BIN
docs/en/images/pen-test-alert-list-10.1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

1
docs/en/modules/account-pro.md

@ -424,3 +424,4 @@ This module doesn't define any additional distributed event. See the [standard d
* [Linked Accounts](./account/linkedaccounts.md)
* [Session Management](./account/session-management.md)
* [Idle Session Timeout](./account/idle-session-timeout.md)
* [Web Authentication API (WebAuthn) passkeys](./account/passkey.md)

2
docs/en/modules/account/impersonation.md

@ -7,7 +7,7 @@
# Tenant impersonation & User impersonation
User impersonation allows you to temporarily sign in as a different user in your tenant's users. This article introduces how to enable impersonation in ABP. Impersonation is enabled by defautl in ABP v5.0 and above.
User impersonation allows you to temporarily sign in as a different user in your tenant's users. This article introduces how to enable impersonation in ABP. Impersonation is enabled by default in ABP v5.0 and above.
## Introduction

63
docs/en/modules/account/passkey.md

@ -0,0 +1,63 @@
# Web Authentication API (WebAuthn) passkeys
The `Web Authentication API (WebAuthn) passkeys` feature allows users to authenticate using passkeys, which are more secure and user-friendly alternatives to traditional passwords. Passkeys leverage public key cryptography to provide strong authentication without the need for users to remember complex passwords.
## Enabling Passkeys
You can enable/disable the `Web Authentication API (WebAuthn) passkeys` feature in the `Setting > Account > Passkeys` page. Also, there is an option to allow how many passkeys a user can register:
![passkey-setting](../../images/passkey-setting.png)
## Manage Passkeys
You can add/rename/delete your passkeys in the `Account/Manage` page:
![my-passkey](../../images/my-passkey.png)
Click the `Add Passkey` button to register a new passkey. You will be prompted to use your device's built-in biometric authentication (such as fingerprint or facial recognition) or an external security key to complete the registration process:
![add-passkey](../../images/add-passkey.png)
## Using Passkey for Login
Once you enable the passkey feature and register at least one passkey, you can use it to log in to your account. On the login page, select the `Passkey login` option and follow the prompts to authenticate using your registered passkey:
![passkey-login](../../images/passkey-login.png)
![passkey-login2](../../images/passkey-login2.png)
## Configure passkey options
ASP.NET Core Identity provides various options to configure passkey behavior through the `IdentityPasskeyOptions` class, which include:
- **AuthenticatorTimeout**: Gets or sets the time that the browser should wait for the authenticator to provide a passkey as a TimeSpan. This option applies to both creating a new passkey and requesting an existing passkey. This option is treated as a hint to the browser, and the browser may ignore the option. The default value is 5 minutes.
- **ChallengeSize**: Gets or sets the size of the challenge in bytes sent to the client during attestation and assertion. This option applies to both creating a new passkey and requesting an existing passkey. The default value is 32 bytes.
- **ServerDomain**: Gets or sets the effective Relying Party ID (domain) of the server. This should be unique and will be used as the identity for the server. This option applies to both creating a new passkey and requesting an existing passkey. If null, which is the default value, the server's origin is used. For more information, see Relying Party Identifier RP ID.
**Example configuration:**
```csharp
builder.Services.Configure<IdentityPasskeyOptions>(options =>
{
options.ServerDomain = "abp.io";
options.AuthenticatorTimeout = TimeSpan.FromMinutes(3);
options.ChallengeSize = 64;
});
```
For a complete list of configuration options, see [IdentityPasskeyOptions](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.identity.identitypasskeyoptions). For the most up-to-date browser defaults, see the [W3C WebAuthn specification](https://www.w3.org/TR/webauthn-3/).
## HTTPS requirement
All passkey operations require HTTPS. The implementation stores authentication data in encrypted and signed cookies that could be intercepted over unencrypted connections.
## Browser Support
Passkeys are supported in most modern browsers, including: Chrome, Edge, Firefox, and Safari. Ensure that you are using the latest version of your browser to take advantage of passkey functionality.
## Additional resources
For more information on WebAuthn and passkeys, refer to the following resources:
- [Enable Web Authentication API (WebAuthn) passkeys](https://learn.microsoft.com/en-us/aspnet/core/security/authentication/passkeys)
- [Web Authentication API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Authentication_API)

3
docs/en/modules/ai-management/index.md

@ -606,7 +606,7 @@ chatComponent.off('messageSent', callbackFunction);
## Using Dynamic Workspace Configurations for custom requirements
The AI Management module allows you to access only configuration of a workspace without resolving pre-constructed chat client. This is useful when you want to use a workspace for your own purposes and you don't need to use the chat client.
The `IWorkspaceConfigurationStore` service is used to access the configuration of a workspace. It has multiple implementaations according to the usage scenario.
The `IWorkspaceConfigurationStore` service is used to access the configuration of a workspace. It has multiple implementations according to the usage scenario.
```csharp
public class MyService
@ -832,4 +832,5 @@ The cache is automatically invalidated when workspaces are created, updated, or
- [Artificial Intelligence Infrastructure](../../framework/infrastructure/artificial-intelligence/index.md): Learn about the underlying AI workspace infrastructure
- [Microsoft.Extensions.AI](https://learn.microsoft.com/en-us/dotnet/ai/): Microsoft's unified AI abstractions
- [Microsoft Agent Framework](https://learn.microsoft.com/en-us/agent-framework/overview/agent-framework-overview): Microsoft's Agent Framework
- [Semantic Kernel](https://learn.microsoft.com/en-us/semantic-kernel/): Microsoft's Semantic Kernel integration

3
docs/en/modules/feature-management.md

@ -72,9 +72,10 @@ namespace Demo
## Feature Management Providers
Features Management Module is extensible, just like the [features system](../framework/infrastructure/features.md). You can extend it by defining feature management providers. There are 3 pre-built feature management providers registered it the following order:
Features Management Module is extensible, just like the [features system](../framework/infrastructure/features.md). You can extend it by defining feature management providers. There are 4 pre-built feature management providers registered in the following order:
* `DefaultValueFeatureManagementProvider`: Gets the value from the default value of the feature definition. It can not set the default value since default values are hard-coded on the feature definition.
* `ConfigurationFeatureManagementProvider`: Gets the value from the [IConfiguration service](../framework/fundamentals/configuration.md).
* `EditionFeatureManagementProvider`: Gets or sets the feature values for an edition. Edition is a group of features assigned to tenants. Edition system has not implemented by the Tenant Management module. You can implement it yourself or purchase the ABP [SaaS Module](https://abp.io/modules/Volo.Saas) which implements it and also provides more SaaS features, like subscription and payment.
* `TenantFeatureManagementProvider`: Gets or sets the features values for tenants.

2
docs/en/modules/saas.md

@ -40,7 +40,7 @@ Firstly, Payment module must be configured properly:
```bash
abp add-module Volo.Payment
```
_Or you can install via using ABP Suite._
_Or you can install via using ABP Studio._
- Configure Saas module to use Payment.

88
docs/en/others/penetration-test-report.md

@ -7,7 +7,7 @@
# ABP Penetration Test Report
The ABP Commercial MVC `v9.1.0` application template has been tested against security vulnerabilities by the [OWASP ZAP v2.14.0](https://www.zaproxy.org/) tool. The demo web application was started on the `https://localhost:44349` address. The below alerts have been reported by the pentest tool. These alerts are sorted by the risk level as high, medium, and low. The informational alerts are not mentioned in this document.
The ABP Commercial MVC `v10.0.1` application template has been tested against security vulnerabilities by the [OWASP ZAP v2.14.0](https://www.zaproxy.org/) tool. The demo web application was started on the `https://localhost:44349` address. The below alerts have been reported by the pentest tool. These alerts are sorted by the risk level as high, medium, and low. The informational alerts are not mentioned in this document.
Many of these alerts are **false-positive**, meaning the vulnerability scanner detected these issues, but they are not exploitable. It's clearly explained for each false-positive alert why this alert is a false-positive.
@ -17,53 +17,75 @@ In the next sections, you will find the affected URLs, attack parameters (reques
There are high _(red flag)_, medium _(orange flag)_, low _(yellow flag)_, and informational _(blue flag)_ alerts.
![penetration-test-9.1.0](../images/pen-test-alert-list-9.1.png)
![penetration-test-10.0.1](../images/pen-test-alert-list-10.1.png)
> The informational alerts are not mentioned in this document. These alerts are not raising any risks on your application and they are optional.
> The informational alerts are not mentioned in this document. These alerts don't raise any risks for your application and they are optional.
### Spring4Shell [Risk: High] - False Positive
### Cross Site Scripting (Reflected) [Risk: High] - Positive
- *[POST] - https://localhost:44349/Account/ForgotPassword* (attack: **class.module.classLoader.DefaultAssertionStatus=nonsense**)
- *[POST] - https://localhost:44349/Account/Login* (attack: **class.module.classLoader.DefaultAssertionStatus=nonsense**)
- *[POST] - https://localhost:44349/Account/Login?ReturnUrl=%2FSettingManagement* (attack: **class.module.classLoader.DefaultAssertionStatus=nonsense**)
- *[GET] - https://localhost:44349/Identity/OrganizationUnits/AddMemberModal?title=SelectAUser&organizationUnitId=...&OrganizationUnitName=%3C%2Fh5%3E%3CscrIpt%3Ealert%281%29%3B%3C%2FscRipt%3E%3Ch5%3E*
- *[GET] - https://localhost:44349/Identity/OrganizationUnits/AddRoleModal?organizationUnitId=...&OrganizationUnitName=%3C%2Fh5%3E%3CscrIpt%3Ealert%281%29%3B%3C%2FscRipt%3E%3Ch5%3E*
- *[GET] - https://localhost:44349/Saas/Host/Tenants/ImpersonateTenantModal?tenantId=...&tenantName=%3C%2Fh5%3E%3CscrIpt%3Ealert%281%29%3B%3C%2FscRipt%3E%3Ch5%3E*
**Description**:
The application appears to be vulnerable to CVE-2022-22965 (otherwise known as Spring4Shell) - remote code execution (RCE) via data binding.
Cross-site Scripting (XSS) is an attack technique that involves echoing attacker-supplied code into a user's browser instance.
**Explanation**:
ABP Framework is built on top of ASP.NET Core and does not use the Spring Framework. This application does not rely on Java-based technologies, making it immune to vulnerabilities like Spring4Shell. The detection is a false positive as there are no Spring dependencies in the project.
This is a **Positive** alert. The application reflects the `OrganizationUnitName` and `tenantName` parameters without proper encoding in the modal headers, allowing for the execution of arbitrary JavaScript. We have created an **internal issue** to track this vulnerability, and it will be fixed in the next release.
### Absence of Anti-CSRF Tokens [Risk: Medium] — False Positive
### PII Disclosure [Risk: High] - False Positive
* *[GET] - https://localhost:44349/Account/LinkUsers/LinkUsersModal?returnUrl=/SettingManagement*
* *[GET] — https://localhost:44349/Account/Manage* (same URL with different query parameters)
* *[GET] - https://localhost:44349/HostDashboard*
* *[GET] - https://localhost:44349/SettingManagement?handler=RenderView&id=Volo.Abp.Account* (other several URLs)
- *[GET] - https://localhost:44349/* (Evidence: 639002492030480000)
- *[GET] - https://localhost:44349/?page=...*
**Description**:
**Description**:
No Anti-CSRF tokens were found in an HTML submission form.
A cross-site request forgery is an attack that involves forcing a victim to send an HTTP request to a target destination without their knowledge or intent in order to perform an action as the victim. The underlying cause is application functionality using predictable URL/form actions in a repeatable way. The nature of the attack is that CSRF exploits the trust that a website has for a user. By contrast, cross-site scripting (XSS) exploits the trust that a user has in a website. Like XSS, CSRF attacks are not necessarily cross-site, but they can be. Cross-site request forgery is also known as CSRF, XSRF, one-click attack, session riding, confused deputy, and sea surf.
The response contains Personally Identifiable Information, such as CC number, SSN and similar sensitive data.
**Explanation:**
**Explanation**:
This is a **false-positive** alert because ABP provides the Anti-CSRF token via a cookie as seen on the following screenshot:
This is a **false-positive** alert. The detected numbers (e.g., `639002492030480000`) are cache-busting timestamps (`_v` parameter) generated by the framework for static assets. They coincidentally match the pattern of Credit Card numbers (pattern matching) but are not sensitive data.
![Absence of Anti-CSRF Token](../images/pen-test-alert-remote-os-command-injection.png)
### Path Traversal [Risk: High] - False Positive
### Application Error Disclosure [Risk: Medium] - False Positive
- *[GET] - https://localhost:44349/Account/Login?returnUrl=Login*
- *[GET] - https://localhost:44349/api/account/security-logs?action=\security-logs*
- *[GET] — https://localhost:44349/AuditLogs*
**Description**:
**Description**:
The Path Traversal attack technique allows an attacker access to files, directories, and commands that potentially reside outside the web document root directory.
**Explanation**:
This is a **false-positive** alert. ABP Framework automatically validates `returnUrl` parameters and ensures they are local to the application or within a whitelist. The application does not return file contents based on these parameters.
### SQL Injection [Risk: High] - False Positive
- *[GET] - https://localhost:44349/AbpPermissionManagement/PermissionManagementModal?providerKey=AbpSolution16711_Swagger+AND+1%3D1+--+*
- *[GET] - https://localhost:44349/Account/Manage?CurrentPassword=ZAP%27+AND+%271%27%3D%271%27+--+*
**Description**:
SQL injection may be possible.
This page contains an error/warning message that may disclose sensitive information like the location of the file that produced the unhandled exception. This information can be used to launch further attacks against the web application. The alert could be a false positive if the error message is found inside a documentation page.
**Explanation**:
This is a **false-positive** alert. ABP Framework uses Entity Framework Core, which inherently uses parameterized queries, preventing standard SQL injection attacks. Manual verification showed that injecting SQL syntax into parameters like `providerKey` results in the input being treated as a literal string (resulting in no match or default behavior) rather than altering the query structure.
### SQL Injection - SQLite [Risk: High] - False Positive
- *[POST] - https://localhost:44349/Account/ForgotPassword?returnUrl=%2FAccount%2FManage* (Attack: `case randomblob(100000) ...`)
- *[POST] - https://localhost:44349/FeatureManagement/FeatureManagementModal*
**Description**:
SQL injection may be possible.
**Explanation**:
There are only one URL that is reported as exposing error messages. This is a **false-positive** alert. The [Audit Logging Module](../modules/audit-logging.md), shows request & response details and exception information, these are not sensitive information and only can be seen by the users whose related permissions are granted.
This is a **false-positive** alert. Similar to the standard SQL Injection alert, the application uses parameterized queries. The detected delays are likely due to application processing variations or network latency rather than successful SQL injection.
### Content Security Policy (CSP) Header Not Set [Risk: Medium] — Positive (Fixed)
@ -238,23 +260,7 @@ A cookie has been set with its `SameSite` attribute set to `none`, which means t
Ensure that the `SameSite` attribute is set to either `lax` or ideally `strict` for all cookies. We discussed setting the **SameSite** attribute to `strict` in the following issue [github.com/abpframework/abp/issues/14215](https://github.com/abpframework/abp/issues/14215) and decided to leave this change to the final developer.
### Information Disclosure - Debug Error Messages [Risk: Low] — False Positive
* *[GET] - https://localhost:44349/AuditLogs*
**Description:**
The response appeared to contain common error messages returned by platforms such as ASP.NET, and Web-servers such as IIS and Apache. You can configure the list of common debug messages.
**Solution:**
Disable debugging messages before pushing them to production.
**Explanation:**
The response of the endpoints above return localization texts which are not real error messages. As there is no real error in the backend side, this vulnerability is a **false-positive** alert.
![Information Disclosure - Debug Error Messages](../images/pen-test-information-disclosure.png)
### Strict-Transport-Security Header Not Set [Risk: Low] - False Positive

372
docs/en/solution-templates/microservice/aspire-integration.md

@ -0,0 +1,372 @@
```json
//[doc-seo]
{
"Description": "Learn how to integrate .NET Aspire into your ABP-based solution for streamlined development, orchestration, and observability of distributed applications."
}
```
# .NET Aspire Integration
````json
//[doc-nav]
{
"Next": {
"Name": "Miscellaneous guides in the Microservice solution",
"Path": "solution-templates/microservice/guides"
}
}
````
> You must have an ABP Business or a higher license to be able to create a microservice solution.
## .NET Aspire Overview
[Aspire](https://aspire.dev/get-started/what-is-aspire/) streamlines building, running, debugging, and deploying distributed apps. Picture your app as a set of services, databases, and frontends—when they’re deployed, they all work together seamlessly, but every time you develop them they need to be individually started and connected. With Aspire, you get a unified toolchain that eliminates complex configs and makes local debugging effortless. Instantly launch and debug your entire app with a single command. Ready to deploy? Aspire lets you publish anywhere—Kubernetes, the cloud, or your own servers. It’s also fully extensible, so you can integrate your favorite tools and services with ease. It provides:
- **Orchestration**: A code-first approach to defining and running distributed applications, managing dependencies, and launch order.
- **Integrations**: Pre-built components for common services (databases, caches, message brokers) with automatic configuration.
- **Tooling**: A developer dashboard for real-time monitoring of logs, traces, metrics, and resource health.
- **Service Discovery**: Automatic service-to-service communication without hardcoded endpoints.
- **Observability**: Built-in OpenTelemetry support for distributed tracing, metrics, and structured logging.
## ABP Integration
When you enable .NET Aspire in an ABP microservice solution, you get a fully integrated development experience where:
- All microservices, gateways, and applications are orchestrated through a single entry point (AppHost).
- Infrastructure containers (databases, Redis, RabbitMQ, Elasticsearch, etc.) are managed as code.
- OpenTelemetry, health checks, and service discovery are automatically configured for all projects via the shared ServiceDefaults project.
## Enabling Aspire
When creating a new microservice solution via ABP Studio:
1. In the solution creation wizard, look for the **".NET Aspire Integration"** step.
2. Toggle the option to **enable .NET Aspire**.
3. Complete the wizard—Aspire projects will be generated along with your solution.
![Enable Aspire in ABP Studio](images/aspire-configuration.png)
## Solution Structure Changes
When Aspire is enabled, two additional projects are added to your solution:
![Aspire Solution Structure](images/aspire-solution-structure.png)
### AppHost (Orchestrator)
[`AppHost`](https://aspire.dev/get-started/app-host/) is the .NET Aspire orchestrator project that declares all resources (services, databases, containers, applications) and their dependencies in C# code. All services, gateways, and applications in the solution have their project references added to `AppHost`.
**Why is it added?**
- Centralized orchestration: Start your entire microservice ecosystem with a single command.
- Code-first infrastructure: Databases, Redis, RabbitMQ, Elasticsearch, and observability tools are defined programmatically.
- Dependency management: `AppHost` ensures services start in the correct order using `WaitFor()` declarations.
- Automatic configuration: Connection strings, endpoints, and environment variables are injected automatically.
**Key files in AppHost:**
| File | Purpose |
|--------|------------|
| `AppHost.cs` | Entry point—creates the distributed application builder and adds all resources |
| `AppHostExtensions.cs` | Extension methods for adding infrastructures, databases, microservices, gateways, and applications |
**What it manages:**
- Database servers (SQL Server, PostgreSQL, MySQL, or MongoDB)
- Per-service databases
- Redis (caching)
- RabbitMQ (messaging)
- Elasticsearch + Kibana (logging)
- Prometheus + Grafana (metrics)
- Jaeger (tracing)
- OpenTelemetry Collector
- All microservices, gateways, and web applications
![Aspire AppHost Resource Topology](images/aspire-apphost-topology.png)
### ServiceDefaults
[`ServiceDefaults`](https://aspire.dev/fundamentals/service-defaults/) is a shared library that provides common cloud-native configuration for all projects in the solution. The `ServiceDefaults` project reference is added to all services, gateways, and applications in the solution.
**Why is it added?**
- Consistency: Every service uses the same observability, health check, and resilience patterns.
- Less boilerplate: Add `builder.AddServiceDefaults()` once, get all defaults automatically.
- Production-ready: OpenTelemetry, health endpoints, and HTTP resilience are preconfigured.
**What it provides:**
| Feature | Description |
|---------|-------------|
| OpenTelemetry | Tracing, metrics, and structured logging with automatic instrumentation |
| Health Checks | `/health` and `/alive` endpoints for Kubernetes-style probes |
| Service Discovery | Automatic resolution of service endpoints |
| HTTP Resilience | Retry policies, timeouts, and circuit breakers for HTTP clients |
**Usage example:**
```csharp
var builder = WebApplication.CreateBuilder(args);
builder.AddServiceDefaults(); // Adds all cloud-native defaults
// ... rest of configuration
```
## Running the Solution
### Without Aspire
1. Open **Solution Runner** in ABP Studio.
2. Start all resources in Solution Runner (services, gateways, applications, and tools such as databases, Redis, RabbitMQ, etc.) individually or collectively using the `Default` profile.
![Solution Runner without Aspire](images/solution-runner-default-profile.png)
### With Aspire
1. Open **Solution Runner** in ABP Studio.
2. Select the **Aspire** profile.
3. Run `MyCompanyName.MyProjectName.AppHost`.
4. AppHost automatically:
- Starts all infrastructure containers (database, Redis, RabbitMQ, Elasticsearch, etc.).
- Launches all microservices, gateways, and applications in dependency order.
- Injects connection strings and environment variables.
- Opens the Aspire Dashboard for monitoring.
![Solution Runner with Aspire](images/solution-runner-aspire-profile.png)
## Aspire Dashboard
The dashboard enables real-time tracking of key aspects of your app, including logs, traces, and environment configurations. It's designed to enhance the development experience by providing a clear and insightful view of your app's state and structure.
Key features of the dashboard include:
- Real-time tracking of logs, traces, and environment configurations.
- User interface to stop, start, and restart resources.
- Collects and displays logs and telemetry; view structured logs, traces, and metrics in an intuitive UI.
- Enhanced debugging with GitHub Copilot, your AI-powered assistant built into the dashboard.
### Opening the Dashboard
When AppHost starts, the Aspire Dashboard opens automatically in ABP Studio's built-in browser at `https://localhost:15105`. Alternatively, you can right-click on AppHost in Solution Runner and select **Browse** to open it manually.
![Aspire Dashboard Login](images/aspire-dashboard-login.png)
**Dashboard login token**: `1q2w3E*` (default, configurable via launch settings)
### Dashboard Features
The dashboard includes several tabs, each offering different insights into your application:
#### Resources
View the status of all resources in your application, including projects, containers, and executables. Monitor health checks, view environment variables, and access endpoints for each resource.
![Aspire Dashboard Resources Tab](images/aspire-dashboard-resources.png)
#### Console
Display console logs from all resources in real-time. Filter by resource and log level to quickly find relevant information during development and debugging.
![Aspire Dashboard Console Tab](images/aspire-dashboard-console.png)
#### Structured Logs
View structured logs from all resources with advanced filtering capabilities. Search and filter logs by resource, log level, timestamp, and custom properties to diagnose issues efficiently.
![Aspire Dashboard Structured Logs Tab](images/aspire-dashboard-structured-logs.png)
#### Traces
Explore distributed traces across your microservices to understand request flows and identify performance bottlenecks. Visualize how requests propagate through different services and examine timing information.
![Aspire Dashboard Traces Tab](images/aspire-dashboard-traces.png)
#### Metrics
Monitor real-time metrics including HTTP requests, response times, garbage collection, memory usage, and custom metrics. Visualize metric trends with interactive charts to understand application performance.
![Aspire Dashboard Metrics Tab](images/aspire-dashboard-metrics.png)
## Tools and Their Management UIs
AppHost pre-configures the following observability and tools. The URLs below are for their **management/dashboard interfaces** (these tools may expose additional internal endpoints for service communication).
All URLs and configurations are defined in the `AppHost` project. If you need to change ports or other settings, you can modify them in the `AppHost` project.
After running AppHost, you can access these tools either by opening the URLs directly in your browser or via Solution Runner **Tools** tab.
### Database Management System Admin Tool
The database management admin tool varies by database type:
| Database | Tool | URL |
|----------|------|-----|
| SQL Server | DBeaver CloudBeaver | `http://localhost:8081` |
| MySQL | phpMyAdmin | `http://localhost:8082` |
| PostgreSQL | pgAdmin | `http://localhost:8083` |
| MongoDB | Mongo Express | `http://localhost:8084` |
For example, if using PostgreSQL, access **pgAdmin** at `http://localhost:8083` or via Solution Runner Tools tab:
![pgAdmin Dashboard](images/aspire-database-postgre-pgadmin.png)
### Grafana
**URL**: `http://localhost:3001`
**Credentials**: `admin` / `admin`
Grafana is a visualization and analytics platform for monitoring metrics. It provides interactive dashboards with charts and graphs for tracking application performance.
![Grafana Dashboard](images/aspire-grafana-dashboard.png)
### Jaeger
**URL**: `http://localhost:16686`
**Credentials**: No authentication required
Jaeger is a distributed tracing system to monitor and troubleshoot problems on interconnected software components called microservices.
![Jaeger Traces](images/aspire-jaeger-traces.png)
### Kibana
**URL**: `http://localhost:5601`
**Credentials**: No authentication required
Kibana is a visualization tool for Elasticsearch data. It provides search and data visualization capabilities for logs stored in Elasticsearch.
![Kibana Dashboard](images/aspire-kibana-dashboard.png)
### Prometheus
**URL**: `http://localhost:9090`
**Credentials**: No authentication required
Prometheus is a monitoring and alerting toolkit. It collects and stores metrics as time series data, allowing you to query and analyze application performance.
![Prometheus Dashboard](images/aspire-prometheus-dashboard.png)
### RabbitMQ Management
**URL**: `http://localhost:15672`
**Credentials**: `guest` / `guest`
RabbitMQ Management UI provides a web-based interface for managing and monitoring RabbitMQ message broker, including queues, exchanges, and message flows.
![RabbitMQ Management](images/aspire-rabbitmq-management.png)
### Redis Insight
**URL**: `http://localhost:5540`
**Credentials**: No authentication required
Redis Insight is a visual tool for Redis that allows you to browse data, run commands, and monitor Redis performance.
![Redis Insight](images/aspire-redis-insight.png)
## Adding New Services, Gateways, or Applications
When you add a new microservice, gateway, or application via **ABP Studio**:
1. `AppHost` is updated automatically - the new project is registered as a resource with appropriate configurations.
2. `ServiceDefaults` is referenced - the new project gets cloud-native defaults.
> You don't need to manually edit `AppHost` in most cases.
## Adding a Resource Manually
If you need to add a resource manually (not via **ABP Studio**), follow these steps:
### 1. Reference ServiceDefaults in your new project
```xml
<ProjectReference Include="..\..\..\aspire\service-defaults\MyCompanyName.MyProjectName.ServiceDefaults\MyCompanyName.MyProjectName.ServiceDefaults.csproj" />
```
> Adjust the path as necessary based on your solution structure.
### 2. Add ServiceDefaults in Program.cs
```csharp
var builder = WebApplication.CreateBuilder(args);
builder.AddServiceDefaults();
// ... your configuration
```
### 3. Add Project Reference to AppHost
Add a reference to your resource project in `MySolutionName.MyProjectName.AppHost/MySolutionName.MyProjectName.AppHost.csproj`:
```xml
<ProjectReference Include="..\..\services\myresource\src\MySolutionName.MyProjectName.MyResource\MySolutionName.MyProjectName.MyResource.csproj" />
```
### 4. Register Resource in AppHost
Edit `AppHostExtensions.cs` and add your resource in the `AddAdditionalResources` method:
```csharp
var myResource = builder
.AddProject<Projects.MySolutionName_MyProjectName_ServiceName>("myresource", "MySolutionName.MyProjectName.MyResource")
.WaitFor(databases.AdministrationDb)
.WaitFor(databases.IdentityDb)
.WaitFor(databases.MyResourceDb)
.WaitFor(databases.AuditLoggingDb)
.WaitFor(databases.SaasDb)
.WaitFor(databases.LanguageManagementDb)
.WaitFor(redis)
.WaitFor(rabbitMq)
.WithReference(databases.AdministrationDb)
.WithReference(databases.IdentityDb)
.WithReference(databases.BlobStoringDb)
.WithReference(databases.MyResourceDb)
.WithReference(databases.AuditLoggingDb)
.WithReference(databases.SaasDb)
.WithReference(databases.LanguageManagementDb)
.ConfigureRabbitMq(rabbitMq, infrastructureDefaultUser, infrastructureDefaultUserPassword)
.ConfigureRedis(redis)
.ConfigureElasticSearch(elasticsearch);
applicationResources["MyResource"] = myResource;
```
> Adjust the dependencies and configurations as necessary.
### 5. Configure Gateway (if needed)
If your resource should be accessible through a gateway, add the gateway configuration in the `AddAdditionalResources` method:
```csharp
var webgateway = applicationResources.FirstOrDefault(x => x.Key == "WebGateway").Value;
if (webgateway != null)
{
webgateway
.WaitFor(applicationResources["MyResource"])
.WithReference(applicationResources["MyResource"])
.WithEnvironment("ReverseProxy__Clusters__MyResource__Destinations__MyResource__Address", "http://MyResource");
}
```
### 6. Configure Authentication Server (if needed)
If your resource needs to be added to `CORS` and `RedirectAllowedUrls` configuration for the authentication server, update the `allowedUrls` variable in the `ConfigureAuthServer` method:
```csharp
var allowedUrls = ReferenceExpression.Create($"{applicationResources["MyResource"].GetEndpoint("http")},...");
```
### 7. Add Database (if needed)
If your resource requires a dedicated database, add it in the `AddDatabases` method:
```csharp
var myResourceDb = databaseServers.Postgres.AddDatabase("MyResource", "MySolutionName.MyProjectName_MyResource");
```
> Adjust the database management system as necessary.
### 8. Add to Solution Runner Profiles (optional)
To run your resource in **Solution Runner** profiles(Default or Aspire), add it following the instructions in the [Studio running applications documentation](../../studio/running-applications.md#add).
## Deploying the Application
.NET Aspire supports deployment to Azure Container Apps, Kubernetes, and other cloud platforms. For detailed deployment guidance, see the official documentation: [.NET Aspire Deployment](https://aspire.dev/deployment/overview/)
To learn more about .NET Aspire, visit: https://aspire.dev/get-started/what-is-aspire/

4
docs/en/solution-templates/microservice/helm-charts-and-kubernetes.md

@ -11,8 +11,8 @@
//[doc-nav]
{
"Next": {
"Name": "Miscellaneous guides in the Microservice solution",
"Path": "solution-templates/microservice/guides"
"Name": "Aspire Integration in the Microservice solution",
"Path": "solution-templates/microservice/aspire-integration"
}
}
````

BIN
docs/en/solution-templates/microservice/images/aspire-apphost-topology.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 246 KiB

BIN
docs/en/solution-templates/microservice/images/aspire-configuration.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

BIN
docs/en/solution-templates/microservice/images/aspire-dashboard-console.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 541 KiB

BIN
docs/en/solution-templates/microservice/images/aspire-dashboard-login.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 KiB

BIN
docs/en/solution-templates/microservice/images/aspire-dashboard-metrics.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 197 KiB

BIN
docs/en/solution-templates/microservice/images/aspire-dashboard-resources.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 238 KiB

BIN
docs/en/solution-templates/microservice/images/aspire-dashboard-structured-logs.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 232 KiB

BIN
docs/en/solution-templates/microservice/images/aspire-dashboard-traces.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 KiB

BIN
docs/en/solution-templates/microservice/images/aspire-database-postgre-pgadmin.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 262 KiB

BIN
docs/en/solution-templates/microservice/images/aspire-grafana-dashboard.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 376 KiB

BIN
docs/en/solution-templates/microservice/images/aspire-jaeger-traces.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 262 KiB

BIN
docs/en/solution-templates/microservice/images/aspire-kibana-dashboard.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 442 KiB

BIN
docs/en/solution-templates/microservice/images/aspire-prometheus-dashboard.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 440 KiB

BIN
docs/en/solution-templates/microservice/images/aspire-rabbitmq-management.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 249 KiB

BIN
docs/en/solution-templates/microservice/images/aspire-redis-insight.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 384 KiB

BIN
docs/en/solution-templates/microservice/images/aspire-solution-structure.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

BIN
docs/en/solution-templates/microservice/images/solution-runner-aspire-profile.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

BIN
docs/en/solution-templates/microservice/images/solution-runner-default-profile.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

9
framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/StaticPermissionDefinitionChangedEvent.cs

@ -0,0 +1,9 @@
using System;
namespace Volo.Abp.Authorization.Permissions;
[Serializable]
public class StaticPermissionDefinitionChangedEvent
{
}

134
framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/StaticPermissionDefinitionStore.cs

@ -6,76 +6,72 @@ using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Volo.Abp.DependencyInjection;
using Volo.Abp.StaticDefinitions;
namespace Volo.Abp.Authorization.Permissions;
public class StaticPermissionDefinitionStore : IStaticPermissionDefinitionStore, ISingletonDependency
{
protected IDictionary<string, PermissionGroupDefinition> PermissionGroupDefinitions => _lazyPermissionGroupDefinitions.Value.Item1;
private readonly Lazy<(Dictionary<string, PermissionGroupDefinition>, List<PermissionDefinition>)> _lazyPermissionGroupDefinitions;
protected IDictionary<string, PermissionDefinition> PermissionDefinitions => _lazyPermissionDefinitions.Value;
private readonly Lazy<Dictionary<string, PermissionDefinition>> _lazyPermissionDefinitions;
protected IList<PermissionDefinition> ResourcePermissionDefinitions => _lazyPermissionGroupDefinitions.Value.Item2;
protected IServiceProvider ServiceProvider { get; }
protected AbpPermissionOptions Options { get; }
private readonly IServiceProvider _serviceProvider;
protected IStaticDefinitionCache<PermissionGroupDefinition, (Dictionary<string, PermissionGroupDefinition>, List<PermissionDefinition>)> GroupCache { get; }
protected IStaticDefinitionCache<PermissionDefinition, Dictionary<string, PermissionDefinition>> DefinitionCache { get; }
public StaticPermissionDefinitionStore(
IServiceProvider serviceProvider,
IOptions<AbpPermissionOptions> options)
IOptions<AbpPermissionOptions> options,
IStaticDefinitionCache<PermissionGroupDefinition, (Dictionary<string, PermissionGroupDefinition>, List<PermissionDefinition>)> groupCache,
IStaticDefinitionCache<PermissionDefinition, Dictionary<string, PermissionDefinition>> definitionCache)
{
_serviceProvider = serviceProvider;
ServiceProvider = serviceProvider;
Options = options.Value;
GroupCache = groupCache;
DefinitionCache = definitionCache;
}
_lazyPermissionDefinitions = new Lazy<Dictionary<string, PermissionDefinition>>(
CreatePermissionDefinitions,
isThreadSafe: true
);
_lazyPermissionGroupDefinitions = new Lazy<(Dictionary<string, PermissionGroupDefinition>, List<PermissionDefinition>)>(
CreatePermissionGroupDefinitions,
isThreadSafe: true
);
public async Task<PermissionDefinition?> GetOrNullAsync(string name)
{
var defs = await GetPermissionDefinitionsAsync();
return defs.GetOrDefault(name);
}
protected virtual Dictionary<string, PermissionDefinition> CreatePermissionDefinitions()
public virtual async Task<IReadOnlyList<PermissionDefinition>> GetPermissionsAsync()
{
var permissions = new Dictionary<string, PermissionDefinition>();
var defs = await GetPermissionDefinitionsAsync();
return defs.Values.ToImmutableList();
}
foreach (var groupDefinition in PermissionGroupDefinitions.Values)
{
foreach (var permission in groupDefinition.Permissions)
{
AddPermissionToDictionaryRecursively(permissions, permission);
}
}
public virtual async Task<PermissionDefinition?> GetResourcePermissionOrNullAsync(string resourceName, string name)
{
var (_, resourcePermissions) = await GetPermissionGroupDefinitionsAsync();
return resourcePermissions.FirstOrDefault(p => p.ResourceName == resourceName && p.Name == name);
}
return permissions;
public virtual async Task<IReadOnlyList<PermissionDefinition>> GetResourcePermissionsAsync()
{
var (_, resourcePermissions) = await GetPermissionGroupDefinitionsAsync();
return resourcePermissions.ToImmutableList();
}
protected virtual void AddPermissionToDictionaryRecursively(
Dictionary<string, PermissionDefinition> permissions,
PermissionDefinition permission)
public async Task<IReadOnlyList<PermissionGroupDefinition>> GetGroupsAsync()
{
if (permissions.ContainsKey(permission.Name))
{
throw new AbpException("Duplicate permission name: " + permission.Name);
}
var (groups, _) = await GetPermissionGroupDefinitionsAsync();
return groups.Values.ToImmutableList();
}
permissions[permission.Name] = permission;
protected virtual async Task<(Dictionary<string, PermissionGroupDefinition>, List<PermissionDefinition>)> GetPermissionGroupDefinitionsAsync()
{
return await GroupCache.GetOrCreateAsync(CreatePermissionGroupDefinitionsAsync);
}
foreach (var child in permission.Children)
{
AddPermissionToDictionaryRecursively(permissions, child);
}
protected virtual async Task<Dictionary<string, PermissionDefinition>> GetPermissionDefinitionsAsync()
{
return await DefinitionCache.GetOrCreateAsync(CreatePermissionDefinitionsAsync);
}
protected virtual (Dictionary<string, PermissionGroupDefinition>, List<PermissionDefinition>) CreatePermissionGroupDefinitions()
protected virtual Task<(Dictionary<string, PermissionGroupDefinition>, List<PermissionDefinition>)> CreatePermissionGroupDefinitionsAsync()
{
using (var scope = _serviceProvider.CreateScope())
using (var scope = ServiceProvider.CreateScope())
{
var context = new PermissionDefinitionContext(scope.ServiceProvider);
@ -104,38 +100,40 @@ public class StaticPermissionDefinitionStore : IStaticPermissionDefinitionStore,
context.CurrentProvider = null;
return (context.Groups, context.ResourcePermissions);
return Task.FromResult((context.Groups, context.ResourcePermissions));
}
}
public Task<PermissionDefinition?> GetOrNullAsync(string name)
protected virtual async Task<Dictionary<string, PermissionDefinition>> CreatePermissionDefinitionsAsync()
{
return Task.FromResult(PermissionDefinitions.GetOrDefault(name));
}
var permissions = new Dictionary<string, PermissionDefinition>();
public virtual Task<IReadOnlyList<PermissionDefinition>> GetPermissionsAsync()
{
return Task.FromResult<IReadOnlyList<PermissionDefinition>>(
PermissionDefinitions.Values.ToImmutableList()
);
}
var (groups, _) = await GetPermissionGroupDefinitionsAsync();
foreach (var groupDefinition in groups.Values)
{
foreach (var permission in groupDefinition.Permissions)
{
AddPermissionToDictionaryRecursively(permissions, permission);
}
}
public virtual Task<PermissionDefinition?> GetResourcePermissionOrNullAsync(string resourceName, string name)
{
return Task.FromResult<PermissionDefinition?>(ResourcePermissionDefinitions.FirstOrDefault(p => p.ResourceName == resourceName && p.Name == name));
return permissions;
}
public virtual Task<IReadOnlyList<PermissionDefinition>> GetResourcePermissionsAsync()
protected virtual void AddPermissionToDictionaryRecursively(
Dictionary<string, PermissionDefinition> permissions,
PermissionDefinition permission)
{
return Task.FromResult<IReadOnlyList<PermissionDefinition>>(
ResourcePermissionDefinitions.ToImmutableList()
);
}
if (permissions.ContainsKey(permission.Name))
{
throw new AbpException("Duplicate permission name: " + permission.Name);
}
public Task<IReadOnlyList<PermissionGroupDefinition>> GetGroupsAsync()
{
return Task.FromResult<IReadOnlyList<PermissionGroupDefinition>>(
PermissionGroupDefinitions.Values.ToImmutableList()
);
permissions[permission.Name] = permission;
foreach (var child in permission.Children)
{
AddPermissionToDictionaryRecursively(permissions, child);
}
}
}

3
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Utils/ProjectNameValidator.cs

@ -18,8 +18,9 @@ public static class ProjectNameValidator
private static readonly string[] IllegalKeywords = new[]
{
"MauiBlazor",
"Blazor"
};
};
private static void ValidateParentDirectoryString(string projectName)
{

3
framework/src/Volo.Abp.Core/Volo/Abp/Internal/InternalServiceCollectionExtensions.cs

@ -5,6 +5,7 @@ using Volo.Abp.Logging;
using Volo.Abp.Modularity;
using Volo.Abp.Reflection;
using Volo.Abp.SimpleStateChecking;
using Volo.Abp.StaticDefinitions;
namespace Volo.Abp.Internal;
@ -42,7 +43,7 @@ internal static class InternalServiceCollectionExtensions
services.AddAssemblyOf<IAbpApplication>();
services.AddTransient(typeof(ISimpleStateCheckerManager<>), typeof(SimpleStateCheckerManager<>));
services.AddSingleton(typeof(IStaticDefinitionCache<,>), typeof(StaticDefinitionCache<,>));
services.Configure<AbpModuleLifecycleOptions>(options =>
{
options.Contributors.Add<OnPreApplicationInitializationModuleLifecycleContributor>();

11
framework/src/Volo.Abp.Core/Volo/Abp/StaticDefinitions/IStaticDefinitionCache.cs

@ -0,0 +1,11 @@
using System;
using System.Threading.Tasks;
namespace Volo.Abp.StaticDefinitions;
public interface IStaticDefinitionCache<TKey, TValue>
{
Task<TValue> GetOrCreateAsync(Func<Task<TValue>> factory);
Task ClearAsync();
}

30
framework/src/Volo.Abp.Core/Volo/Abp/StaticDefinitions/StaticDefinitionCache.cs

@ -0,0 +1,30 @@
using System;
using System.Threading;
using System.Threading.Tasks;
namespace Volo.Abp.StaticDefinitions;
public class StaticDefinitionCache<TKey, TValue> : IStaticDefinitionCache<TKey, TValue>
{
private Lazy<Task<TValue>>? _lazy;
public virtual async Task<TValue> GetOrCreateAsync(Func<Task<TValue>> factory)
{
var lazy = _lazy;
if (lazy != null)
{
return await lazy.Value;
}
var newLazy = new Lazy<Task<TValue>>(factory, LazyThreadSafetyMode.ExecutionAndPublication);
lazy = Interlocked.CompareExchange(ref _lazy, newLazy, null) ?? newLazy;
return await lazy.Value;
}
public virtual Task ClearAsync()
{
Interlocked.Exchange(ref _lazy, null);
return Task.CompletedTask;
}
}

7
framework/src/Volo.Abp.EntityFrameworkCore.Sqlite/Volo/Abp/EntityFrameworkCore/Sqlite/AbpEntityFrameworkCoreSqliteModule.cs

@ -1,3 +1,5 @@
using System.Linq;
using Microsoft.EntityFrameworkCore.Sqlite.Infrastructure.Internal;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.EntityFrameworkCore.GlobalFilters;
using Volo.Abp.EntityFrameworkCore.Interceptors;
@ -32,7 +34,10 @@ public class AbpEntityFrameworkCoreSqliteModule : AbpModule
{
options.ConfigureDefaultOnConfiguring((dbContext, dbContextOptionsBuilder) =>
{
dbContextOptionsBuilder.AddInterceptors(new SqliteBusyTimeoutSaveChangesInterceptor(sqliteOptions.BusyTimeout.Value));
if (dbContextOptionsBuilder.Options.Extensions.Any(extension => extension is SqliteOptionsExtension))
{
dbContextOptionsBuilder.AddInterceptors(new SqliteBusyTimeoutSaveChangesInterceptor(sqliteOptions.BusyTimeout.Value));
}
}, overrideExisting: false);
});
}

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save