# Aspire Community Toolkit The Aspire Community Toolkit is a comprehensive collection of integrations and extensions for .NET Aspire, a cloud-ready stack for building distributed applications. This toolkit bridges the gap between .NET Aspire and popular third-party services, databases, message brokers, programming languages, and development tools. It enables developers to orchestrate complex, multi-technology application stacks using a consistent, fluent API that simplifies container management, service discovery, and configuration. The toolkit provides two main categories of packages: hosting integrations for container orchestration and resource management (39+ packages), and client integrations for SDK configuration with health checks and telemetry (10+ packages). Community-contributed and maintained by core contributors, it supports databases (Meilisearch, RavenDB, SQLite, SurrealDB), message brokers (ActiveMQ, LavinMQ), AI/ML services (Ollama), cloud services (Azure Data API Builder, Dapr), programming languages (Golang, Java, Python, Rust, Bun, Deno), storage solutions (MinIO), and development tools (MailPit, k6, Ngrok). ## Hosting Integration: Meilisearch Search Engine Adding and configuring a Meilisearch container with data persistence and service reference. ```csharp // AppHost/Program.cs using Projects; var builder = DistributedApplication.CreateBuilder(args); // Add Meilisearch with data volume for persistence var meilisearch = builder.AddMeilisearch("meilisearch") .WithDataVolume(); // Persists data across container restarts // Reference from API service builder.AddProject("apiservice") .WithReference(meilisearch) // Injects connection string .WaitFor(meilisearch) // Ensures container is ready .WithHttpHealthCheck("/health"); builder.Build().Run(); ``` ## Client Integration: Meilisearch Client Using the Meilisearch client in a service with dependency injection and CRUD operations. ```csharp // ApiService/Program.cs using Meilisearch; var builder = WebApplication.CreateBuilder(args); builder.AddServiceDefaults(); builder.AddMeilisearchClient("meilisearch"); // Registers MeilisearchClient var app = builder.Build(); app.MapDefaultEndpoints(); // Create and index documents app.MapGet("/create", async (MeilisearchClient meilisearch) => { var index = meilisearch.Index("movies"); var documents = new Movie[] { new() { Id = "1", Title = "Carol", Genres = ["Romance", "Drama"] }, new() { Id = "2", Title = "Wonder Woman", Genres = ["Action", "Adventure"] }, new() { Id = "3", Title = "Life of Pi", Genres = ["Adventure", "Drama"] }, new() { Id = "4", Title = "Mad Max: Fury Road", Genres = ["Adventure", "Science Fiction"] }, }; var task = await index.AddDocumentsAsync(documents); var response = await index.WaitForTaskAsync(task.TaskUid); return task; }); // Search with highlighting app.MapGet("/search", async (MeilisearchClient meilisearch) => { var index = meilisearch.Index("movies"); var result = await index.SearchAsync( "car", new SearchQuery { AttributesToHighlight = ["title"], }); return result; }); // Get all documents app.MapGet("/get", async (MeilisearchClient meilisearch) => { var index = await meilisearch.GetIndexAsync("movies"); var data = await index.GetDocumentsAsync(); return data.Results; }); app.Run(); public record Movie { public string Id { get; set; } public string Title { get; set; } public string[] Genres { get; set; } } ``` ## Hosting Integration: Ollama AI Models Configuring Ollama with multiple models from different sources and OpenWebUI dashboard. ```csharp // AppHost/Program.cs var builder = DistributedApplication.CreateBuilder(args); // Add Ollama container with data persistence and web UI var ollama = builder.AddOllama("ollama") .WithDataVolume() // Persist downloaded models .WithOpenWebUI() // Add management web interface .WithGPUSupport(); // Optional: enable GPU acceleration // Add model from Ollama library var phi3 = ollama.AddModel("phi3", "phi3"); // Add model from HuggingFace var llama = ollama.AddHuggingFaceModel( "llama", "bartowski/Llama-3.2-1B-Instruct-GGUF:IQ4_XS" ); // Multiple Ollama instances with different models var ollama2 = builder.AddOllama("ollama2") .WithDataVolume() .WithOpenWebUI(); var tinyllama = ollama2.AddModel("tinyllama", "tinyllama"); // Reference models in web frontend builder.AddProject("webfrontend") .WithExternalHttpEndpoints() .WithReference(phi3) // Model-specific connection .WaitFor(phi3) // Wait for model download .WithReference(llama) .WithReference(tinyllama); builder.Build().Run(); ``` ## Client Integration: OllamaSharp with IChatClient Integrating Ollama models with .NET's IChatClient interface for AI conversations. ```csharp // ApiService/Program.cs var builder = WebApplication.CreateBuilder(args); builder.AddServiceDefaults(); // Register OllamaSharp client with IChatClient extension builder.AddKeyedOllamaApiClient("phi3-connection") .AddKeyedChatClient("phi3"); builder.AddKeyedOllamaApiClient("llama-connection") .AddKeyedChatClient("llama"); var app = builder.Build(); // Use IChatClient for AI interactions app.MapPost("/chat", async ( [FromBody] string prompt, [FromServices] IChatClient chatClient) => { var response = await chatClient.CompleteAsync(prompt); return response.Message.Text; }); // Use different models via keyed services app.MapPost("/chat/{model}", async ( string model, [FromBody] string prompt, [FromKeyedServices] KeyedServiceProvider chatClients) => { var chatClient = chatClients.GetRequiredKeyedService(model); var response = await chatClient.CompleteAsync(prompt); return response.Message.Text; }); app.Run(); ``` ## Hosting Integration: Dapr with Sidecars Configuring Dapr sidecars with state stores and pub/sub messaging. ```csharp // AppHost/Program.cs var builder = DistributedApplication.CreateBuilder(args); var redis = builder.AddRedis("redis").WithRedisInsight(); // Define Dapr components var stateStore = builder.AddDaprStateStore("statestore") .WaitFor(redis); var redisHost = redis.Resource.PrimaryEndpoint.Property(EndpointProperty.Host); var redisPort = redis.Resource.PrimaryEndpoint.Property(EndpointProperty.Port); var pubSub = builder.AddDaprPubSub("pubsub") .WithMetadata( "redisHost", ReferenceExpression.Create($"{redisHost}:{redisPort}") ) .WaitFor(redis); if (redis.Resource.PasswordParameter is not null) { pubSub.WithMetadata("redisPassword", redis.Resource.PasswordParameter); } // Add services with Dapr sidecars builder.AddProject("servicea") .WithDaprSidecar(sidecar => { sidecar.WithReference(stateStore) .WithReference(pubSub); }) .WaitFor(redis); builder.AddProject("serviceb") .WithDaprSidecar(sidecar => sidecar.WithReference(pubSub)) .WaitFor(redis); // Console app with Dapr (no appPort, sender only) builder.AddProject("servicec") .WithDaprSidecar(sidecar => sidecar.WithReference(stateStore)) .WaitFor(redis); builder.Build().Run(); ``` ## Client Integration: Dapr State and PubSub Using Dapr client for state management and publish/subscribe messaging in services. ```csharp // ServiceA/Program.cs var builder = WebApplication.CreateBuilder(args); builder.Services.AddDaprClient(); var app = builder.Build(); // State management app.MapGet("/weatherforecast", async (DaprClient client) => { // Get from state store var cached = await client.GetStateAsync( "statestore", "cache" ); if (cached is null || cached.ExpiresAt < DateTime.UtcNow) { var forecast = GenerateWeatherForecast(); cached = new CachedWeatherForecast { Forecast = forecast, ExpiresAt = DateTime.UtcNow.AddMinutes(5) }; // Save to state store await client.SaveStateAsync("statestore", "cache", cached); } return cached.Forecast; }); // Publish message app.MapPost("/weather/notify", async ( WeatherUpdate update, DaprClient client) => { await client.PublishEventAsync("pubsub", "weather-updates", update); return Results.Accepted(); }); app.Run(); record CachedWeatherForecast(WeatherForecast[] Forecast, DateTime ExpiresAt); record WeatherUpdate(string Location, int Temperature, string Condition); ``` ## Hosting Integration: SQLite with Web UI Setting up SQLite database files with optional web-based database management UI. ```csharp // AppHost/Program.cs var builder = DistributedApplication.CreateBuilder(args); // SQLite for ADO.NET access var sqlite = builder.AddSqlite("sqlite") .WithSqliteWeb() // Add web-based DB browser .WithDataBindMount("./data"); // Mount local directory // SQLite for Entity Framework var sqliteEF = builder.AddSqlite("sqlite-ef") .WithSqliteWeb() .WithDataVolume(); // Use Docker volume var api = builder.AddProject("api") .WithReference(sqlite) .WithReference(sqliteEF); builder.Build().Run(); ``` ## Client Integration: SQLite ADO.NET and Entity Framework Using SQLite with both ADO.NET connections and Entity Framework Core. ```csharp // Api/Program.cs using Microsoft.Data.Sqlite; using Microsoft.EntityFrameworkCore; var builder = WebApplication.CreateBuilder(args); builder.AddServiceDefaults(); // Register SQLite connection for ADO.NET builder.AddSqliteConnection("sqlite"); // Register SQLite with Entity Framework builder.AddSqliteDbContext("sqlite-ef"); var app = builder.Build(); app.MapDefaultEndpoints(); await SetupDatabase(app); // ADO.NET queries app.MapGet("/test", async (SqliteConnection db) => { await db.OpenAsync(); var command = db.CreateCommand(); command.CommandText = "SELECT name FROM test"; var result = await command.ExecuteScalarAsync(); return result?.ToString() ?? null; }); app.MapPost("/test", async ( SqliteConnection db, [FromBody] string name) => { await db.OpenAsync(); var command = db.CreateCommand(); command.CommandText = "INSERT INTO test (name) VALUES ($name)"; command.Parameters.AddWithValue("$name", name); await command.ExecuteNonQueryAsync(); return Results.Created($"/test/{name}", name); }); // Entity Framework queries app.MapGet("/blog", async (BloggingContext db) => { var blogs = await db.Blogs.ToListAsync(); return Results.Ok(blogs); }); app.MapPost("/blog", async ( BloggingContext db, [FromBody] Blog blog) => { db.Blogs.Add(blog); await db.SaveChangesAsync(); return Results.Created($"/blog/{blog.BlogId}", blog); }); app.Run(); static async Task SetupDatabase(WebApplication app) { using var scope = app.Services.CreateScope(); // Initialize ADO.NET database var db = scope.ServiceProvider.GetRequiredService(); await db.OpenAsync(); var command = db.CreateCommand(); command.CommandText = "CREATE TABLE IF NOT EXISTS test (id INTEGER PRIMARY KEY, name TEXT)"; await command.ExecuteNonQueryAsync(); // Initialize EF Core database using var context = scope.ServiceProvider.GetRequiredService(); await context.Database.MigrateAsync(); } public class BloggingContext : DbContext { public BloggingContext(DbContextOptions options) : base(options) { } public DbSet Blogs { get; set; } } public class Blog { public int BlogId { get; set; } public string Url { get; set; } } ``` ## Hosting Integration: RavenDB NoSQL Database Configuring RavenDB document database with security settings and database creation. ```csharp // AppHost/Program.cs using CommunityToolkit.Aspire.Hosting.RavenDB; using Projects; var builder = DistributedApplication.CreateBuilder(args); // Configure unsecured RavenDB for development var serverSettings = RavenDBServerSettings.Unsecured(); var ravendb = builder.AddRavenDB("ravendb", serverSettings) .WithDataVolume(); // Persist data // Pre-create database ravendb.AddDatabase("ravenDatabase"); builder.AddProject("apiservice") .WithReference(ravendb) .WaitFor(ravendb); builder.Build().Run(); ``` ## Client Integration: RavenDB Document Store Using RavenDB client for document-based CRUD operations with session management. ```csharp // ApiService/Program.cs using Raven.Client.Documents; var builder = WebApplication.CreateBuilder(args); builder.AddServiceDefaults(); // Register RavenDB document store builder.AddRavenDBClient( connectionName: "ravendb", configureSettings: settings => { settings.CreateDatabase = true; settings.DatabaseName = "ravenDatabase"; }); var app = builder.Build(); app.MapDefaultEndpoints(); // Store document app.MapGet("/create", async (IDocumentStore documentStore) => { using var session = documentStore.OpenAsyncSession(); var company = new Company { Name = "RavenDB", Phone = "(26) 642-7012", Fax = "(26) 642-7012" }; await session.StoreAsync(company, "companies/ravendb"); await session.SaveChangesAsync(); return Results.Created("/get", company); }); // Load document app.MapGet("/get", async (IDocumentStore documentStore) => { using var session = documentStore.OpenAsyncSession(); var company = await session.LoadAsync("companies/ravendb"); return company is not null ? Results.Ok(company) : Results.NotFound(); }); app.Run(); public class Company { public string? Id { get; set; } public string? Name { get; set; } public string? Phone { get; set; } public string? Fax { get; set; } } ``` ## Hosting Integration: MinIO S3-Compatible Storage Setting up MinIO object storage with parameterized credentials and bucket management. ```csharp // AppHost/Program.cs using Projects; var builder = DistributedApplication.CreateBuilder(args); // Define credentials as parameters var username = builder.AddParameter("user", "minioadmin"); var password = builder.AddParameter("password", "minioadmin", secret: true); var minio = builder.AddMinioContainer("minio", username, password) .WithDataVolume(); // Persist bucket data builder.AddProject("apiservice") .WithReference(minio) .WaitFor(minio) .WithHttpHealthCheck("/health"); builder.Build().Run(); ``` ## Client Integration: MinIO Client Using MinIO client for S3-compatible bucket and object operations. ```csharp // ApiService/Program.cs using Microsoft.AspNetCore.Mvc; using Minio; using Minio.DataModel.Args; var builder = WebApplication.CreateBuilder(args); builder.AddServiceDefaults(); builder.AddMinioClient("minio"); var app = builder.Build(); app.MapDefaultEndpoints(); // Create bucket app.MapPut("/buckets/{bucketName}", async ( string bucketName, [FromServices] IMinioClient minioClient) => { var mbArgs = new MakeBucketArgs() .WithBucket(bucketName); await minioClient.MakeBucketAsync(mbArgs); return Results.Ok(); }); // Check bucket exists app.MapGet("/buckets/{bucketName}", async ( string bucketName, [FromServices] IMinioClient minioClient) => { var exists = await minioClient.BucketExistsAsync( new BucketExistsArgs().WithBucket(bucketName) ); return exists ? Results.Ok() : Results.NotFound(); }); // Upload object app.MapPost("/buckets/{bucketName}/{fileName}/upload", async ([FromRoute] string bucketName, [FromRoute] string fileName, HttpRequest request, [FromServices] IMinioClient minioClient) => { var memstream = new MemoryStream(); await request.Body.CopyToAsync(memstream); var length = memstream.Length; memstream.Seek(0, SeekOrigin.Begin); var putObjectArgs = new PutObjectArgs() .WithObject(fileName) .WithBucket(bucketName) .WithStreamData(memstream) .WithObjectSize(length); await minioClient.PutObjectAsync(putObjectArgs); return Results.Ok(); }).DisableAntiforgery(); // Download object app.MapGet("/buckets/{bucketName}/{fileName}/download", async (string bucketName, string fileName, [FromServices] IMinioClient minioClient) => { var memStream = new MemoryStream(); var getObjectArgs = new GetObjectArgs() .WithBucket(bucketName) .WithObject(fileName) .WithCallbackStream(stream => { stream.CopyToAsync(memStream); }); await minioClient.GetObjectAsync(getObjectArgs); return Results.File( memStream.ToArray(), "application/octet-stream", fileName ); }); app.Run(); ``` ## Hosting Integration: Golang Applications Running Golang applications as part of the distributed application with build support. ```csharp // AppHost/Program.cs var builder = DistributedApplication.CreateBuilder(args); // Run Go application with default configuration var goApp = builder.AddGolangApp( name: "go-api", workingDirectory: "../go-api", executable: ".", args: null, buildTags: ["production", "mysql"] // Optional build tags ); // Run Go application from specific package var goWorker = builder.AddGolangApp( name: "go-worker", workingDirectory: "../go-services", executable: "./cmd/worker", args: ["--verbose"] ); // Configure endpoints goApp.WithHttpEndpoint(port: 8080, env: "PORT"); builder.Build().Run(); ``` ## Hosting Integration: Java/Spring Boot Applications Running Java and Spring Boot applications as containers or executables with Maven builds. ```csharp // AppHost/Program.cs var builder = DistributedApplication.CreateBuilder(args); // Java app as container var containerapp = builder.AddSpringApp( "containerapp", new JavaAppContainerResourceOptions() { ContainerImageName = "aliencube/aspire-spring-maven-sample", OtelAgentPath = "/agents" }); // Java app as executable with Maven build var executableapp = builder.AddSpringApp( "executableapp", workingDirectory: "../CommunityToolkit.Aspire.Hosting.Java.Spring.Maven", new JavaAppExecutableResourceOptions() { ApplicationName = "target/spring-maven-0.0.1-SNAPSHOT.jar", Port = 8085, OtelAgentPath = "../../../agents", }) .WithMavenBuild() // Build before running .PublishAsDockerFile(c => { c.WithBuildArg("JAR_NAME", "spring-maven-0.0.1-SNAPSHOT.jar") .WithBuildArg("AGENT_PATH", "/agents") .WithBuildArg("SERVER_PORT", "8085"); }) .WithHttpHealthCheck("/health"); var webapp = builder.AddProject("webapp") .WithExternalHttpEndpoints() .WithReference(containerapp) .WithReference(executableapp); builder.Build().Run(); ``` ## Hosting Integration: Python Applications Running Python applications with Uvicorn and uv package manager. ```csharp // AppHost/Program.cs var builder = DistributedApplication.CreateBuilder(args); // Run Python app with Uvicorn builder.AddUvicornApp( name: "uvicornapp", workingDirectory: "../uvicornapp-api", appName: "main:app" ) .WithHttpEndpoint(port: 8000, env: "PORT"); // Run Python app with uv (modern Python package manager) builder.AddUvApp( name: "uvapp", workingDirectory: "../uv-api", projectName: "uv-api" ) .WithHttpEndpoint(env: "PORT"); builder.Build().Run(); ``` ## Summary The Aspire Community Toolkit serves as a critical bridge between .NET Aspire's orchestration capabilities and the broader ecosystem of databases, services, and programming languages commonly used in modern cloud applications. Its primary use cases include multi-language application development (coordinating .NET services with Golang, Java, Python, and Rust components), polyglot data access (integrating traditional SQL, NoSQL, search engines, and object storage in a single stack), AI/ML integration (hosting and consuming LLM models through Ollama), microservices patterns (implementing service mesh architectures with Dapr), and development workflow enhancement (providing observability, testing, and debugging tools). The toolkit eliminates the complexity of manual container orchestration, environment configuration, and service wiring. Integration patterns follow a consistent two-phase approach: hosting configuration in the AppHost project using `AddXXX()` extension methods with fluent configuration APIs (`.WithDataVolume()`, `.WithReference()`, `.WaitFor()`), and client consumption in services through `AddXXXClient()` methods that register typed clients with health checks and telemetry. Connection strings are automatically generated and injected via the `WithReference()` mechanism, enabling seamless service discovery. The toolkit handles lifecycle management (startup ordering with `WaitFor()`), security (parameter-based secrets), persistence (volumes and bind mounts), observability (health checks, OpenTelemetry), and development tools (web UIs for databases and message brokers). All integrations are NuGet packages installable independently, with both stable and preview versions available through NuGet Gallery and Azure Artifacts feeds.