@ -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. |
|||
|
|||
 |
|||
|
|||
## Solution Structure Changes |
|||
|
|||
When Aspire is enabled, two additional projects are added to your solution: |
|||
|
|||
 |
|||
|
|||
### 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`. |
|||
|
|||
 |
|||
|
|||
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 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. |
|||
|
|||
 |
|||
|
|||
### 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. |
|||
|
|||
 |
|||
|
|||
#### Structured Logs |
|||
|
|||
View structured logs from all resources with advanced filtering capabilities. Search and filter logs by resource, log level, timestamp, and custom properties. |
|||
|
|||
 |
|||
|
|||
#### Distributed Traces |
|||
|
|||
Explore distributed traces across your microservices to understand request flows and identify performance bottlenecks. |
|||
|
|||
 |
|||
|
|||
#### Metrics |
|||
|
|||
Monitor real-time metrics including HTTP requests, response times, garbage collection, memory usage, and custom metrics. |
|||
|
|||
 |
|||
|
|||
## Pre-Configured Observability Tools |
|||
|
|||
AppHost comes with pre-configured observability and management tools: |
|||
|
|||
### Grafana |
|||
|
|||
Visualization and analytics platform for monitoring metrics with interactive dashboards. |
|||
|
|||
 |
|||
|
|||
### Jaeger |
|||
|
|||
Distributed tracing system to monitor and troubleshoot problems across microservices. |
|||
|
|||
 |
|||
|
|||
### Kibana |
|||
|
|||
Visualization tool for Elasticsearch data with search and data visualization capabilities for logs. |
|||
|
|||
 |
|||
|
|||
### Prometheus |
|||
|
|||
Monitoring and alerting toolkit that collects and stores metrics as time series data. |
|||
|
|||
 |
|||
|
|||
### RabbitMQ Management |
|||
|
|||
Web-based interface for managing and monitoring the RabbitMQ message broker. |
|||
|
|||
 |
|||
|
|||
### Redis Insight |
|||
|
|||
Visual tool for Redis that allows you to browse data, run commands, and monitor performance. |
|||
|
|||
 |
|||
|
|||
### 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 | |
|||
|
|||
 |
|||
|
|||
## 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** |
|||
|
After Width: | Height: | Size: 75 KiB |
|
After Width: | Height: | Size: 52 KiB |
|
After Width: | Height: | Size: 141 KiB |
|
After Width: | Height: | Size: 45 KiB |
|
After Width: | Height: | Size: 56 KiB |
|
After Width: | Height: | Size: 61 KiB |
|
After Width: | Height: | Size: 56 KiB |
|
After Width: | Height: | Size: 67 KiB |
|
After Width: | Height: | Size: 81 KiB |
|
After Width: | Height: | Size: 63 KiB |
|
After Width: | Height: | Size: 104 KiB |
|
After Width: | Height: | Size: 98 KiB |
|
After Width: | Height: | Size: 57 KiB |
|
After Width: | Height: | Size: 82 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 53 KiB |
|
After Width: | Height: | Size: 7.2 KiB |
@ -0,0 +1,475 @@ |
|||
# Building Dynamic XML Sitemaps with ABP Framework |
|||
|
|||
Search Engine Optimization (SEO) is crucial for any web application that wants to be discovered by users. One of the most fundamental SEO practices is providing a comprehensive XML sitemap that helps search engines crawl and index your website efficiently. In this article, we'll use a reusable ABP module that automatically generates dynamic XML sitemaps for both static Razor Pages and dynamic content from your database. |
|||
|
|||
By the end of this tutorial, you'll have a production-ready sitemap solution that discovers your pages automatically, includes dynamic content like blog posts or products, and regenerates sitemaps in the background without impacting performance. |
|||
|
|||
## What is an XML Sitemap? |
|||
|
|||
An XML sitemap is a file that lists all important pages of your website in a structured format that search engines can easily read. It acts as a roadmap for crawlers like Google, Bing, and others, telling them which pages exist, when they were last updated, and how they relate to each other. |
|||
|
|||
For modern web applications with dynamic content, manually maintaining sitemap files quickly becomes impractical. A dynamic sitemap solution that automatically discovers and updates URLs is essential for: |
|||
|
|||
- **Large content sites** with frequently changing blog posts, articles, or products |
|||
- **Multi-tenant applications** where each tenant may have different content |
|||
- **Enterprise applications** with complex page hierarchies |
|||
- **E-commerce platforms** with thousands of product pages |
|||
|
|||
## Why Build a Custom Sitemap Module? |
|||
|
|||
While there are general-purpose sitemap libraries available, building a custom module for ABP Framework provides several advantages: |
|||
|
|||
✅ **Deep ABP Integration**: Leverages ABP's dependency injection, background workers, and module system |
|||
✅ **Automatic Discovery**: Uses ASP.NET Core's Razor Page infrastructure to automatically find pages |
|||
✅ **Type-Safe Configuration**: Strongly-typed attributes and options for configuration |
|||
✅ **Multi-Group Support**: Organize sitemaps by logical groups (main, blog, products, etc.) |
|||
✅ **Background Generation**: Non-blocking sitemap regeneration using ABP's background worker system |
|||
✅ **Repository Integration**: Direct integration with ABP repositories for database entities |
|||
|
|||
## Project Architecture Overview |
|||
|
|||
Before using the module, let's understand its architecture: |
|||
|
|||
 |
|||
|
|||
The sitemap module consists of several key components: |
|||
|
|||
1. **Discovery Layer**: Discovers Razor Pages and their metadata using reflection |
|||
2. **Source Layer**: Defines contracts for providing sitemap items (static pages and dynamic content) |
|||
3. **Collection Layer**: Collects items from all registered sources |
|||
4. **Generation Layer**: Transforms collected items into XML format |
|||
5. **Management Layer**: Orchestrates file generation and background workers |
|||
|
|||
## Installation |
|||
|
|||
To get started, clone the demo repository which includes the sitemap module: |
|||
|
|||
```bash |
|||
git clone https://github.com/salihozkara/AbpSitemapDemo |
|||
cd AbpSitemapDemo |
|||
``` |
|||
|
|||
The repository contains the sitemap module in the `Modules/abp.sitemap/` directory. To use it in your own project, add a project reference: |
|||
|
|||
```xml |
|||
<ProjectReference Include="../Modules/abp.sitemap/Abp.Sitemap.Web/Abp.Sitemap.Web.csproj" /> |
|||
``` |
|||
|
|||
## Module Configuration |
|||
|
|||
After installing the package, add the module to your ABP application's module class: |
|||
|
|||
```csharp |
|||
using Abp.Sitemap.Web; |
|||
|
|||
[DependsOn( |
|||
typeof(SitemapWebModule), // 👈 Add sitemap module |
|||
// ... other dependencies |
|||
)] |
|||
public class YourProjectWebModule : AbpModule |
|||
{ |
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
// Configure sitemap options |
|||
Configure<SitemapOptions>(options => |
|||
{ |
|||
options.BaseUrl = "https://yourdomain.com"; // 👈 Your website URL |
|||
options.FolderPath = "Sitemaps"; // 👈 Where XML files are stored |
|||
options.WorkerPeriod = 3600000; // 👈 Regenerate every hour (in milliseconds) |
|||
}); |
|||
} |
|||
} |
|||
``` |
|||
|
|||
> **Note:** In ABP applications, BaseUrl can be resolved from AppUrlOptions to stay consistent with environment configuration. |
|||
|
|||
That's it! The module is now integrated and will automatically: |
|||
- Discover your Razor Pages |
|||
- Generate sitemap XML files on application startup |
|||
- Regenerate sitemaps in the background every hour |
|||
|
|||
## Usage Examples |
|||
|
|||
Let's explore practical examples of using the sitemap module. You can see complete working examples in the [AbpSitemapDemo repository](https://github.com/salihozkara/AbpSitemapDemo). |
|||
|
|||
### Example 1: Mark Static Pages |
|||
|
|||
The simplest way to include pages in your sitemap is using attributes: |
|||
|
|||
```csharp |
|||
using Abp.Sitemap.Web.Sitemap.Sources.Page.Attributes; |
|||
|
|||
namespace YourProject.Pages; |
|||
|
|||
[IncludeSitemapXml] // 👈 Include in default "Main" group |
|||
public class IndexModel : PageModel |
|||
{ |
|||
public void OnGet() |
|||
{ |
|||
// Your page logic |
|||
} |
|||
} |
|||
|
|||
[IncludeSitemapXml(Group = "Help")] |
|||
public class FaqModel : PageModel |
|||
{ |
|||
public void OnGet() |
|||
{ |
|||
// Your page logic |
|||
} |
|||
} |
|||
``` |
|||
|
|||
These pages will be automatically discovered and included in the sitemap XML files. |
|||
|
|||
### Example 2: Add Dynamic Content from Database |
|||
|
|||
For dynamic content like blog posts, products, or articles, create a custom sitemap source. Here's a complete example using a Book entity: |
|||
|
|||
```csharp |
|||
using Abp.Sitemap.Web.Sitemap.Core; |
|||
using Abp.Sitemap.Web.Sitemap.Sources.Group; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace YourProject.Sitemaps; |
|||
|
|||
public class BookSitemapSource : GroupedSitemapItemSource<Book>, ITransientDependency |
|||
{ |
|||
public BookSitemapSource( |
|||
IReadOnlyRepository<Book> repository, |
|||
IAsyncQueryableExecuter executer) |
|||
: base(repository, executer, group: "Books") // 👈 Creates sitemap-Books.xml |
|||
{ |
|||
Filter = x => x.IsPublished; // 👈 Only published books |
|||
} |
|||
|
|||
protected override Expression<Func<Book, SitemapItem>> Selector => |
|||
book => new SitemapItem( |
|||
book.Id.ToString(), // 👈 Unique identifier |
|||
$"/Books/Detail/{book.Id}", // 👈 URL pattern matching your route |
|||
book.LastModificationTime ?? book.CreationTime // 👈 Last modified date |
|||
) |
|||
{ |
|||
ChangeFrequency = "weekly", |
|||
Priority = 0.7 |
|||
}; |
|||
} |
|||
``` |
|||
|
|||
Key points: |
|||
- Inherits from `GroupedSitemapItemSource<TEntity>` |
|||
- Specifies the entity type (`Book`) |
|||
- Defines a group name ("Books") which creates `sitemap-Books.xml` |
|||
- Uses `Filter` to include only published books |
|||
- Maps entity properties to sitemap URLs using `Selector` |
|||
- Automatically registered via `ITransientDependency` |
|||
|
|||
### Example 3: Category-Based Dynamic Content |
|||
|
|||
For content with categories, you can build more complex URL patterns: |
|||
|
|||
```csharp |
|||
using Abp.Sitemap.Web.Sitemap.Core; |
|||
using Abp.Sitemap.Web.Sitemap.Sources.Group; |
|||
|
|||
namespace YourProject.Sitemaps; |
|||
|
|||
public class ArticleSitemapSource : GroupedSitemapItemSource<Article>, ITransientDependency |
|||
{ |
|||
public ArticleSitemapSource( |
|||
IReadOnlyRepository<Article> repository, |
|||
IAsyncQueryableExecuter executer) |
|||
: base(repository, executer, "Articles") |
|||
{ |
|||
// Multiple filter conditions |
|||
Filter = x => x.IsPublished && |
|||
!x.IsDeleted && |
|||
x.PublishDate <= DateTime.Now; |
|||
} |
|||
|
|||
protected override Expression<Func<Article, SitemapItem>> Selector => |
|||
article => new SitemapItem( |
|||
article.Id.ToString(), |
|||
$"/blog/{article.Category.Slug}/{article.Slug}", // 👈 Category-based URL |
|||
article.LastModificationTime ?? article.CreationTime |
|||
); |
|||
} |
|||
``` |
|||
|
|||
This example demonstrates: |
|||
- Multiple filter conditions for complex business logic |
|||
- Building URLs with category slugs |
|||
|
|||
## Testing Your Sitemaps |
|||
|
|||
After configuring the module, test your sitemap generation: |
|||
|
|||
### 1. Run Your Application |
|||
|
|||
```bash |
|||
dotnet run |
|||
``` |
|||
|
|||
The sitemaps are automatically generated on application startup. |
|||
|
|||
### 2. Check Generated Files |
|||
|
|||
Navigate to `{WebProject}/Sitemaps/` directory (at the root of your web project): |
|||
|
|||
``` |
|||
{WebProject} |
|||
└── Sitemaps/ |
|||
├── sitemap.xml # Main group (static pages) |
|||
├── sitemap-Books.xml # Books from database |
|||
├── sitemap-Articles.xml # Articles from database |
|||
└── sitemap-Help.xml # Help pages |
|||
``` |
|||
|
|||
### 3. Verify XML Content |
|||
|
|||
Open `sitemap-Books.xml` and verify the structure: |
|||
|
|||
```xml |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> |
|||
<url> |
|||
<loc>https://yourdomain.com/Books/Detail/3a071e39-12c9-48d7-8c1e-3b4f5c6d7e8f</loc> |
|||
<lastmod>2025-12-13</lastmod> |
|||
</url> |
|||
<url> |
|||
<loc>https://yourdomain.com/Books/Detail/7b8c9d0e-1f2a-3b4c-5d6e-7f8g9h0i1j2k</loc> |
|||
<lastmod>2025-12-10</lastmod> |
|||
</url> |
|||
</urlset> |
|||
``` |
|||
|
|||
### 4. Test in Browser |
|||
|
|||
Visit the sitemap URLs directly (the module serves them from the root path): |
|||
- Main sitemap: `https://localhost:5001/sitemap.xml` |
|||
- Books sitemap: `https://localhost:5001/sitemap-Books.xml` |
|||
|
|||
> **Note:** The sitemaps are stored in `{WebProject}/Sitemaps/` directory and served directly from the root URL. |
|||
|
|||
## Advanced Configuration |
|||
|
|||
### Custom Regeneration Schedule |
|||
|
|||
Control when sitemaps are regenerated using cron expressions: |
|||
|
|||
```csharp |
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
Configure<SitemapOptions>(options => |
|||
{ |
|||
options.BaseUrl = "https://yourdomain.com"; |
|||
options.WorkerCronExpression = "0 0 2 * * ?"; // 👈 Every day at 2 AM |
|||
// Or use period in milliseconds: |
|||
// options.WorkerPeriod = 7200000; // 2 hours |
|||
}); |
|||
} |
|||
``` |
|||
|
|||
### Environment-Specific Configuration |
|||
|
|||
Use different settings for development and production: |
|||
|
|||
```csharp |
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
var configuration = context.Services.GetConfiguration(); |
|||
var hostingEnvironment = context.Services.GetHostingEnvironment(); |
|||
|
|||
Configure<SitemapOptions>(options => |
|||
{ |
|||
if (hostingEnvironment.IsDevelopment()) |
|||
{ |
|||
options.BaseUrl = "https://localhost:5001"; |
|||
options.WorkerPeriod = 300000; // 5 minutes for testing |
|||
} |
|||
else |
|||
{ |
|||
options.BaseUrl = configuration["App:SelfUrl"]!; |
|||
options.WorkerPeriod = 3600000; // 1 hour in production |
|||
} |
|||
|
|||
options.FolderPath = "Sitemaps"; |
|||
}); |
|||
} |
|||
``` |
|||
|
|||
### Manual Sitemap Generation |
|||
|
|||
Trigger sitemap generation manually (useful for admin panels): |
|||
|
|||
```csharp |
|||
using Abp.Sitemap.Web.Sitemap.Management; |
|||
|
|||
public class SitemapManagementService : ITransientDependency |
|||
{ |
|||
private readonly SitemapFileGenerator _generator; |
|||
|
|||
public SitemapManagementService(SitemapFileGenerator generator) |
|||
{ |
|||
_generator = generator; |
|||
} |
|||
|
|||
[Authorize("Admin")] |
|||
public async Task RegenerateSitemapsAsync() |
|||
{ |
|||
await _generator.GenerateAsync(); // 👈 Manual regeneration |
|||
} |
|||
} |
|||
``` |
|||
|
|||
## Real-World Use Cases |
|||
|
|||
Here are practical scenarios where the sitemap module excels: |
|||
|
|||
### E-Commerce Platform |
|||
```csharp |
|||
// Products grouped by category |
|||
public class ProductSitemapSource : GroupedSitemapItemSource<Product> |
|||
{ |
|||
// Automatically includes all active products with stock |
|||
} |
|||
|
|||
// Separate sitemap for categories |
|||
public class CategorySitemapSource : GroupedSitemapItemSource<Category> |
|||
{ |
|||
// All browsable categories |
|||
} |
|||
|
|||
// Brand pages |
|||
public class BrandSitemapSource : GroupedSitemapItemSource<Brand> |
|||
{ |
|||
// All active brands |
|||
} |
|||
``` |
|||
|
|||
Result: `sitemap-Products.xml`, `sitemap-Categories.xml`, `sitemap-Brands.xml` |
|||
|
|||
### Content Management System |
|||
```csharp |
|||
// Blog posts by date |
|||
public class BlogPostSitemapSource : GroupedSitemapItemSource<BlogPost> |
|||
{ |
|||
// Filter by published date, priority based on view count |
|||
} |
|||
|
|||
// Static CMS pages |
|||
[IncludeSitemapXml] |
|||
public class AboutUsModel : PageModel { } |
|||
``` |
|||
|
|||
## Best Practices |
|||
|
|||
### 1. Group Related Content |
|||
Organize your sitemaps logically: |
|||
```csharp |
|||
// ✅ Good: Logical grouping |
|||
"Products", "Categories", "Brands", "Blog", "Help" |
|||
|
|||
// ❌ Bad: Everything in one group |
|||
"Main" // Contains 50,000 mixed URLs |
|||
``` |
|||
|
|||
### 2. Use Filters Wisely |
|||
```csharp |
|||
// ✅ Good: Only published, non-deleted content |
|||
Filter = x => x.IsPublished && |
|||
!x.IsDeleted && |
|||
x.PublishDate <= DateTime.Now |
|||
|
|||
// ❌ Bad: Including draft content |
|||
Filter = x => true // Everything included |
|||
``` |
|||
|
|||
### 3. Keep URLs Clean |
|||
```csharp |
|||
// ✅ Good: SEO-friendly URLs |
|||
$"/products/{product.Slug}" |
|||
$"/blog/{year}/{month}/{article.Slug}" |
|||
|
|||
// ❌ Bad: Technical IDs exposed |
|||
$"/product-detail?id={product.Id}" |
|||
``` |
|||
|
|||
## Troubleshooting |
|||
|
|||
### Sitemap Not Generated |
|||
**Problem:** No XML files in `{WebProject}/Sitemaps/` |
|||
|
|||
**Solutions:** |
|||
1. Check module is added to dependencies |
|||
2. Verify `SitemapOptions.BaseUrl` is configured |
|||
3. Check application logs for errors |
|||
4. Ensure the web project directory has write permissions |
|||
|
|||
### Pages Not Appearing |
|||
**Problem:** Some pages missing from sitemap |
|||
|
|||
**Solutions:** |
|||
1. Verify `[IncludeSitemapXml]` attribute is present |
|||
2. Check namespace imports: `using Abp.Sitemap.Web.Sitemap.Sources.Page.Attributes;` |
|||
3. Ensure PageModel classes are public |
|||
4. Check filter conditions in custom sources |
|||
|
|||
### Background Worker Not Running |
|||
**Problem:** Sitemaps not regenerating automatically |
|||
|
|||
**Solutions:** |
|||
1. Check `SitemapOptions.WorkerPeriod` is set |
|||
2. Verify background workers are enabled in ABP configuration |
|||
3. Check application logs for worker errors |
|||
|
|||
## Performance Considerations |
|||
|
|||
### Caching Strategy |
|||
Consider adding caching for frequently accessed sitemaps: |
|||
|
|||
```csharp |
|||
public class CachedSitemapFileGenerator : ITransientDependency |
|||
{ |
|||
private readonly SitemapFileGenerator _generator; |
|||
private readonly IDistributedCache _cache; |
|||
|
|||
public async Task<string> GetOrGenerateAsync(string group) |
|||
{ |
|||
var cacheKey = $"Sitemap:{group}"; |
|||
var cached = await _cache.GetStringAsync(cacheKey); |
|||
|
|||
if (cached != null) |
|||
return cached; |
|||
|
|||
await _generator.GenerateAsync(); |
|||
// Read and cache... |
|||
} |
|||
} |
|||
``` |
|||
|
|||
## Conclusion |
|||
|
|||
The ABP Sitemap module provides a production-ready solution for dynamic sitemap generation in ABP Framework applications. By leveraging ABP's architecture—dependency injection, repository pattern, and background workers—the module automatically discovers pages, includes dynamic content, and regenerates sitemaps without manual intervention. |
|||
|
|||
Key benefits: |
|||
✅ **Zero Configuration** for basic scenarios |
|||
✅ **Type-Safe** attribute-based configuration |
|||
✅ **Extensible** for complex business logic |
|||
✅ **Performance** optimized with background processing |
|||
✅ **SEO-Friendly** following XML sitemap standards |
|||
|
|||
Whether you're building a blog, e-commerce platform, or enterprise application, this module provides a solid foundation for search engine optimization. |
|||
|
|||
## Additional Resources |
|||
|
|||
### Documentation |
|||
- [ABP Framework Documentation](https://abp.io/docs/latest/) |
|||
- [ABP Background Workers](https://abp.io/docs/latest/framework/infrastructure/background-workers) |
|||
- [ABP Repository Pattern](https://abp.io/docs/latest/framework/architecture/domain-driven-design/repositories) |
|||
- [ABP Dependency Injection](https://abp.io/docs/latest/framework/fundamentals/dependency-injection) |
|||
|
|||
### Source Code |
|||
- [Complete Working Demo](https://github.com/salihozkara/AbpSitemapDemo) - Full implementation with examples |
|||
- [BookSitemapSource](https://github.com/salihozkara/AbpSitemapDemo/blob/master/AbpSitemapDemo/Pages/Books/Index.cshtml.cs#L23) - Entity-based source example |
|||
- [Index.cshtml](https://github.com/salihozkara/AbpSitemapDemo/blob/master/AbpSitemapDemo/Pages/Index.cshtml#L9) - Page attribute usage |
|||
@ -0,0 +1 @@ |
|||
Learn how to use the ABP Sitemap module for automatic XML sitemap generation in your ABP Framework applications. |
|||
|
After Width: | Height: | Size: 43 KiB |
|
After Width: | Height: | Size: 33 KiB |
|
After Width: | Height: | Size: 48 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 10 KiB |
@ -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. |
|||
|
|||
 |
|||
|
|||
### 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: |
|||
|
|||
 |
|||
|
|||
|
|||
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 |
|||
|
|||
 |
|||
|
|||
- [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. |
|||
|
|||
 |
|||
|
|||
## 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!* |
|||
@ -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. |
|||
@ -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/) |
|||
@ -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 |
|||
``` |
|||
@ -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; |
|||
} |
|||
``` |
|||
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 53 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 90 KiB After Width: | Height: | Size: 51 KiB |
|
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 33 KiB |
|
After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 43 KiB |
|
After Width: | Height: | Size: 62 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 16 KiB |
@ -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: |
|||
|
|||
 |
|||
|
|||
## Manage Passkeys |
|||
|
|||
You can add/rename/delete your passkeys in the `Account/Manage` page: |
|||
|
|||
 |
|||
|
|||
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: |
|||
|
|||
 |
|||
|
|||
## 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: |
|||
|
|||
 |
|||
|
|||
 |
|||
|
|||
## 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) |
|||
@ -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. |
|||
|
|||
 |
|||
|
|||
## Solution Structure Changes |
|||
|
|||
When Aspire is enabled, two additional projects are added to your solution: |
|||
|
|||
 |
|||
|
|||
### 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 |
|||
|
|||
 |
|||
|
|||
### 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. |
|||
|
|||
 |
|||
|
|||
### 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. |
|||
|
|||
 |
|||
|
|||
## 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. |
|||
|
|||
 |
|||
|
|||
**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. |
|||
|
|||
 |
|||
|
|||
#### 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. |
|||
|
|||
 |
|||
|
|||
#### 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. |
|||
|
|||
 |
|||
|
|||
#### 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. |
|||
|
|||
 |
|||
|
|||
#### 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. |
|||
|
|||
 |
|||
|
|||
## 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: |
|||
|
|||
 |
|||
|
|||
|
|||
### 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. |
|||
|
|||
 |
|||
|
|||
### 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. |
|||
|
|||
 |
|||
|
|||
### 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. |
|||
|
|||
 |
|||
|
|||
### 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. |
|||
|
|||
 |
|||
|
|||
### 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. |
|||
|
|||
 |
|||
|
|||
### 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. |
|||
|
|||
 |
|||
|
|||
## 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/ |
|||
|
After Width: | Height: | Size: 246 KiB |
|
After Width: | Height: | Size: 52 KiB |
|
After Width: | Height: | Size: 541 KiB |
|
After Width: | Height: | Size: 180 KiB |
|
After Width: | Height: | Size: 197 KiB |
|
After Width: | Height: | Size: 238 KiB |
|
After Width: | Height: | Size: 232 KiB |
|
After Width: | Height: | Size: 186 KiB |
|
After Width: | Height: | Size: 262 KiB |
|
After Width: | Height: | Size: 376 KiB |
|
After Width: | Height: | Size: 262 KiB |
|
After Width: | Height: | Size: 442 KiB |
|
After Width: | Height: | Size: 440 KiB |
|
After Width: | Height: | Size: 249 KiB |
|
After Width: | Height: | Size: 384 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 30 KiB |