Performance testing with BenchmarkDotNet, load testing, and Test.Live projects for Service Bus throughput validation. Covers hot path optimization and baselines. Trigger: benchmark, performance test, load test, throughput, Test.Live.
From dotnet-ai-kitnpx claudepluginhub faysilalshareef/dotnet-ai-kit --plugin dotnet-ai-kitThis skill uses the workspace's default tool permissions.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Searches prompts.chat for AI prompt templates by keyword or category, retrieves by ID with variable handling, and improves prompts via AI. Use for discovering or enhancing prompts.
Enables AI agents to execute x402 payments with per-task budgets, spending controls, and non-custodial wallets via MCP tools. Use when agents pay for APIs, services, or other agents.
namespace {Company}.{Domain}.Benchmarks;
[MemoryDiagnoser]
[SimpleJob(RuntimeMoniker.Net90)]
public class EventSerializationBenchmarks
{
private Event<OrderCreatedData> _event = null!;
private string _json = null!;
[GlobalSetup]
public void Setup()
{
_event = new Event<OrderCreatedData>
{
AggregateId = Guid.NewGuid(),
Sequence = 1,
Type = EventTypes.OrderCreated,
DateTime = DateTime.UtcNow,
Data = new OrderCreatedData("Test", 100m, [])
};
_json = JsonConvert.SerializeObject(_event);
}
[Benchmark(Baseline = true)]
public string Serialize_Newtonsoft()
=> JsonConvert.SerializeObject(_event);
[Benchmark]
public Event<OrderCreatedData> Deserialize_Newtonsoft()
=> JsonConvert.DeserializeObject<Event<OrderCreatedData>>(_json)!;
}
// Run: dotnet run -c Release --project src/Benchmarks/
namespace {Company}.{Domain}.Tests.Live;
/// <summary>
/// Sends batches of events to Service Bus and measures throughput.
/// Requires real Service Bus connection string in environment.
/// </summary>
public sealed class ServiceBusThroughputTest
{
[Fact(Skip = "Manual execution only — requires live Service Bus")]
public async Task MeasurePublishThroughput()
{
// Arrange
var connectionString = Environment.GetEnvironmentVariable(
"SERVICEBUS_CONNECTION_STRING")!;
var client = new ServiceBusClient(connectionString);
var sender = client.CreateSender("{company}-{domain}-commands");
var events = Enumerable.Range(1, 1000).Select(i =>
new ServiceBusMessage($"{{\"AggregateId\":\"{Guid.NewGuid()}\",\"Sequence\":{i}}}")
{
Subject = EventTypes.OrderCreated,
SessionId = Guid.NewGuid().ToString()
}).ToList();
// Act
var sw = Stopwatch.StartNew();
foreach (var batch in events.Chunk(100))
{
using var messageBatch = await sender.CreateMessageBatchAsync();
foreach (var msg in batch)
messageBatch.TryAddMessage(msg);
await sender.SendMessagesAsync(messageBatch);
}
sw.Stop();
// Assert
var throughput = events.Count / sw.Elapsed.TotalSeconds;
Console.WriteLine($"Throughput: {throughput:F0} messages/sec");
throughput.Should().BeGreaterThan(100, "Minimum throughput not met");
}
}
[MemoryDiagnoser]
public class QueryBenchmarks
{
private ApplicationDbContext _db = null!;
[GlobalSetup]
public async Task Setup()
{
var options = new DbContextOptionsBuilder<ApplicationDbContext>()
.UseSqlServer("Server=.;Database=BenchmarkDb;Trusted_Connection=true;")
.Options;
_db = new ApplicationDbContext(options);
// Seed 10,000 orders for realistic benchmarks
await SeedData.SeedOrders(_db, 10000);
}
[Benchmark]
public async Task<List<OrderOutput>> Query_WithPagination()
{
return await _db.Orders.AsNoTracking()
.OrderByDescending(o => o.Sequence)
.Skip(0).Take(20)
.Select(o => new OrderOutput(o.Id, o.CustomerName, o.Total))
.ToListAsync();
}
[Benchmark]
public async Task<List<OrderOutput>> Query_WithFilter()
{
return await _db.Orders.AsNoTracking()
.Where(o => o.CustomerName.Contains("Test"))
.OrderByDescending(o => o.Sequence)
.Skip(0).Take(20)
.Select(o => new OrderOutput(o.Id, o.CustomerName, o.Total))
.ToListAsync();
}
}
tests/
{Domain}.Tests.Unit/ # Unit tests (CI)
{Domain}.Tests.Integration/ # Integration tests (CI)
{Domain}.Tests.Live/ # Live infrastructure tests (manual)
{Domain}.Benchmarks/ # BenchmarkDotNet projects (manual)
| Anti-Pattern | Correct Approach |
|---|---|
| Optimizing without benchmarks | Measure first, optimize second |
| Benchmarks in CI pipeline | Run benchmarks manually or on schedule |
| Testing with Debug build | Always benchmark in Release mode |
| Live tests without Skip attribute | Mark with Skip to prevent accidental CI runs |
# Find BenchmarkDotNet usage
grep -r "BenchmarkDotNet\|\[Benchmark\]" --include="*.cs" tests/ benchmarks/
# Find Test.Live projects
find . -name "*Tests.Live*" -type d
# Find throughput tests
grep -r "Throughput\|Stopwatch" --include="*.cs" tests/
Benchmarks/ project with Release configurationTest.Live project for real infrastructure validationSkip attribute or [Trait("Category", "Live")]