|
Before Width: | Height: | Size: 214 KiB After Width: | Height: | Size: 180 KiB |
|
Before Width: | Height: | Size: 749 KiB After Width: | Height: | Size: 712 KiB |
|
Before Width: | Height: | Size: 779 KiB After Width: | Height: | Size: 709 KiB |
|
Before Width: | Height: | Size: 697 KiB After Width: | Height: | Size: 667 KiB |
|
Before Width: | Height: | Size: 852 KiB After Width: | Height: | Size: 825 KiB |
|
Before Width: | Height: | Size: 738 KiB After Width: | Height: | Size: 714 KiB |
|
Before Width: | Height: | Size: 802 KiB After Width: | Height: | Size: 742 KiB |
|
Before Width: | Height: | Size: 633 KiB After Width: | Height: | Size: 620 KiB |
|
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 1.3 MiB After Width: | Height: | Size: 1.2 MiB |
|
Before Width: | Height: | Size: 1.3 MiB After Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 1.4 MiB After Width: | Height: | Size: 1.4 MiB |
|
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 1.2 MiB |
|
Before Width: | Height: | Size: 2.2 MiB After Width: | Height: | Size: 2.1 MiB |
|
Before Width: | Height: | Size: 602 KiB After Width: | Height: | Size: 594 KiB |
|
Before Width: | Height: | Size: 78 KiB After Width: | Height: | Size: 44 KiB |
@ -0,0 +1,79 @@ |
|||
# ABP.IO Platform 9.3 Final Has Been Released! |
|||
|
|||
We are glad to announce that [ABP](https://abp.io/) 9.3 stable version has been released today. |
|||
|
|||
## What's New With Version 9.3? |
|||
|
|||
All the new features were explained in detail in the [9.3 RC Announcement Post](https://abp.io/community/announcements/announcing-abp-9-3-release-candidate-4dqgiryf), so there is no need to review them again. You can check it out for more details. |
|||
|
|||
## Getting Started with 9.3 |
|||
|
|||
### Creating New Solutions |
|||
|
|||
You can check the [Get Started page](https://abp.io/get-started) to see how to get started with ABP. You can either download [ABP Studio](https://abp.io/get-started#abp-studio-tab) (**recommended**, if you prefer a user-friendly GUI application - desktop application) or use the [ABP CLI](https://abp.io/docs/latest/cli) to create new solutions. |
|||
|
|||
> **Note**: ABP Studio **v1.2.1** has been released with support for **ABP 9.3**. If you already have ABP Studio installed, update it to v1.2.1 (or later, if available) to create new applications targeting 9.3. ABP Studio checks for updates automatically and will prompt you in-app modal to update to the latest version, or you can download the latest installer from the [Studio](https://abp.io/studio) page. See the [upgrading guide](https://abp.io/docs/latest/studio/installation#upgrading) for details. After updating, the New Solution wizard will create applications with ABP 9.3 by default. You can check the [ABP Studio and ABP Startup Template Version Mappings](https://abp.io/docs/latest/studio/version-mapping) documentation to see the corresponding ABP versions for other versions of Studio. |
|||
|
|||
### How to Upgrade an Existing Solution |
|||
|
|||
You can upgrade your existing solutions with either ABP Studio or ABP CLI. In the following sections, both approaches are explained: |
|||
|
|||
### Upgrading via ABP Studio |
|||
|
|||
If you are already using the ABP Studio, you can upgrade it to the latest version. ABP Studio periodically checks for updates in the background, and when a new version of ABP Studio is available, you will be notified through a modal. Then, you can update it by confirming the opened modal. See [the documentation](https://abp.io/docs/latest/studio/installation#upgrading) for more info. |
|||
|
|||
After upgrading the ABP Studio, then you can open your solution in the application, and simply click the **Upgrade ABP Packages** action button to instantly upgrade your solution: |
|||
|
|||
 |
|||
|
|||
### Upgrading via ABP CLI |
|||
|
|||
Alternatively, you can upgrade your existing solution via ABP CLI. First, you need to install the ABP CLI or upgrade it to the latest version. |
|||
|
|||
If you haven't installed it yet, you can run the following command: |
|||
|
|||
```bash |
|||
dotnet tool install -g Volo.Abp.Studio.Cli |
|||
``` |
|||
|
|||
Or to update the existing CLI, you can run the following command: |
|||
|
|||
```bash |
|||
dotnet tool update -g Volo.Abp.Studio.Cli |
|||
``` |
|||
|
|||
After installing/updating the ABP CLI, you can use the [`update` command](https://abp.io/docs/latest/CLI#update) to update all the ABP related NuGet and NPM packages in your solution as follows: |
|||
|
|||
```bash |
|||
abp update |
|||
``` |
|||
|
|||
You can run this command in the root folder of your solution to update all ABP related packages. |
|||
|
|||
## Migration Guides |
|||
|
|||
There are a few breaking changes in this version that may affect your application. Please read the migration guide carefully, if you are upgrading from v9.2: [ABP Version 9.3 Migration Guide](https://abp.io/docs/9.3/release-info/migration-guides/abp-9-3) |
|||
|
|||
## Community News |
|||
|
|||
### New ABP Community Articles |
|||
|
|||
As always, exciting articles have been contributed by the ABP community. I will highlight some of them here: |
|||
|
|||
* [Fahri Gedik](https://abp.io/community/members/fahrigedik) has published 2 new articles: |
|||
* [A Modern Approach to Angular Dependency Injection using inject function](https://abp.io/community/articles/a-modern-approach-to-angular-dependency-injection-using-8np4o1ap) |
|||
* [Angular Application Builder: Transitioning from Webpack to Esbuild](https://abp.io/community/articles/angular-application-builder-transitioning-from-webpack-to-3yzhzfl0) |
|||
* [Benjamin Fadina](https://abp.io/community/members/benjaminsqlserver@gmail.com) has published several videos on various topics such as **Blazor Web Assembly Using ABP.IO**, **CQRS Implementation with MediatR in ABP** and more. You can see all his videos [here](https://abp.io/community/members/benjaminsqlserver@gmail.com). |
|||
* [Mansur Besleney](https://abp.io/community/members/mansur.besleney) has published [How to Build Persistent Background Jobs with ABP Framework and Quartz](https://abp.io/community/articles/how-to-build-persistent-background-jobs-with-abp-framework-n9aloh93) |
|||
* [Halil Ibrahim Kalkan](https://x.com/hibrahimkalkan) has published [Multitenancy with Separate Databases in .NET and ABP](https://abp.io/community/articles/multitenancy-with-separate-databases-in-dotnet-and-abp-51nvl4u9) |
|||
* [Alex Maiereanu](https://abp.io/community/members/alex.maiereanu@3sstudio.com) has published [ABP-Hangfire-AzurePostgreSQL](https://abp.io/community/articles/abphangfireazurepostgresql-s1jnf3yg) |
|||
* [Jack Fistelmann](https://abp.io/community/members/jfistelmann) has published [ABP and maildev](https://abp.io/community/articles/abp-and-maildev-gy13cr1p) |
|||
* [Harsh Gupta](https://abp.io/community/members/harshgupta) has published [How to Add a Module in the ABP.io Application?](https://abp.io/community/articles/how-to-add-a-module-in-the-abp.io-application-sdeajkn6) |
|||
* [Tarık Özdemir](https://abp.io/community/members/mtozdemir) has published [AI-First Architecture for .NET Projects: A Modern Blueprint Inspired by McKinsey](https://abp.io/community/articles/AI-First%20Architecture%20for%20.NET%20Projects%3A%20A%20Modern%20Blueprint-h2wgcoq3) |
|||
* [Liming Ma](https://github.com/maliming) has published [Using Hangfire Dashboard in ABP API Website](https://abp.io/community/articles/using-hangfire-dashboard-in-abp-api-website--r32ox497) |
|||
|
|||
Thanks to the ABP Community for all the content they have published. You can also [post your ABP related (text or video) content](https://abp.io/community/posts/create) to the ABP Community. |
|||
|
|||
## About the Next Version |
|||
|
|||
The next feature version will be 10.0. You can follow the [release planning here](https://github.com/abpframework/abp/milestones). Please [submit an issue](https://github.com/abpframework/abp/issues/new) if you have any problems with this version. |
|||
|
After Width: | Height: | Size: 676 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 9.2 KiB |
|
Before Width: | Height: | Size: 63 KiB After Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 9.6 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 63 KiB After Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 48 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 8.5 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 6.8 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 8.8 KiB |
|
Before Width: | Height: | Size: 79 KiB After Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 9.9 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 9.8 KiB After Width: | Height: | Size: 5.7 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 9.4 KiB |
|
Before Width: | Height: | Size: 70 KiB After Width: | Height: | Size: 48 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 9.2 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 8.0 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 8.6 KiB |
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 63 KiB After Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 126 KiB |
@ -0,0 +1,138 @@ |
|||
# Integration Services in ABP — What they are, when to use them, and how they behave 🚦 |
|||
|
|||
If you’ve been building with ABP for a while, you’ve probably used Application Services for your UI and APIs in your .NET and ASP.NET Core apps. Integration Services are similar—but with a different mission: they exist for service-to-service or module-to-module communication, not for end users. |
|||
|
|||
If you want the formal spec, see the official doc: [Integration Services](../../framework/api-development/integration-services.md). This post is the practical, no-fluff guide. |
|||
|
|||
## What is an Integration Service? |
|||
|
|||
An Integration Service is an application service or ASP.NET Core MVC controller marked with the `[IntegrationService]` attribute. That marker tells ABP “this endpoint is for internal communication.” |
|||
|
|||
- They are not exposed by default (safer for reusable modules and monoliths). |
|||
- When exposed, their route prefix is `/integration-api` (so you can easily protect them at your gateway or firewall). |
|||
- Auditing is disabled by default for them (less noise for machine-to-machine calls). |
|||
|
|||
Quick look: |
|||
|
|||
```csharp |
|||
[IntegrationService] |
|||
public interface IProductIntegrationService : IApplicationService |
|||
{ |
|||
Task<List<ProductDto>> GetProductsByIdsAsync(List<Guid> ids); |
|||
} |
|||
|
|||
public class ProductIntegrationService : ApplicationService, IProductIntegrationService |
|||
{ |
|||
public Task<List<ProductDto>> GetProductsByIdsAsync(List<Guid> ids) |
|||
{ |
|||
// fetch and return minimal product info for other services/modules |
|||
} |
|||
} |
|||
``` |
|||
|
|||
## Are they HTTP endpoints? |
|||
|
|||
- By default: no (they won’t be reachable over HTTP in the ASP.NET Core routing pipeline). |
|||
- If you need them over HTTP (typically for microservices), explicitly enable: |
|||
|
|||
```csharp |
|||
Configure<AbpAspNetCoreMvcOptions>(options => |
|||
{ |
|||
options.ExposeIntegrationServices = true; |
|||
}); |
|||
``` |
|||
|
|||
Once exposed, ABP puts them under `/integration-api/...` instead of `/api/...` in the ASP.NET Core routing pipeline. That’s your hint to restrict them from public internet access. |
|||
|
|||
## Enable auditing (optional) |
|||
|
|||
If you want audit logs for integration calls, enable it explicitly: |
|||
|
|||
```csharp |
|||
Configure<AbpAuditingOptions>(options => |
|||
{ |
|||
options.IsEnabledForIntegrationServices = true; |
|||
}); |
|||
``` |
|||
|
|||
## When should you use Integration Services? |
|||
|
|||
- Internal, synchronous operations between services or modules. |
|||
- You need a “thin” API designed for other services (not for UI): minimal DTOs, no view concerns, predictable contracts. |
|||
- You want to hide these endpoints from public clients, or only allow them inside your private network or k8s cluster. |
|||
- You’re packaging a reusable module that might be used in both monolith and microservice deployments. |
|||
|
|||
## When NOT to use them |
|||
|
|||
- Public APIs or anything intended for browsers/mobile apps → use regular application services/controllers. |
|||
- Asynchronous cross-service workflows → consider domain events + outbox/inbox; use Integration Services for sync calls. |
|||
- Complex, chatty UI endpoints → those belong to your external API surface, not internal integration. |
|||
|
|||
## Common use-cases and examples |
|||
|
|||
- Identity lookups across services: an Ordering service needs basic user info from the Identity service. |
|||
- Permission checks from another module: a CMS module asks a Permission service for access decisions. |
|||
- Product data hydrations: a Cart service needs minimal product details (price, name) from Catalog. |
|||
- Internal admin/maintenance operations that aren’t meant for end users but are needed by other services. |
|||
|
|||
## Example: microservice-to-microservice call |
|||
|
|||
1) Mark and expose the integration service in the target service: |
|||
|
|||
```csharp |
|||
[IntegrationService] |
|||
public interface IUserIntegrationService : IApplicationService |
|||
{ |
|||
Task<UserBriefDto?> FindByIdAsync(Guid id); |
|||
} |
|||
|
|||
Configure<AbpAspNetCoreMvcOptions>(o => o.ExposeIntegrationServices = true); |
|||
``` |
|||
|
|||
2) In the caller service, add an HTTP client proxy only for Integration Services if you like to keep things clean: |
|||
|
|||
```csharp |
|||
services.AddHttpClientProxies( |
|||
typeof(TargetServiceApplicationModule).Assembly, |
|||
remoteServiceConfigurationName: "TargetService", |
|||
asDefaultServices: true, |
|||
applicationServiceTypes: ApplicationServiceTypes.IntegrationServices); |
|||
``` |
|||
|
|||
3) Call it just like a local service (ABP’s HTTP proxy handles the wire): |
|||
|
|||
```csharp |
|||
public class OrderAppService : ApplicationService |
|||
{ |
|||
private readonly IUserIntegrationService _userIntegrationService; |
|||
|
|||
public OrderAppService(IUserIntegrationService userIntegrationService) |
|||
{ |
|||
_userIntegrationService = userIntegrationService; |
|||
} |
|||
|
|||
public async Task PlaceOrderAsync(CreateOrderDto input) |
|||
{ |
|||
var user = await _userIntegrationService.FindByIdAsync(CurrentUser.GetId()); |
|||
// validate user status, continue placing order... |
|||
} |
|||
} |
|||
``` |
|||
|
|||
## Monolith vs. Microservices |
|||
|
|||
- Monolith: keep them unexposed and call via DI in-process. You get the same clear contract with zero network overhead. |
|||
- Microservices: expose them and route behind your gateway. The `/integration-api` prefix makes it easy to firewall/gateway-restrict. |
|||
|
|||
## Practical tips |
|||
|
|||
- Keep integration DTOs lean and stable. These are machine contracts—don’t mix UI concerns. |
|||
- Name them clearly (e.g., `UserIntegrationService`) so intent is obvious. |
|||
- Guard your ASP.NET Core gateway application: block `/integration-api/*` from public traffic. |
|||
- Enable auditing only if you truly need the logs for these calls. |
|||
|
|||
## Further reading |
|||
|
|||
- Official docs: [Integration Services](../../framework/api-development/integration-services.md) |
|||
|
|||
That’s it! Integration Services give you a clean, intentional way to design internal APIs—great in monoliths, essential in microservices. |
|||
|
After Width: | Height: | Size: 4.8 MiB |
|
After Width: | Height: | Size: 377 KiB |
|
After Width: | Height: | Size: 190 KiB |
|
After Width: | Height: | Size: 153 KiB |
|
After Width: | Height: | Size: 1.7 MiB |
@ -0,0 +1,83 @@ |
|||
# 🚀 Best Practices for Azure DevOps CI/CD Pipelines |
|||
|
|||
**CI/CD (Continuous Integration / Continuous Delivery)** is not just fancy tech talk - it's now a must-have for modern software teams. |
|||
Microsoft's **Azure DevOps** helps make these processes easier to manage. |
|||
But how do you create pipelines that work well for your team? Let's look at some practical tips that will make your life easier. |
|||
|
|||
--- |
|||
|
|||
## 1. 📜 Define Your Pipeline as Code |
|||
|
|||
Don't use the manual setup method that's hard to track. Azure DevOps lets you use **YAML files** for your pipelines, which gives you: |
|||
|
|||
- A record of all changes - who made them and when |
|||
- The same setup across all environments |
|||
- The ability to undo changes when something goes wrong |
|||
|
|||
This stops the common problem where something works on one computer but not another. |
|||
|
|||
 |
|||
|
|||
--- |
|||
|
|||
## 2. 🔑 Store Sensitive Information Safely |
|||
|
|||
Never put passwords directly in your code, even temporarily. |
|||
Each environment should have its own settings, and keep sensitive information in **Azure Key Vault** or **Library Variable Groups**. |
|||
|
|||
You'll avoid security problems later. |
|||
|
|||
<!--  --> |
|||
--- |
|||
|
|||
## 3. 🏗️ Keep Building and Releasing Separate |
|||
|
|||
Think of **Building** like cooking a meal - you prepare everything and package it up. |
|||
**Releasing** is like delivering that meal to different people. |
|||
|
|||
Keeping these as separate steps means: |
|||
|
|||
- You create your package once, then send it to multiple places |
|||
- You save time and resources by not rebuilding the same thing over and over |
|||
|
|||
 |
|||
|
|||
--- |
|||
|
|||
## 4. 🧪 Add Automatic Testing |
|||
|
|||
Don't waste time testing the same things manually over and over. |
|||
Set up **different types of tests** to run automatically. When tests run every time you make changes: |
|||
|
|||
- You catch problems before your customers do |
|||
- Your software quality stays high without extra manual work |
|||
|
|||
Azure DevOps has tools to help you see test results easily without searching through technical logs. |
|||
|
|||
--- |
|||
|
|||
## 5. 🛡️ Add Safety Checks |
|||
|
|||
Automatic doesn't mean pushing everything to your live system right away. |
|||
For important environments, add **human approval steps** or **automatic checks** like security scans. |
|||
|
|||
This helps you avoid emergency problems in the middle of the night. |
|||
|
|||
 |
|||
|
|||
|
|||
--- |
|||
|
|||
## ✅ Conclusion |
|||
|
|||
Good Azure DevOps pipelines aren't just about automation - they help you feel confident in your process. |
|||
Remember these main points: |
|||
|
|||
✔ Use YAML files to keep everything visible and trackable |
|||
✔ Keep passwords and sensitive data in secure storage (not in your code) |
|||
✔ Build once, deploy to many places |
|||
✔ Let automatic tests find problems before users do |
|||
✔ Add safety checks for important systems |
|||
|
|||
 |
|||
--- |
|||
@ -0,0 +1,398 @@ |
|||
# ABP Now Supports Angular Standalone Applications |
|||
|
|||
We are excited to announce that **ABP now supports Angular’s standalone component structure** in the latest Studio update. This article walks you through how to generate a standalone application, outlines the migration steps, and highlights the benefits of this shift over traditional module-based architecture. |
|||
|
|||
--- |
|||
|
|||
## Why Standalone? |
|||
|
|||
Angular's standalone component architecture, which is introduced in version 14 and made default in version 19, is a major leap forward for Angular development. Here is why it matters: |
|||
|
|||
### 🔧 Simplified Project Structure |
|||
|
|||
Standalone components eliminate the need for `NgModule` wrappers. This leads to: |
|||
|
|||
- Fewer files to manage |
|||
- Cleaner folder organization |
|||
- Reduced boilerplate |
|||
|
|||
Navigating and understanding your codebase becomes easier for everyone on your team. |
|||
|
|||
### 🚀 Faster Bootstrapping |
|||
|
|||
Standalone apps simplify app initialization: |
|||
|
|||
```ts |
|||
bootstrapApplication(AppComponent, appConfig); |
|||
``` |
|||
|
|||
This avoids the need for `AppModule` and speeds up startup times. |
|||
|
|||
### 📦 Smaller Bundle Sizes |
|||
|
|||
Since components declare their own dependencies, Angular can more effectively tree-shake unused code. Result? Smaller bundle sizes and faster load times. |
|||
|
|||
### 🧪 Easier Testing & Reusability |
|||
|
|||
Standalone components are self-contained. They declare their dependencies within the `imports` array, making them: |
|||
|
|||
- Easier to test in isolation |
|||
- Easier to reuse in different contexts |
|||
|
|||
### 🧠 Clearer Dependency Management |
|||
|
|||
Standalone components explicitly define what they need. No more hidden dependencies buried in shared modules. |
|||
|
|||
### 🔄 Gradual Adoption |
|||
|
|||
You can mix and match standalone and module-based components. This allows for **incremental migration**, reducing risk in larger codebases. Here is the related document for the [standalone migration](https://angular.dev/reference/migrations/standalone). |
|||
|
|||
--- |
|||
|
|||
## Getting Started: Creating a Standalone Angular App |
|||
|
|||
Angular CLI makes it easy to start: |
|||
|
|||
```bash |
|||
ng new my-app |
|||
``` |
|||
|
|||
With Angular 19, new apps follow this bootstrapping model: |
|||
|
|||
```ts |
|||
// main.ts |
|||
import { bootstrapApplication } from "@angular/platform-browser"; |
|||
import { appConfig } from "./app/app.config"; |
|||
import { AppComponent } from "./app/app.component"; |
|||
|
|||
bootstrapApplication(AppComponent, appConfig).catch((err) => |
|||
console.error(err) |
|||
); |
|||
``` |
|||
|
|||
The `app.config.ts` file replaces `AppModule`: |
|||
|
|||
```ts |
|||
// app.config.ts |
|||
import { ApplicationConfig, provideZoneChangeDetection } from "@angular/core"; |
|||
import { provideRouter } from "@angular/router"; |
|||
import { routes } from "./app.routes"; |
|||
|
|||
export const appConfig: ApplicationConfig = { |
|||
providers: [ |
|||
provideZoneChangeDetection({ eventCoalescing: true }), |
|||
provideRouter(routes), |
|||
], |
|||
}; |
|||
``` |
|||
|
|||
Routing is defined in a simple `Routes` array: |
|||
|
|||
```ts |
|||
// app.routes.ts |
|||
import { Routes } from "@angular/router"; |
|||
|
|||
export const routes: Routes = []; |
|||
``` |
|||
|
|||
--- |
|||
|
|||
## ABP Studio Support for Standalone Structure |
|||
|
|||
Starting with the latest release (insert version number here), ABP Studio fully supports Angular's standalone structure. While the new format is encouraged, module-based structure will continue to be supported for backwards compatibility. |
|||
|
|||
To try it out, simply update your ABP Studio to create apps with the latest version. |
|||
|
|||
--- |
|||
|
|||
## What’s New in ABP Studio Templates? |
|||
|
|||
When you generate an app using the latest ABP Studio, the project structure aligns with Angular's standalone architecture. |
|||
|
|||
This migration is split into four parts: |
|||
|
|||
1. **Package updates** |
|||
2. **Schematics updates** |
|||
3. **Suite code generation updates** |
|||
4. **Template refactors** |
|||
|
|||
--- |
|||
|
|||
## Package Migration Details |
|||
|
|||
Migration has been applied to packages in the [ABP GitHub repository](https://github.com/abpframework/abp/tree/dev/npm/ng-packs/packages). Here is an example from the Identity package. |
|||
|
|||
### 🧩 Migrating Components |
|||
|
|||
Components are made standalone, using: |
|||
|
|||
```bash |
|||
ng g @angular/core:standalone |
|||
``` |
|||
|
|||
Example: |
|||
|
|||
```ts |
|||
@Component({ |
|||
selector: 'abp-roles', |
|||
templateUrl: './roles.component.html', |
|||
providers: [...], |
|||
imports: [ |
|||
ReactiveFormsModule, |
|||
LocalizationPipe, |
|||
... |
|||
], |
|||
}) |
|||
export class RolesComponent implements OnInit { ... } |
|||
``` |
|||
|
|||
### 🛣 Updating Routing |
|||
|
|||
Old lazy-loaded routes using `forLazy()`: |
|||
|
|||
```ts |
|||
{ |
|||
path: 'identity', |
|||
loadChildren: () => import('@abp/ng.identity').then(m => m.IdentityModule.forLazy({...})) |
|||
} |
|||
``` |
|||
|
|||
Now replaced with: |
|||
|
|||
```ts |
|||
{ |
|||
path: 'identity', |
|||
loadChildren: () => import('@abp/ng.identity').then(c => c.createRoutes({...})) |
|||
} |
|||
``` |
|||
|
|||
### 🧱 Replacing Module Declarations |
|||
|
|||
The old setup: |
|||
|
|||
```ts |
|||
// identity.module.ts |
|||
@NgModule({ |
|||
imports: [IdentityRoutingModule, RolesComponent, UsersComponent], |
|||
}) |
|||
export class IdentityModule {...} |
|||
``` |
|||
|
|||
```ts |
|||
//identity-routing.module |
|||
const routes: Routes = [...]; |
|||
@NgModule({ |
|||
imports: [RouterModule.forChild(routes)], |
|||
exports: [RouterModule], |
|||
}) |
|||
export class IdentityRoutingModule {} |
|||
``` |
|||
|
|||
New setup: |
|||
|
|||
```ts |
|||
// identity-routes.ts |
|||
export function provideIdentity(options: IdentityConfigOptions = {}): Provider[] { |
|||
return [...]; |
|||
} |
|||
export const createRoutes = (options: IdentityConfigOptions = {}): Routes => [ |
|||
{ |
|||
path: '', |
|||
component: RouterOutletComponent, |
|||
providers: provideIdentity(options), |
|||
children: [ |
|||
{ |
|||
path: 'roles', |
|||
component: ReplaceableRouteContainerComponent, |
|||
data: { |
|||
requiredPolicy: 'AbpIdentity.Roles', |
|||
replaceableComponent: { |
|||
key: eIdentityComponents.Roles, |
|||
defaultComponent: RolesComponent, |
|||
}, |
|||
}, |
|||
title: 'AbpIdentity::Roles', |
|||
}, |
|||
... |
|||
], |
|||
}, |
|||
]; |
|||
``` |
|||
|
|||
--- |
|||
|
|||
## ABP Schematics Migration Details |
|||
|
|||
You can reach details by checking [ABP Schematics codebase](https://github.com/abpframework/abp/tree/dev/npm/ng-packs/packages/schematics). |
|||
|
|||
### 📚 Library creation |
|||
|
|||
When you run the `abp create-lib` command, the prompter will ask you the `templateType`. It supports both module and standalone templates. |
|||
|
|||
```ts |
|||
"templateType": { |
|||
"type": "string", |
|||
"description": "Type of the template", |
|||
"enum": ["module", "standalone"], |
|||
"x-prompt": { |
|||
"message": "Select the type of template to generate:", |
|||
"type": "list", |
|||
"items": [ |
|||
{ "value": "module", "label": "Module Template" }, |
|||
{ "value": "standalone", "label": "Standalone Template" } |
|||
] |
|||
} |
|||
}, |
|||
``` |
|||
|
|||
--- |
|||
|
|||
## ABP Suite Code Generation Migration Details |
|||
|
|||
ABP Suite will also be supporting both structures. If you have a project that is generated with the previous versions, the Suite will detect the structure in that way and generate the related code accordingly. Conversely, here is what is changed for the standalone migration: |
|||
|
|||
**❌ Discarded module files** |
|||
|
|||
```ts |
|||
// entity-one.module.ts |
|||
@NgModule({ |
|||
declarations: [], |
|||
imports: [EntityOneComponent, EntityOneRoutingModule], |
|||
}) |
|||
export class EntityOneModule {} |
|||
``` |
|||
|
|||
```ts |
|||
// entity-one-routing.module.ts |
|||
export const routes: Routes = [ |
|||
{ |
|||
path: "", |
|||
component: EntityOneComponent, |
|||
canActivate: [authGuard, permissionGuard], |
|||
}, |
|||
]; |
|||
|
|||
@NgModule({ |
|||
imports: [RouterModule.forChild(routes)], |
|||
exports: [RouterModule], |
|||
}) |
|||
export class EntityOneRoutingModule {} |
|||
``` |
|||
|
|||
```ts |
|||
// app-routing.module.ts |
|||
{ |
|||
path: 'entity-ones', |
|||
loadChildren: () => |
|||
import('./entity-ones/entity-one/entity-one.module').then(m => m.EntityOneModule), |
|||
}, |
|||
``` |
|||
|
|||
**✅ Added routes configuration** |
|||
|
|||
```ts |
|||
// entity-one.routes.ts |
|||
export const ENTITY_ONE_ROUTES: Routes = [ |
|||
{ |
|||
path: "", |
|||
loadComponent: () => { |
|||
return import("./components/entity-one.component").then( |
|||
(c) => c.EntityOneComponent |
|||
); |
|||
}, |
|||
canActivate: [authGuard, permissionGuard], |
|||
}, |
|||
]; |
|||
``` |
|||
|
|||
```ts |
|||
// app.routes.ts |
|||
{ path: 'entity-ones', children: ENTITY_ONE_ROUTES }, |
|||
``` |
|||
|
|||
--- |
|||
|
|||
## Template Migration Details |
|||
|
|||
### 🧭 Routing: `app.routes.ts` |
|||
|
|||
```ts |
|||
// app.routes.ts |
|||
import { Routes } from '@angular/router'; |
|||
|
|||
export const APP_ROUTES: Routes = [ |
|||
{ |
|||
path: '', |
|||
pathMatch: 'full', |
|||
loadComponent: () => import('./home/home.component').then(m => m.HomeComponent), |
|||
}, |
|||
{ |
|||
path: 'account', |
|||
loadChildren: () => import('@abp/ng.account').then(m => m.createRoutes()), |
|||
}, |
|||
... |
|||
]; |
|||
``` |
|||
|
|||
### ⚙ Configuration: `app.config.ts` |
|||
|
|||
```ts |
|||
// app.config.ts |
|||
export const appConfig: ApplicationConfig = { |
|||
providers: [ |
|||
provideRouter(APP_ROUTES), |
|||
APP_ROUTE_PROVIDER, |
|||
provideAbpCore( |
|||
withOptions({ |
|||
environment, |
|||
registerLocaleFn: registerLocale(), |
|||
... |
|||
}) |
|||
), |
|||
provideAbpOAuth(), |
|||
provideAbpThemeShared(), |
|||
... |
|||
], |
|||
}; |
|||
|
|||
``` |
|||
|
|||
### 🧼 Removed: `shared.module.ts` |
|||
|
|||
This file has been removed to reduce unnecessary shared imports. Components now explicitly import what they need—leading to better encapsulation and less coupling. |
|||
|
|||
--- |
|||
|
|||
## Common Problems |
|||
|
|||
You may encounter these common problems that you would need to manage. |
|||
|
|||
### 1. Missing Imports |
|||
|
|||
In standalone structure, components must declare all their dependencies in `imports`. Forgetting this often causes template errors. |
|||
|
|||
### 2. Mixed Structures |
|||
|
|||
Combining modules and standalone in the same feature leads to confusion. Migrate features fully or keep them module-based. |
|||
|
|||
### 3. Routing Errors |
|||
|
|||
Incorrect migration from `forLazy()` to `createRoutes()` or `loadComponent` can break navigation. Double-check route configs. |
|||
|
|||
### 4. Service Injection |
|||
|
|||
Services provided in old modules may be missing. Add them in the component’s `providers` or `app.config.ts`. |
|||
|
|||
### 5. Shared Module Habit |
|||
|
|||
Reintroducing a shared module reduces the benefits of standalone. Import dependencies directly where needed. |
|||
|
|||
--- |
|||
|
|||
## Conclusion |
|||
|
|||
Angular’s standalone component architecture is a significant improvement for scalability, simplicity, and performance. With latest version of ABP Studio, you can adopt this modern approach with ease—without losing support for existing module-based projects. |
|||
|
|||
**Ready to modernize your Angular development?** |
|||
|
|||
Update your ABP Studio today and start building with standalone power! |
|||
|
Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 70 KiB |
|
Before Width: | Height: | Size: 77 KiB After Width: | Height: | Size: 73 KiB |