Skip to content

DevTeam/csharp-interactive

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Build automation system for .NET

NuGet csi GitHub GitHub Build

C# interactive build automation system makes it easy to build .NET projects. It can be part of your solution as a regular .NET console project or run C# scripts without compiling them, or even run in REPL mode - allowing you to run C# interactively.

Key Features

✔️ Three Integrated Execution Modes

  • Flexible interoperability between modes (#operating-modes) to adapt to diverse workflow requirements.

✔️ Native Cross-Platform Support

  • Seamlessly operates on Windows, Linux, and macOS without compatibility compromises.

✔️ Integrated Debugging Capabilities

  • Debug ".NET build projects" directly to identify and resolve issues during compilation and builds.

✔️ Zero Abstraction Overhead

  • Eliminates restrictive constructs (e.g., Tasks/Targets):
  • Pure .NET codebase – no proprietary syntax or hidden layers
  • Industry-standard practices ensure long-term maintainability

✔️ Granular Build Control API

  • Precise management of builds, tests, and deployments with streamlined project configuration.

✔️ Consolidated Build Analytics

  • Actionable insights through summarized statistics.

Operating modes

.NET build project

Seamless integration into existing solutions as a standard .NET console project.

Typical .NET console project

  1. Create the Project
    Initialize a new console application using .NET CLI:
dotnet new console -n MyBuildApp
cd MyConsoleApp
  1. Add a reference to the Build automation library for .NET
    Add the CSharpInteractive NuGet package for scripting capabilities:
dotnet add package CSharpInteractive

Creating a Build Automation Project from the build template

  1. Install the Template
    First, install the CSharpInteractive.Templates NuGet package as a dotnet template:
dotnet new install CSharpInteractive.Templates

Detailed installation guide

  1. Generate the Project
    Create a new project named Build using the template:
dotnet new build -o ./Build

Dual Execution Modes

The generated project supports two run methods:

  • Compiled Application (via Program.cs):
    dotnet run --project ./Build
  • Script Execution (via Program.csx):
    dotnet csi ./Build
Running C# script

Direct execution of C# scripts without prior compilation:

  • Zero-Compilation Workflow - execute .csx files directly using Roslyn scripting engines, bypassing traditional dotnet build steps for rapid iteration.
  • Cross-Platform Scripting
    • Windows - integrate with PowerShell/PowerShell Core automation pipelines
    • Linux/macOS - combine with bash/zsh scripts via shebang directives (#!/usr/bin/env dotnet-script)
    • Dependency Management - resolve NuGet packages in scripts via #r "nuget: PackageName/Version" syntax, with local cache optimization.

Run a specified script with a given argument:

dotnet csi ./MyDirectory/hello.csx World 

Run a single script located in the MyDirectory directory:

dotnet csi ./MyDirectory World
Usage details
dotnet csi [options] [--] [script] [script arguments]

Executes a script if specified, otherwise launches an interactive REPL (Read Eval Print Loop).

-- - Indicates that the remaining arguments should not be treated as options.

script - The path to the script file to run. If no such file is found, the command will treat it as a directory and look for a single script file inside that directory.

script arguments - Script arguments are accessible in a script via the global list Args[index] by an argument index.

@file - Read the response file for more options.

Supported options:

Option Description Alternative form
--help Show how to use the command. /?, -h, /h, /help
--version Display the tool version. /version
--source Specify the NuGet package source to use. Supported formats: URL, or a UNC directory path. -s, /s, /source
--property <key=value> Define a key-value pair(s) for the script properties called Props, which is accessible in scripts. -p, /property, /p
--property:<key=value> Define a key-value pair(s) in MSBuild style for the script properties called Props, which is accessible in scripts. -p:<key=value>, /property:<key=value>, /p:<key=value>, --property:key1=val1;key2=val2
Interactive

REPL (Read-Eval-Print-Loop) interface for interactive code evaluation. Please see this page for installation details.

Launch the tool in the interactive mode:

dotnet csi

Simply enter C# commands sequentially one line after another and get the result in console output.

NuGet packages

Package name Link Description Installation
dotnet-csi NuGet C# script runner and REPL tool for build automation dotnet tool install --global dotnet-csi
CSharpInteractive NuGet Build automation library for .NET dotnet add package CSharpInteractive
CSharpInteractive.Templates NuGet Build automation project templates for .NET dotnet new install CSharpInteractive.Templates

Usage examples

API

Output, logging and tracing

Writing a line to a build log

WriteLine("Hello");

Writing a line highlighted with "Header" color to a build log

WriteLine("Hello", Header);
WriteLine("Hello ".WithColor(Header), "world!");

Writing an empty line to a build log

WriteLine();

Registering errors in the build log

Error("Error info");
Error("Error info", "Error identifier");
Error("Error: ".WithColor(), "datails".WithColor(Color.Details));

Registering warnings in the build log

Warning("Warning info");
Warning("Warning ", "info".WithColor(Color.Details));

Registering a summary in the build log

Summary("Summary message");
Summary("Summary ", "message".WithColor(Color.Details));

Registering information in the build log

Info("Some info");
Info("Some ", "info".WithColor(Color.Details));

Registering trace information in the build log

Trace("Some trace info");
Trace("Some trace ", "info".WithColor(Color.Details));

Arguments and parameters

Command line arguments

Args have got from the script arguments.

if (Args.Count > 0)
{
    WriteLine(Args[0]);
}

if (Args.Count > 1)
{
    WriteLine(Args[1]);
}

Using properties

WriteLine(Props["version"]);
WriteLine(Props.Get("configuration", "Release"));

// Some CI/CDs have integration of these properties.
// For example in TeamCity this property with all changes will be available in the next TeamCity steps.
Props["version"] = "1.1.6";

Microsoft DI

Using the Host property

Host is actually the provider of all global properties and methods.

var packages = Host.GetService<INuGet>();
Host.WriteLine("Hello");

Getting services

This method might be used to get access to different APIs like INuGet or ICommandLine.

GetService<INuGet>();

var serviceProvider = GetService<IServiceProvider>();
serviceProvider.GetService(typeof(INuGet));

Besides that, it is possible to get an instance of System.IServiceProvider to access APIs.

Using service collections

public void Run()
{
    var serviceProvider =
        GetService<IServiceCollection>()
            .AddTransient<MyTask>()
            .BuildServiceProvider();

    var myTask = serviceProvider.GetRequiredService<MyTask>();
    var exitCode = myTask.Run();
    exitCode.ShouldBe(0);
}

private class MyTask(ICommandLineRunner runner)
{
    public int? Run() => runner
        .Run(new CommandLine("whoami"))
        .EnsureSuccess()
        .ExitCode;
}

NuGet

Restoring a NuGet package of newest version

using HostApi;

IEnumerable<NuGetPackage> packages = GetService<INuGet>()
    .Restore(new NuGetRestoreSettings("IoC.Container").WithVersionRange(VersionRange.All));

Restoring a NuGet package by a version range for the specified .NET and path

using HostApi;

var packagesPath = Path.Combine(
    Path.GetTempPath(),
    Guid.NewGuid().ToString()[..4]);

var settings = new NuGetRestoreSettings("IoC.Container")
    .WithVersionRange(VersionRange.Parse("[1.3, 1.3.8)"))
    .WithTargetFrameworkMoniker("net5.0")
    .WithPackagesPath(packagesPath);

IEnumerable<NuGetPackage> packages = GetService<INuGet>().Restore(settings);

Command Line

Building custom command lines

using HostApi;

// Creates and run a simple command line 
"whoami".AsCommandLine().Run().EnsureSuccess();

// Creates and run a simple command line 
new CommandLine("whoami").Run().EnsureSuccess();

// Creates and run a command line with arguments 
new CommandLine("cmd", "/c", "echo", "Hello").Run();

// Same as previous statement
new CommandLine("cmd", "/c")
    .AddArgs("echo", "Hello")
    .Run().EnsureSuccess();

(new CommandLine("cmd") + "/c" + "echo" + "Hello")
    .Run().EnsureSuccess();

"cmd".AsCommandLine("/c", "echo", "Hello")
    .Run().EnsureSuccess();

("cmd".AsCommandLine() + "/c" + "echo" + "Hello")
    .Run().EnsureSuccess();

// Just builds a command line with multiple environment variables
var cmd = new CommandLine("cmd", "/c", "echo", "Hello")
    .AddVars(("Var1", "val1"), ("var2", "Val2"));

// Same as previous statement
cmd = new CommandLine("cmd") + "/c" + "echo" + "Hello" + ("Var1", "val1") + ("var2", "Val2");

// Builds a command line to run from a specific working directory 
cmd = new CommandLine("cmd", "/c", "echo", "Hello")
    .WithWorkingDirectory("MyDyrectory");

// Builds a command line and replaces all command line arguments
cmd = new CommandLine("cmd", "/c", "echo", "Hello")
    .WithArgs("/c", "echo", "Hello !!!");

Running a command line

using HostApi;

GetService<ICommandLineRunner>()
    .Run(new CommandLine("cmd", "/c", "DIR")).EnsureSuccess();

// or the same thing using the extension method
new CommandLine("cmd", "/c", "DIR")
    .Run().EnsureSuccess();

// using operator '+'
var cmd = new CommandLine("cmd") + "/c" + "DIR";
cmd.Run().EnsureSuccess();

// with environment variables
cmd = new CommandLine("cmd") + "/c" + "DIR" + ("MyEnvVar", "Some Value");
cmd.Run().EnsureSuccess();

Running a command line asynchronously

using HostApi;

await GetService<ICommandLineRunner>()
    .RunAsync(new CommandLine("cmd", "/C", "DIR")).EnsureSuccess();

// or the same thing using the extension method
var result = await new CommandLine("cmd", "/c", "DIR")
    .RunAsync().EnsureSuccess();

Running and analyzing an output

using HostApi;

var lines = new List<string>();
var result = new CommandLine("cmd", "/c", "SET")
    .AddVars(("MyEnv", "MyVal"))
    .Run(output => lines.Add(output.Line)).EnsureSuccess();

lines.ShouldContain("MyEnv=MyVal");

Running asynchronously in parallel

using HostApi;

var task = new CommandLine("cmd", "/c", "DIR")
    .RunAsync().EnsureSuccess();

var result = new CommandLine("cmd", "/c", "SET")
    .Run().EnsureSuccess();

await task;

Cancellation of asynchronous run

Cancellation will destroy the process and its child processes.

using HostApi;

var cancellationTokenSource = new CancellationTokenSource();
var task = new CommandLine("cmd", "/c", "TIMEOUT", "/T", "120")
    .RunAsync(null, cancellationTokenSource.Token);

cancellationTokenSource.CancelAfter(TimeSpan.FromMilliseconds(100));
task.IsCompleted.ShouldBeFalse();

Running with timeout

If timeout expired a process will be killed.

using HostApi;

var exitCode = new CommandLine("cmd", "/c", "TIMEOUT", "/T", "120")
    .Run(null, TimeSpan.FromMilliseconds(1))
    .ExitCode;

Docker CLI

Building a project in a docker container

using HostApi;

// Creates a base docker command line
var dockerRun = new DockerRun()
    .WithAutoRemove(true)
    .WithInteractive(true)
    .WithImage("mcr.microsoft.com/dotnet/sdk")
    .WithPlatform("linux")
    .WithContainerWorkingDirectory("/MyProjects")
    .AddVolumes((ToAbsoluteLinuxPath(Environment.CurrentDirectory), "/MyProjects"));

// Creates a new library project in a docker container
dockerRun
    .WithCommandLine(new DotNetCustom("new", "classlib", "-n", "MyLib", "--force"))
    .Run().EnsureSuccess();

// Builds the library project in a docker container
var result = dockerRun
    .WithCommandLine(new DotNetBuild().WithProject("MyLib/MyLib.csproj"))
    .Build().EnsureSuccess();

string ToAbsoluteLinuxPath(string path) =>
    "/" + path.Replace(":", "").Replace('\\', '/');

Running in docker

using HostApi;

// Creates some command line to run in a docker container
var cmd = new CommandLine("whoami");

// Runs the command line in a docker container
var result = new DockerRun(cmd, "mcr.microsoft.com/dotnet/sdk")
    .WithAutoRemove(true)
    .Run().EnsureSuccess();

.NET CLI

Adding a NuGet package

using HostApi;

var result = new DotNetAddPackage()
    .WithWorkingDirectory("MyLib")
    .WithPackage("Pure.DI")
    .Run().EnsureSuccess();

Adding a NuGet source

using HostApi;

new DotNetNuGetAddSource()
    .WithName("TestSource")
    .WithSource(source)
    .Run().EnsureSuccess();

Adding a project reference

using HostApi;

new DotNetAddReference()
    .WithProject(Path.Combine("MyTests", "MyTests.csproj"))
    .WithReferences(Path.Combine("MyLib", "MyLib.csproj"))
    .Run().EnsureSuccess();

new DotNetRemoveReference()
    .WithProject(Path.Combine("MyTests", "MyTests.csproj"))
    .WithReferences(Path.Combine("MyLib", "MyLib.csproj"))
    .Run().EnsureSuccess();

var lines = new List<string>();
new DotNetListReference()
    .WithProject(Path.Combine("MyTests", "MyTests.csproj"))
    .Run(output => lines.Add(output.Line));

lines.Any(i => i.Contains("MyLib.csproj")).ShouldBeFalse();

Adding projects to the solution file

using HostApi;

new DotNetNew()
    .WithTemplateName("sln")
    .WithName("MySolution")
    .WithForce(true)
    .AddArgs("--format", "sln")
    .Run().EnsureSuccess();

new DotNetSlnAdd()
    .WithSolution("MySolution.sln")
    .AddProjects(
        Path.Combine("MyLib", "MyLib.csproj"),
        Path.Combine("MyTests", "MyTests.csproj"))
    .Run().EnsureSuccess();

Adding project-to-project (P2P) references

using HostApi;

var result = new DotNetAddReference()
    .WithProject(Path.Combine("MyTests", "MyTests.csproj"))
    .WithReferences(Path.Combine("MyLib", "MyLib.csproj"))
    .Run().EnsureSuccess();

Building a project

using HostApi;

var messages = new List<BuildMessage>();
var result = new DotNetBuild()
    .WithWorkingDirectory("MyTests")
    .Build(message => messages.Add(message)).EnsureSuccess();

result.Errors.Any(message => message.State == BuildMessageState.StdError).ShouldBeFalse(result.ToString());
result.ExitCode.ShouldBe(0, result.ToString());

Building a project using MSBuild

using HostApi;

// Creates a new library project, running a command like: "dotnet new classlib -n MyLib --force"
new DotNetNew()
    .WithTemplateName("classlib")
    .WithName("MyLib")
    .WithForce(true)
    .Build().EnsureSuccess();

// Builds the library project, running a command like: "dotnet msbuild /t:Build -restore /p:configuration=Release -verbosity=detailed" from the directory "MyLib"
var result = new MSBuild()
    .WithWorkingDirectory("MyLib")
    .WithTarget("Build")
    .WithRestore(true)
    .AddProps(("configuration", "Release"))
    .WithVerbosity(DotNetVerbosity.Detailed)
    .Build().EnsureSuccess();

// The "result" variable provides details about a build
result.Errors.Any(message => message.State == BuildMessageState.StdError).ShouldBeFalse(result.ToString());
result.ExitCode.ShouldBe(0, result.ToString());

Cleaning a project

using HostApi;

// Clean the project, running a command like: "dotnet clean" from the directory "MyLib"
new DotNetClean()
    .WithWorkingDirectory("MyLib")
    .Build().EnsureSuccess();

Clearing the specified NuGet cache type

using HostApi;

new DotNetNuGetLocalsClear()
    .WithCacheLocation(NuGetCacheLocation.Temp)
    .Run().EnsureSuccess();

Creating a new project, configuration file, or solution based on the specified template

using HostApi;

new DotNetNew()
    .WithTemplateName("classlib")
    .WithName("MyLib")
    .WithForce(true)
    .Run().EnsureSuccess();

Deleting a NuGet package to the server

using HostApi;

new DotNetNuGetDelete()
    .WithPackage("MyLib")
    .WithPackageVersion("1.0.0")
    .WithSource(repoUrl)
    .Run().EnsureSuccess();

Disabling a NuGet source

using HostApi;

new DotNetNuGetDisableSource()
    .WithName("TestSource")
    .Run().EnsureSuccess();

Displaing template package metadata

using HostApi;

new DotNetNewDetails()
    .WithTemplateName("CSharpInteractive.Templates")
    .Run().EnsureSuccess();

Enabling a NuGet source

using HostApi;

new DotNetNuGetEnableSource()
    .WithName("TestSource")
    .Run().EnsureSuccess();

Enabling or disabling workload-set update mode

using HostApi;

new DotNetWorkloadConfig()
    .WithUpdateMode(DotNetWorkloadUpdateMode.WorkloadSet)
    .Run().EnsureSuccess();

Executing a dotnet application

using HostApi;
new DotNetExec()
    .WithPathToApplication(Path.Combine(path, "MyApp.dll"))
    .Run().EnsureSuccess();

Fixing (non code style) analyzer issues

using HostApi;

new DotNetFormatAnalyzers()
    .WithWorkingDirectory("MyLib")
    .WithProject("MyLib.csproj")
    .AddDiagnostics("CA1831", "CA1832")
    .WithSeverity(DotNetFormatSeverity.Warning)
    .Run().EnsureSuccess();

Fixing code style issues

using HostApi;

new DotNetFormatStyle()
    .WithWorkingDirectory("MyLib")
    .WithProject("MyLib.csproj")
    .AddDiagnostics("IDE0005", "IDE0006")
    .WithSeverity(DotNetFormatSeverity.Information)
    .Run().EnsureSuccess();

Formatting a code

using HostApi;

new DotNetFormat()
    .WithWorkingDirectory("MyLib")
    .WithProject("MyLib.csproj")
    .AddDiagnostics("IDE0005", "IDE0006")
    .AddIncludes(".", "./tests")
    .AddExcludes("./obj")
    .WithSeverity(DotNetFormatSeverity.Information)
    .Run().EnsureSuccess();

Getting a value of a specified NuGet configuration setting

using HostApi;

string? repositoryPath = null;
new DotNetNuGetConfigGet()
    .WithConfigKey("repositoryPath")
    .Run(output => repositoryPath = output.Line).EnsureSuccess();

Installing a template package

using HostApi;

new DotNetNewInstall()
    .WithPackage("Pure.DI.Templates")
    .Run().EnsureSuccess();

Installing optional workloads

using HostApi;

new DotNetWorkloadInstall()
    .AddWorkloads("aspire")
    .Run().EnsureSuccess();

Installing the .NET local tools that are in scope for the current directory

using HostApi;

// Creates a local tool manifest 
new DotNetNew()
    .WithTemplateName("tool-manifest")
    .Run().EnsureSuccess();

new DotNetToolRestore()
    .Run().EnsureSuccess();

Installing the specified .NET tool

using HostApi;

new DotNetToolInstall()
    .WithLocal(true)
    .WithPackage("dotnet-csi")
    .WithVersion("1.1.2")
    .Run().EnsureSuccess();

Installing workloads needed for a project or a solution

using HostApi;

new DotNetWorkloadRestore()
    .WithProject(Path.Combine("MyLib", "MyLib.csproj"))
    .Run().EnsureSuccess();

Invoking a local tool

using HostApi;

var script = Path.GetTempFileName();
File.WriteAllText(script, "Console.WriteLine($\"Hello, {Args[0]}!\");");

var stdOut = new List<string>();
new DotNetToolRun()
    .WithCommandName("dotnet-csi")
    .AddArgs(script)
    .AddArgs("World")
    .Run(output => stdOut.Add(output.Line))
    .EnsureSuccess();

// Checks stdOut
stdOut.Contains("Hello, World!").ShouldBeTrue();

Packing a code into a NuGet package

using HostApi;

// Creates a NuGet package of version 1.2.3 for the project
new DotNetPack()
    .WithWorkingDirectory("MyLib")
    .WithOutput(path)
    .AddProps(("version", "1.2.3"))
    .Build().EnsureSuccess();

Printing a dependency graph for NuGet package

using HostApi;

new DotNetNuGetWhy()
    .WithProject(Path.Combine("MyLib", "MyLib.csproj"))
    .WithPackage("MyLib.1.2.3.nupkg")
    .Run().EnsureSuccess();

Printing all .NET tools of the specified type currently installed

using HostApi;

new DotNetToolList()
    .WithLocal(true)
    .Run().EnsureSuccess();

new DotNetToolList()
    .WithGlobal(true)
    .Run().EnsureSuccess();

Printing all configured NuGet sources

using HostApi;

new DotNetNuGetListSource()
    .WithFormat(NuGetListFormat.Short)
    .Run().EnsureSuccess();

Printing all projects in a solution file

using HostApi;

var lines = new List<string>();
new DotNetSlnList()
    .WithSolution("MySolution.sln")
    .Run(output => lines.Add(output.Line))
    .EnsureSuccess();

Printing available templates to be run using dotnet new

using HostApi;

new DotNetNewList()
    .Run().EnsureSuccess();

Printing installed workloads

using HostApi;

new DotNetWorkloadList()
    .Run().EnsureSuccess();

Printing nuget configuration files currently being applied to a directory

using HostApi;

var configPaths = new List<string>();
new DotNetNuGetConfigPaths()
    .Run(output => configPaths.Add(output.Line)).EnsureSuccess();

Printing NuGet packages for a project

using HostApi;

new DotNetAddPackage()
    .WithWorkingDirectory("MyLib")
    .WithPackage("Pure.DI")
    .Run().EnsureSuccess();

var lines = new List<string>();
new DotNetListPackage()
    .WithProject(Path.Combine("MyLib", "MyLib.csproj"))
    .WithVerbosity(DotNetVerbosity.Minimal)
    .Run(output => lines.Add(output.Line));

lines.Any(i => i.Contains("Pure.DI")).ShouldBeTrue();

Printing project references for a project

using HostApi;

new DotNetAddReference()
    .WithProject(Path.Combine("MyTests", "MyTests.csproj"))
    .WithReferences(Path.Combine("MyLib", "MyLib.csproj"))
    .Run().EnsureSuccess();

var lines = new List<string>();
new DotNetListReference()
    .WithProject(Path.Combine("MyTests", "MyTests.csproj"))
    .Run(output => lines.Add(output.Line));

lines.Any(i => i.Contains("MyLib.csproj")).ShouldBeTrue();

Printing the latest available version of the .NET SDK and .NET Runtime, for each feature band

using HostApi;

var sdks = new List<Sdk>();
new DotNetSdkCheck()
    .Run(output =>
    {
        if (output.Line.StartsWith("Microsoft."))
        {
            var data = output.Line.Split(' ', StringSplitOptions.RemoveEmptyEntries);
            if (data.Length >= 2)
            {
                sdks.Add(new Sdk(data[0], NuGetVersion.Parse(data[1])));
            }
        }
    })
    .EnsureSuccess();

sdks.Count.ShouldBeGreaterThan(0);

record Sdk(string Name, NuGetVersion Version);

Printing the location of the specified NuGet cache type

using HostApi;

new DotNetNuGetLocalsList()
    .WithCacheLocation(NuGetCacheLocation.GlobalPackages)
    .Run().EnsureSuccess();

Publishing an application and its dependencies to a folder for deployment to a hosting system

using HostApi;

new DotNetPublish()
    .WithWorkingDirectory("MyLib")
    .WithFramework(framework)
    .WithOutput("bin")
    .Build().EnsureSuccess();

Pushing a NuGet package to the server

using HostApi;

new DotNetNuGetPush()
    .WithWorkingDirectory("MyLib")
    .WithPackage(Path.Combine("packages", "MyLib.1.0.0.nupkg"))
    .WithSource(repoUrl)
    .Run().EnsureSuccess();

Removing a NuGet package

using HostApi;

new DotNetAddPackage()
    .WithWorkingDirectory("MyLib")
    .WithPackage("Pure.DI")
    .Run().EnsureSuccess();

new DotNetRemovePackage()
    .WithWorkingDirectory("MyLib")
    .WithPackage("Pure.DI")
    .Run().EnsureSuccess();

Removing a project or multiple projects from the solution file

using HostApi;

new DotNetSlnRemove()
    .WithSolution("MySolution.sln")
    .AddProjects(
        Path.Combine("MyLib", "MyLib.csproj"))
    .Run().EnsureSuccess();

Removing an existing source from your NuGet configuration files

using HostApi;

new DotNetNuGetRemoveSource()
    .WithName("TestSource")
    .Run().EnsureSuccess(); 

Repairing workloads installations

using HostApi;

new DotNetWorkloadRepair()
    .Run().EnsureSuccess();

Restoring the dependencies and tools of a project

using HostApi;

new DotNetRestore()
    .WithProject(Path.Combine("MyLib", "MyLib.csproj"))
    .Build().EnsureSuccess();

Running a .NET application

// Adds the namespace "HostApi" to use .NET build API
using HostApi;

new DotNet()
    .WithPathToApplication(Path.Combine(path, "MyApp.dll"))
    .Run().EnsureSuccess();

Running a custom .NET command

using HostApi;

// Gets the dotnet version, running a command like: "dotnet --version"
NuGetVersion? version = null;
new DotNetCustom("--version")
    .Run(message => NuGetVersion.TryParse(message.Line, out version))
    .EnsureSuccess();

version.ShouldNotBeNull();

Running source code without any explicit compile or launch commands

using HostApi;

var stdOut = new List<string>();
new DotNetRun()
    .WithProject(Path.Combine("MyApp", "MyApp.csproj"))
    .Build(message => stdOut.Add(message.Text))
    .EnsureSuccess();

Running tests from the specified assemblies

using HostApi;

// Runs tests
var result = new VSTest()
    .AddTestFileNames(Path.Combine("bin", "MyTests.dll"))
    .WithWorkingDirectory(path)
    .Build().EnsureSuccess();

// The "result" variable provides details about build and tests
result.ExitCode.ShouldBe(0, result.ToString());
result.Summary.Tests.ShouldBe(1, result.ToString());
result.Tests.Count(test => test.State == TestState.Finished).ShouldBe(1, result.ToString());

Searching all .NET tools that are published to NuGet

using HostApi;

new DotNetToolSearch()
    .WithPackage("dotnet-csi")
    .WithDetail(true)
    .Run().EnsureSuccess();

Searching for a NuGet package

using System.Text;
using System.Text.Json;
using HostApi;

var packagesJson = new StringBuilder();
new DotNetPackageSearch()
    .WithSearchTerm("Pure.DI")
    .WithFormat(DotNetPackageSearchResultFormat.Json)
    .Run(output => packagesJson.AppendLine(output.Line)).EnsureSuccess();

var result = JsonSerializer.Deserialize<Result>(
    packagesJson.ToString(),
    new JsonSerializerOptions { PropertyNameCaseInsensitive = true });

result.ShouldNotBeNull();
result.SearchResult.SelectMany(i => i.Packages).Count(i => i.Id == "Pure.DI").ShouldBe(1);

record Result(int Version, IReadOnlyCollection<Source> SearchResult);

record Source(string SourceName, IReadOnlyCollection<Package> Packages);

record Package(
    string Id,
    string LatestVersion,
    int TotalDownloads,
    string Owners);

Searching for optional workloads

using HostApi;

new DotNetWorkloadSearch()
    .WithSearchString("maui")
    .Run().EnsureSuccess();

Searching for the templates

using HostApi;

new DotNetNewSearch()
    .WithTemplateName("build")
    .Run().EnsureSuccess();

Setting the value of a specified NuGet configuration setting

using HostApi;

new DotNetNuGetConfigSet()
    .WithConfigFile(configFile)
    .WithConfigKey("repositoryPath")
    .WithConfigValue("MyValue")
    .Run().EnsureSuccess();

Signing with certificate

using HostApi;

new DotNetNuGetSign()
    .AddPackages("MyLib.1.2.3.nupkg")
    .WithCertificatePath("certificate.pfx")
    .WithCertificatePassword("Abc")
    .WithTimestampingServer("http://timestamp.digicert.com/")
    .Run().EnsureSuccess();

Storing the specified assemblies in the runtime package store.

using HostApi;

new DotNetStore()
    .AddManifests(Path.Combine("MyLib", "MyLib.csproj"))
    .WithFramework("net8.0")
    .WithRuntime("win-x64")
    .Build();

Testing a project using the MSBuild VSTest target

using HostApi;

// Runs tests via a command
var result = new MSBuild()
    .WithTarget("VSTest")
    .WithWorkingDirectory("MyTests")
    .Build().EnsureSuccess();

// The "result" variable provides details about a build
result.ExitCode.ShouldBe(0, result.ToString());
result.Summary.Tests.ShouldBe(1, result.ToString());
result.Tests.Count(test => test.State == TestState.Finished).ShouldBe(1, result.ToString());

Testing from the specified project

using HostApi;

// Runs tests
var result = new DotNetTest()
    .WithProject("MyTests")
    .Build().EnsureSuccess();

Uninstalling a specified workload

using HostApi;

new DotNetWorkloadUninstall()
    .AddWorkloads("aspire")
    .Run().EnsureSuccess();

Uninstalling a template package

using HostApi;

new DotNetNewUninstall()
    .WithPackage("Pure.DI.Templates")
    .Run();

Uninstalling the specified .NET tool

using HostApi;

new DotNetToolUninstall()
    .WithPackage("dotnet-csi")
    .Run().EnsureSuccess();

Unsetting the value of a specified NuGet configuration setting

using HostApi;

new DotNetNuGetConfigUnset()
    .WithConfigKey("repositoryPath")
    .Run().EnsureSuccess();

Updating a NuGet source

using HostApi;

new DotNetNuGetUpdateSource()
    .WithName("TestSource")
    .WithSource(newSource)
    .Run().EnsureSuccess();

Updating installed template packages

using HostApi;

new DotNetNewUpdate()
    .Run().EnsureSuccess();

Updating installed workloads

using HostApi;

new DotNetWorkloadUpdate()
    .Run().EnsureSuccess();

Updating the specified .NET tool

using HostApi;

new DotNetToolUpdate()
    .WithLocal(true)
    .WithPackage("dotnet-csi")
    .WithVersion("1.1.2")
    .Run().EnsureSuccess();

Working with development certificates

using HostApi;

// Create a certificate, trust it, and export it to a PEM file.
new DotNetDevCertsHttps()
    .WithExportPath("certificate.pem")
    .WithTrust(true)
    .WithFormat(DotNetCertificateFormat.Pem)
    .WithPassword("Abc")
    .Run().EnsureSuccess();

Running C# script

using HostApi;

var script = Path.GetTempFileName();
File.WriteAllText(script, "Console.WriteLine($\"Hello, {Args[0]}!\");");

var stdOut = new List<string>();
new DotNetCsi()
    .WithScript(script)
    .AddArgs("World")
    .Run(output => stdOut.Add(output.Line))
    .EnsureSuccess();

// Checks stdOut
stdOut.Contains("Hello, World!").ShouldBeTrue();

Shutting down build servers

using HostApi;

// Shuts down all build servers that are started from dotnet.
new DotNetBuildServerShutdown()
    .Run().EnsureSuccess();

TeamCity API

TeamCity integration via service messages

For more details how to use TeamCity service message API please see this page. Instead of creating a root message writer like in the following example:

using JetBrains.TeamCity.ServiceMessages.Write.Special;
using var writer = new TeamCityServiceMessages().CreateWriter(Console.WriteLine);

use this statement:

using JetBrains.TeamCity.ServiceMessages.Write.Special;
using var writer = GetService<ITeamCityWriter>();

This sample opens a block My Tests and reports about two tests:

// Adds a namespace to use ITeamCityWriter
using JetBrains.TeamCity.ServiceMessages.Write.Special;

using var writer = GetService<ITeamCityWriter>();
using (var tests = writer.OpenBlock("My Tests"))
{
    using (var test = tests.OpenTest("Test1"))
    {
        test.WriteStdOutput("Hello");
        test.WriteImage("TestsResults/Test1Screenshot.jpg", "Screenshot");
        test.WriteDuration(TimeSpan.FromMilliseconds(10));
    }

    using (var test = tests.OpenTest("Test2"))
    {
        test.WriteIgnored("Some reason");
    }
}

For more information on TeamCity Service Messages, see this page.