Getting Started
This guide walks you through building your first Arc.Core application from scratch. You’ll learn how to set up the application, define commands and queries, and run your service.
Prerequisites
Section titled “Prerequisites”- .NET 9 SDK or later
- Basic understanding of C# and .NET concepts
Installation
Section titled “Installation”Add the Arc.Core package to your project:
dotnet add package Cratis.ArcBasic Setup
Section titled “Basic Setup”Create a new console application and configure Arc.Core:
using Cratis.Arc;using Microsoft.Extensions.DependencyInjection;using Microsoft.Extensions.Logging;
var builder = ArcApplication.CreateBuilder(args);
// Add Arc servicesbuilder.AddCratisArc(options => options.Hosting.ApplicationUrl = "http://localhost:5000/");
// Configure loggingbuilder.Services.AddLogging(logging =>{ logging.AddConsole(); logging.SetMinimumLevel(LogLevel.Information);});
// Build and run the applicationvar app = builder.Build();
// Wire up the Arc middleware and endpointsapp.UseCratisArc();
Console.WriteLine("Application started on http://localhost:5000/");Console.WriteLine("Press Ctrl+C to stop...");
await app.RunAsync();ArcApplicationBuilder API
Section titled “ArcApplicationBuilder API”The ArcApplicationBuilder provides a familiar builder pattern for configuring your application:
Creating a Builder
Section titled “Creating a Builder”// Create with command-line argumentsvar builder = ArcApplication.CreateBuilder(args);
// Or without argumentsvar builder = ArcApplication.CreateBuilder();Available Properties
Section titled “Available Properties”The builder exposes several properties for configuration:
// Configuration systemIConfigurationManager Configuration = builder.Configuration;
// Host environment informationIHostEnvironment Environment = builder.Environment;
// Logging configurationILoggingBuilder Logging = builder.Logging;
// Service collection for dependency injectionIServiceCollection Services = builder.Services;
// Metrics configurationIMetricsBuilder Metrics = builder.Metrics;Adding Arc Services
Section titled “Adding Arc Services”builder.AddCratisArc( configureOptions: options => { // Configure Arc-specific options (ArcOptions) }, configureBuilder: arcBuilder => { // Add extensions like Chronicle, MongoDB, etc. });ArcApplication API
Section titled “ArcApplication API”Starting the Application
Section titled “Starting the Application”The UseCratisArc method wires up the Arc middleware and endpoints. It takes no arguments:
// UseCratisArc takes no arguments — it wires up the middleware and endpoints.app.UseCratisArc();The listen URL is not passed here — it comes from configuration via ArcOptions.Hosting.ApplicationUrl (default http://+:5001/). Set it through the options callback when adding Arc services, or in appsettings.json under Cratis:Arc:Hosting:ApplicationUrl.
Running the Application
Section titled “Running the Application”// Run and block until shutdown (Ctrl+C)await app.RunAsync();
// Or control start/stop manuallyawait app.StartAsync();// ... do work ...await app.StopAsync();Working with Commands
Section titled “Working with Commands”Commands represent actions or operations in your application. They’re automatically exposed as HTTP POST endpoints.
Defining a Command
Section titled “Defining a Command”using Cratis.Arc.Commands;
[Command]public record CreateUser(string Name, string Email){ public Task Handle(ILogger<CreateUser> logger) { logger.LogInformation("Creating user: {Name}", Name); // Your business logic here return Task.CompletedTask; }}Accessing Command Endpoints
Section titled “Accessing Command Endpoints”Commands are exposed as POST endpoints:
curl -X POST http://localhost:5000/api/your-app/create-user \ -H "Content-Type: application/json" \ -d '{"name":"John Doe","email":"john@example.com"}'Working with Queries
Section titled “Working with Queries”Queries represent data retrieval operations. They’re automatically exposed as HTTP GET endpoints.
Defining a Query
Section titled “Defining a Query”using Cratis.Arc.Queries;
[ReadModel]public record User(Guid Id, string Name){ // Exposed as GET; the method's parameters become query arguments. public static User GetUser(Guid id) => new(id, "John Doe");}Accessing Query Endpoints
Section titled “Accessing Query Endpoints”Queries are exposed as GET endpoints:
curl http://localhost:5000/api/your-app/get-user?id=123e4567-e89b-12d3-a456-426614174000Configuration
Section titled “Configuration”Using appsettings.json
Section titled “Using appsettings.json”Arc.Core supports standard .NET configuration:
{ "Cratis": { "Arc": { "GeneratedApis": { "RoutePrefix": "api" }, "CorrelationId": { "HttpHeader": "X-Correlation-ID" }, "Tenancy": { "HttpHeader": "X-Tenant-ID" } } }, "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning" } }}Environment-Specific Configuration
Section titled “Environment-Specific Configuration”Use environment-specific files following .NET conventions:
appsettings.json- Base configurationappsettings.Development.json- Development overridesappsettings.Production.json- Production overrides
var builder = ArcApplication.CreateBuilder(args);
// Configuration is automatically loaded based on environmentvar environment = builder.Environment.EnvironmentName;Console.WriteLine($"Running in {environment} environment");Custom Configuration Section
Section titled “Custom Configuration Section”Specify a custom configuration section path:
builder.AddCratisArc( configSectionPath: "MyApp:ArcSettings");Adding Services
Section titled “Adding Services”Logging
Section titled “Logging”builder.Services.AddLogging(logging =>{ logging.AddConsole(); logging.AddDebug(); logging.SetMinimumLevel(LogLevel.Information);});Custom Services
Section titled “Custom Services”// Singletonbuilder.Services.AddSingleton<IMyService, MyService>();
// Scoped (per request)builder.Services.AddScoped<IUserRepository, UserRepository>();
// Transient (per injection)builder.Services.AddTransient<IEmailSender, EmailSender>();Using Arc Conventions
Section titled “Using Arc Conventions”Arc supports automatic service registration using attributes:
// Services with [Singleton], [Scoped], or [Transient] attributes// are automatically registered[Singleton]public class MyService : IMyService{ // Implementation}Complete Example
Section titled “Complete Example”Here’s a complete working example that demonstrates commands, queries, and services:
using Cratis.Arc;using Cratis.Arc.Commands;using Cratis.Arc.Queries;using Microsoft.Extensions.DependencyInjection;using Microsoft.Extensions.Logging;
var builder = ArcApplication.CreateBuilder(args);
builder.AddCratisArc(options => options.Hosting.ApplicationUrl = "http://localhost:5000/");
builder.Services.AddLogging(logging =>{ logging.AddConsole(); logging.SetMinimumLevel(LogLevel.Information);});
var app = builder.Build();
app.UseCratisArc();
Console.WriteLine("Application started!");Console.WriteLine("Available endpoints:");Console.WriteLine(" POST http://localhost:5000/api/my-app/greet");Console.WriteLine(" GET http://localhost:5000/api/my-app/get-greeting?name=World");Console.WriteLine(" GET http://localhost:5000/.cratis/me");Console.WriteLine();Console.WriteLine("Press Ctrl+C to stop...");
await app.RunAsync();
// Commands[Command]public record Greet(string Name){ public Task Handle(ILogger<Greet> logger) { logger.LogInformation("Greeting {Name}", Name); return Task.CompletedTask; }}
// Queries[ReadModel]public record Greeting(string Text){ public static Greeting GetGreeting(string name) => new($"Hello, {name}!");}Advanced Scenarios
Section titled “Advanced Scenarios”Background Services
Section titled “Background Services”Combine Arc.Core with IHostedService for background processing:
public class BackgroundWorker(ILogger<BackgroundWorker> logger) : BackgroundService{ protected override async Task ExecuteAsync(CancellationToken stoppingToken) { logger.LogInformation("Background worker started");
while (!stoppingToken.IsCancellationRequested) { // Do background work await Task.Delay(TimeSpan.FromSeconds(30), stoppingToken); }
logger.LogInformation("Background worker stopped"); }}
// Register itbuilder.Services.AddHostedService<BackgroundWorker>();Integrating with Chronicle
Section titled “Integrating with Chronicle”Add event sourcing capabilities:
builder.AddCratisArc(configureBuilder: arcBuilder =>{ arcBuilder.WithChronicle();});Integrating with MongoDB
Section titled “Integrating with MongoDB”Add MongoDB support:
builder.AddCratisArc(configureBuilder: arcBuilder =>{ arcBuilder.WithMongoDB();});Troubleshooting
Section titled “Troubleshooting”Endpoints Not Found
Section titled “Endpoints Not Found”Ensure you’ve called app.UseCratisArc() before app.RunAsync():
var app = builder.Build();app.UseCratisArc(); // Must be called!await app.RunAsync();HTTP Listener Errors
Section titled “HTTP Listener Errors”If you get HTTP listener errors, ensure:
- The port is not already in use
- You have permissions to bind to the port (on Windows, non-admin users can’t bind to port 80)
- Set the listen URL via
ArcOptions.Hosting.ApplicationUrl(in the options callback orappsettings.jsonunderCratis:Arc:Hosting:ApplicationUrl) — it is not passed toUseCratisArc. Usehttp://+:5001/instead ofhttp://localhost:5001/to listen on all interfaces
Configuration Not Loading
Section titled “Configuration Not Loading”Ensure appsettings.json is copied to output:
<ItemGroup> <None Update="appsettings*.json"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </None></ItemGroup>Next Steps
Section titled “Next Steps”Now that you have a basic Arc.Core application running, explore these topics:
- Authentication - Implement custom authentication handlers
- Authorization - Protect your endpoints with authorization attributes
- Commands - Learn about advanced command patterns
- Queries - Discover query features like filtering and pagination
- Identity - Integrate the identity system
- Tenancy - Configure multi-tenant applications
- Validation - Add validation to commands and queries