Skip to content

DevHost

CloudFy edited this page Feb 23, 2026 · 6 revisions

NuGet version

Arcturus DevHost is a an MSBuild SDK for orchestrating multiple .NET projects and executables in a single development host environment. Perfect for microservices development, allowing you to run and manage multiple services locally with a single command.

Overview

The Arcturus.DevHost.Sdk provides a streamlined way to create orchestrator projects that can:

  • Run multiple .NET projects simultaneously
  • Execute external processes (npm, node, etc.)
  • Manage process lifecycles with proper cleanup
  • Configure URLs and environment variables per project
  • Automatically generate strongly-typed project metadata using source generators

Installation

Create a new console project that references the SDK:

<Project Sdk="Arcturus.DevHost.Sdk/2025.1.28.20">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net10.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <!-- Add project references to the projects you want to orchestrate -->
  <ItemGroup>
    <ProjectReference Include="..\MyApi\MyApi.csproj" />
    <ProjectReference Include="..\MyWorker\MyWorker.csproj" />
  </ItemGroup>

</Project>

This simply replaces

// replace ..
<Project Sdk="Microsoft.NET.Sdk.Web">
// .. with ..
<Project Sdk="Arcturus.DevHost.Sdk/2026.1.10.30">

How It Works

The SDK automatically integrates pipelines into one executable and start a uniform process with all dependencies.

Usage

Basic Example

using Arcturus.DevHost.Hosting;
using Microsoft.Extensions.Logging;

var builder = OrchestratorHostBuilder.Create();
builder.ConfigureLogging(l => l.SetMinimumLevel(LogLevel.Information));

// Add a .NET project (generated by source generator)
builder.AddProject<Projects.MyApi>(
    c => c.WithUrls("http://localhost:5000")
          .WithEnvironmentVariable("ASPNETCORE_ENVIRONMENT", "Development"));

// Add another project
builder.AddProject<Projects.MyWorker>();

// Add an external executable (e.g., npm for a frontend)
builder.AddExecutable("npm", "run dev", workingDirectory: "./ClientApp");

await builder.Build().RunAsync();

Advanced Configuration

var builder = OrchestratorHostBuilder.Create();

// Configure logging
builder.ConfigureLogging(l =>
{
    l.AddConsole();
    l.SetMinimumLevel(LogLevel.Debug);
});

// Add multiple projects with different configurations
builder
    .AddProject<Projects.ApiGateway>(c => c
        .WithUrls("http://localhost:5000", "https://localhost:5001")
        .WithEnvironmentVariable("ASPNETCORE_ENVIRONMENT", "Development")
        .WithEnvironmentVariable("ConnectionStrings__Default", "..."))
    .AddProject<Projects.IdentityService>(c => c
        .WithUrls("http://localhost:5100"))
    .AddProject<Projects.OrderService>(c => c
        .WithUrls("http://localhost:5200"));

// Add executables with shell support
builder.AddExecutable("npm", "start", 
    workingDirectory: "./frontend", 
    useShellExecute: true);

var host = builder.Build();
await host.RunAsync(); // or host.Run() for synchronous execution

Features

Process Lifecycle Management

  • Automatic Startup: All resources start in parallel
  • Graceful Shutdown: Ctrl+C triggers cancellation and cleanup
  • Job Object Integration: Child processes are automatically terminated when the orchestrator exits (Windows)
  • Process Tree Cleanup: Ensures entire process trees are terminated

Project Resources

  • In-Process Execution: .NET projects run in the same process using Assembly.LoadFrom
  • URL Configuration: Configure ASP.NET Core URLs via WithUrls()
  • Environment Variables: Set per-project environment variables
  • Automatic Entry Point Detection: Finds and invokes the Main method

Executable Resources

  • External Process Support: Run npm, node, or any executable
  • Working Directory: Specify custom working directories
  • Shell Execute: Option to use shell execution for commands requiring it
  • Environment Variable Inheritance: Processes inherit environment variables

Logging Integration

  • Uses Microsoft.Extensions.Logging
  • Configurable log levels
  • Process lifecycle events logged
  • Error handling with detailed messages

Build-Time Behavior

When you build an orchestrator project:

  1. Before Compilation (GenerateProjectReferencesList target):

    • Collects all <ProjectReference> items
    • Extracts project name and full path
    • Writes to $(IntermediateOutputPath)ProjectReferences.txt
    • Adds the file to AdditionalFiles for the source generator
  2. During Compilation:

    • Source generator reads ProjectReferences.txt
    • Generates Projects.g.cs with metadata classes
    • Classes are compiled into your orchestrator project
  3. Runtime:

    • Generated metadata classes are used by AddProject<T>()
    • Projects are loaded from their DLL paths
    • Entry points are invoked with configured arguments

Project Metadata Customization

You can customize the generated type name for a project reference:

<ItemGroup>
  <ProjectReference Include="..\MyApi\MyApi.csproj" 
                    ProjectMetadataTypeName="MainApi" />
</ItemGroup>

This generates a class named MainApi instead of MyApi.

Default Global Usings

The SDK automatically includes:

  • Microsoft.Extensions.Logging
  • System.Threading.Tasks

Project Capabilities

The SDK adds the following project capabilities:

  • DynamicFileNesting
  • DynamicFileNestingEnabled
  • ArcturusOrchestration

Limitations

  • Windows Only: Job object integration currently only works on Windows
  • In-Process Execution: .NET projects run in the same AppDomain, which may cause conflicts if they have incompatible dependencies
  • .NET Standard 2.0: The SDK targets netstandard2.0 for maximum compatibility

Best Practices

  1. Use Separate Ports: Ensure each project uses unique ports to avoid conflicts
  2. Configure Logging: Set appropriate log levels to reduce noise
  3. Environment Variables: Use environment variables for configuration instead of hard-coded values
  4. Working Directories: Specify working directories for executables that depend on relative paths
  5. Graceful Shutdown: Always use RunAsync() with cancellation token support

Documentation

For detailed documentation, visit Arcturus Wiki.

License

This project is licensed under the MIT License.

Clone this wiki locally