Observability is useful only when it remains usable as an application grows. A dashboard that works well with five resources can become difficult to operate when a distributed application contains dozens or hundreds of resources, logs, traces, metrics, health checks, and changing service states.
.NET Aspire includes a developer dashboard for observing resources and telemetry during application development. Aspire 13.5 introduced improvements around dashboard filtering, reconnection behavior, health-check handling, and telemetry-related scenarios.
That makes an important engineering question worth testing: How does the Aspire dashboard behave when the amount of application telemetry increases significantly?
Rather than assuming that a dashboard feature scales well, developers can build a controlled workload and measure usability, resource consumption, connection behavior, and telemetry visibility.
Why Dashboard Scale Matters
A distributed application can generate many observability events.
Consider an application with:
API
|
+-- Authentication
+-- Orders
+-- Payments
+-- Notifications
|
+-- PostgreSQL
+-- Redis
+-- Message Broker
+-- Background Workers
Each component can produce:
Logs
Metrics
Traces
Health checks
Exceptions
Resource state changes
As the number of resources increases, the dashboard has more information to display and process.
The challenge is not simply collecting telemetry. The dashboard must also help developers find the information they need.
What Should Be Benchmarked?
A dashboard benchmark should measure more than raw CPU or memory usage.
Useful dimensions include:
| Area | What to Measure |
|---|---|
| Startup | Time until dashboard is usable |
| Resource discovery | Time to display resources |
| Filtering | Responsiveness when filtering |
| Logs | Loading and rendering behavior |
| Traces | Trace query responsiveness |
| Metrics | Chart rendering behavior |
| Health checks | State update behavior |
| Reconnection | Recovery after connection interruption |
| Memory | Dashboard process/resource usage |
| CPU | Resource usage during telemetry activity |
The exact measurements should be collected from an actual test environment.
Do not present generic values as universal performance benchmarks.
Create a Controlled Aspire Application
Start with a small baseline.
var builder = DistributedApplication.CreateBuilder(args);
builder.AddProject<Projects.Api>("api");
builder.AddProject<Projects.Worker>("worker");
builder.AddRedis("cache");
builder.AddPostgres("postgres");
builder.Build().Run();
This gives you a starting point.
Then gradually increase the number of resources.
For example:
Test A: 5 resources
Test B: 25 resources
Test C: 50 resources
Test D: 100 resources
The exact scale should be selected based on the workload you want to investigate.
Generate Realistic Telemetry
Simply creating many resources is not enough.
The benchmark should generate telemetry that resembles real application activity.
For example:
public async Task ProcessRequestAsync()
{
using var activity = ActivitySource
.StartActivity("ProcessOrder");
logger.LogInformation(
"Processing order {OrderId}",
orderId);
await ProcessDatabaseOperationAsync();
await ProcessNotificationAsync();
}
The goal is to create realistic combinations of:
Request traces
Database spans
Background activity
Structured logs
Exceptions
Health checks
Avoid generating artificial telemetry at an unrealistic rate unless the purpose of the test is specifically to determine a stress limit.
Establish a Baseline
Before testing large workloads, capture the dashboard's normal behavior.
Record:
Resource count
Telemetry rate
Dashboard startup time
Memory usage
CPU usage
Filter response
Log loading behavior
Trace loading behavior
For example:
| Test | Resources | Telemetry Rate | Result |
|---|---|---|---|
| Baseline | 5 | Controlled | Record |
| Medium | 25 | Controlled | Record |
| Large | 50 | Controlled | Record |
| Stress | 100+ | Controlled | Record |
The table should contain actual measurements from your environment.
Testing Resource Filtering
Filtering becomes more important as the resource list grows.
Suppose the dashboard contains:
api-orders
api-users
api-payments
worker-orders
worker-notifications
postgres
redis
messagebus
...
A useful benchmark should test whether filtering remains responsive as the number of resources increases.
Measure:
Type filter
|
v
Search / Filter
|
v
Visible Resources
|
v
Response Time
The important metric is not simply whether filtering works, but whether the user can interact with it comfortably under a large resource set.
Testing Logs Under Load
Logs can become one of the largest telemetry streams.
Generate representative structured logs:
logger.LogInformation(
"Order {OrderId} processed for customer {CustomerId}",
orderId,
customerId);
Then measure:
Initial log display
Loading additional records
Filtering
Searching
Rendering behavior
Memory usage
A benchmark should avoid generating sensitive production data.
Use synthetic identifiers and controlled test content.
Testing Distributed Traces
Distributed tracing becomes valuable as applications become more complex.
A single request might produce:
HTTP Request
|
+-- Authentication
|
+-- Order Service
|
+-- PostgreSQL
|
+-- Redis
|
+-- Notification Worker
The dashboard needs to make this relationship understandable.
A useful test should therefore measure trace discovery and inspection rather than simply counting trace records.
Health Check Behavior
Health checks are another important part of the dashboard.
A service might expose:
API
|
+-- Database Health
+-- Cache Health
+-- Message Broker Health
Test transitions such as:
Healthy
|
v
Dependency Failure
|
v
Unhealthy
|
v
Dependency Recovered
|
v
Healthy
Measure how quickly the dashboard reflects meaningful state changes.
The purpose is to test observability behavior, not to claim a universal health-check propagation time.
Testing Reconnection Behavior
Distributed development environments can experience temporary connectivity problems.
A useful experiment deliberately interrupts the dashboard's connection and observes what happens.
Connected
|
v
Connection Interrupted
|
v
Dashboard State
|
v
Connection Restored
|
v
Telemetry Recovery
Record:
Whether the dashboard remains usable
Whether resource information is preserved
Whether telemetry resumes
Whether duplicate information appears
Whether the user needs to refresh manually
This is particularly useful when developing over remote or unstable environments.
Measuring Memory Usage
Memory should be measured throughout the test rather than only at startup.
A useful test pattern is:
Start Dashboard
|
v
Load Resources
|
v
Generate Telemetry
|
v
Browse Logs
|
v
Browse Traces
|
v
Apply Filters
|
v
Measure Memory
This helps distinguish startup allocation from workload-related growth.
A single memory measurement cannot tell you whether memory usage remains stable over time.
Testing CPU Usage
CPU measurements should be collected while the dashboard is performing specific activities.
For example:
Idle
|
+-- Resource browsing
|
+-- Log filtering
|
+-- Trace inspection
|
+-- High telemetry activity
This creates a more useful profile than simply recording average CPU utilization for the entire test.
Large Workload Testing
A meaningful stress test should increase workload dimensions gradually.
For example:
Phase 1
10 resources
Phase 2
25 resources
Phase 3
50 resources
Phase 4
100 resources
Phase 5
Increase telemetry volume
This makes it easier to identify the point at which behavior changes significantly.
Do not jump directly from five resources to an arbitrarily large number and call the resulting observation a scalability limit.
A true scalability limit requires a controlled experiment and clearly defined acceptance criteria.
Separating Dashboard and Application Performance
One important benchmarking mistake is confusing dashboard overhead with application overhead.
The application may be performing normally while the dashboard is processing large amounts of telemetry.
Therefore, monitor both:
Application
|
+-- CPU
+-- Memory
+-- Request Latency
Dashboard
|
+-- CPU
+-- Memory
+-- Rendering
+-- Telemetry Processing
This separation makes the results easier to interpret.
Example Benchmark Record
A useful benchmark record could contain:
{
"resourceCount": 50,
"telemetryProfile": "medium",
"scenario": "trace-inspection",
"dashboardMemoryMb": 0,
"dashboardCpuPercent": 0,
"filterResponseMs": 0,
"reconnection": "pass"
}
The zero values here are placeholders.
The benchmark should populate them from actual measurements rather than invented numbers.
Common Mistakes
Measuring Only Startup
A dashboard may start quickly but behave differently after processing a large amount of telemetry.
Generating Unrealistic Telemetry
An artificial event generator can create a workload that has little relationship to actual application behavior.
Testing Only Resource Count
Ten resources producing huge telemetry volumes may be more demanding than one hundred mostly idle resources.
Ignoring Browser Performance
The dashboard is a user interface. Browser rendering and client-side processing can affect perceived performance.
Using One Machine
A benchmark performed on a single development machine does not automatically represent another developer workstation or CI environment.
Treating One Test as a Universal Limit
The results depend on resource count, telemetry rate, machine capacity, browser, application architecture, and environment.
Troubleshooting
Dashboard Becomes Slow
Determine which activity causes the slowdown.
Test separately:
Resource browsing
Log browsing
Trace browsing
Metrics
Filtering
This helps isolate the source.
Memory Keeps Increasing
Run a longer test and monitor memory over time.
Also check whether the workload continuously increases the amount of retained telemetry.
A continuously growing workload is different from a fixed dataset being repeatedly inspected.
Telemetry Disappears After Reconnection
Check whether the issue is with:
The application
Telemetry transport
Dashboard connection
Browser state
Environment networking
Do not assume the dashboard is the source without isolating the layers.
Health Status Is Unexpected
Verify the underlying health-check endpoint independently.
If the application reports an incorrect health state, dashboard behavior may simply be reflecting the source data.
Best Practices for Aspire Dashboard Benchmarking
Establish a small baseline.
Increase resource count gradually.
Control telemetry generation.
Measure logs, traces, metrics, and health checks separately.
Test filtering with realistic resource counts.
Test reconnection behavior explicitly.
Monitor CPU and memory over time.
Record browser and machine characteristics.
Separate application resource usage from dashboard usage.
Repeat important measurements.
Keep benchmark data consistent.
Avoid publishing unsupported performance limits.
Advantages and Disadvantages
Advantages
Provides a practical way to evaluate observability behavior before scaling an application.
Helps identify dashboard usability problems under larger workloads.
Encourages teams to test telemetry volume rather than only application functionality.
Makes reconnection and health-state behavior measurable.
Can reveal whether an application's telemetry strategy needs refinement.
Disadvantages
Results are highly environment-dependent.
Resource count alone does not represent telemetry workload.
Browser performance can influence observations.
Large telemetry experiments require careful workload design.
A benchmark does not automatically establish a universal scalability limit.
A Practical Test Matrix
A team evaluating Aspire dashboard behavior can use a matrix like this:
| Scenario | Resources | Telemetry | Logs | Traces | Health Checks | Reconnect |
|---|---|---|---|---|---|---|
| Baseline | Small | Low | Yes | Yes | Yes | Yes |
| Medium | Medium | Medium | Yes | Yes | Yes | Yes |
| Large | Large | High | Yes | Yes | Yes | Yes |
| Stress | Large | Very High | Yes | Yes | Yes | Yes |
The exact resource counts and telemetry rates should be chosen based on the application's expected operating profile.
Conclusion
.NET Aspire's dashboard provides developers with a convenient way to observe distributed applications, but observability itself needs to be tested when applications grow. Aspire 13.5 includes improvements around dashboard behavior and telemetry workflows, making it reasonable to evaluate how those capabilities behave under controlled larger workloads.
The most useful benchmark does not attempt to produce one universal "maximum number of services" or "maximum telemetry rate." Instead, it measures how resource discovery, filtering, logs, traces, health checks, reconnection, CPU, and memory behave as workload complexity increases.
For teams using Aspire at scale, this type of testing can expose problems before the dashboard becomes a bottleneck in daily development. More importantly, it encourages a broader observability mindset: telemetry is not useful merely because it exists; developers must still be able to find, interpret, and act on it when the application becomes busy.
Join the conversation! Your thoughts help the community grow.