Cake.Sdk provides built-in support for dependency injection using the .NET IoC container. You can register services and resolve them in your tasks using the IServiceCollection and ServiceProvider.
Registering services
Register services using the RegisterServices partial method. This method is automatically discovered and called during the build initialization.
Basic service registration
#:sdk Cake.Sdk
public static partial class Program
{
static partial void RegisterServices(IServiceCollection services)
{
services.AddSingleton<IMyService, MyService>();
}
}
Registering multiple services
You can register multiple services in the same method:
static partial void RegisterServices(IServiceCollection services)
{
services.AddSingleton<IMyService, MyService>();
services.AddTransient<IAnotherService, AnotherService>();
services.AddScoped<IDataService, DataService>();
}
Service lifetime options
Cake.Sdk supports the standard .NET service lifetime options:
AddSingleton- Creates a single instance for the entire buildAddScoped- Creates an instance per scope (typically per task execution)AddTransient- Creates a new instance each time it's requested
Resolving services
Resolve services in your tasks using the ServiceProvider property:
Task("MyTask")
.Does(() =>
{
var service = ServiceProvider.GetRequiredService<IMyService>();
service.DoSomething();
});
Optional service resolution
Use GetService for optional dependencies that may not be registered:
Task("MyTask")
.Does(() =>
{
var service = ServiceProvider.GetService<IMyService>();
if (service != null)
{
service.DoSomething();
}
});
Registering tasks as dependencies
You can register tasks as dependencies using the IoC container. This is useful for dynamically creating tasks based on configuration or other services:
public static partial class Program
{
static partial void RegisterServices(IServiceCollection services)
{
// Register MyService
services.AddSingleton<IMyService, MyService>();
// Injects IOC-Task as a dependency of Build task
services.AddSingleton(new Action<IScriptHost>(
host => host.Task("IOC-Task")
.IsDependeeOf("Build")
.Does(() => Information("Hello from IOC-Task"))));
}
}
Example
Here's a complete example showing how to use the IoC container:
Service interface and implementation
public interface ILoggerService
{
void LogInfo(string message);
void LogError(string message);
}
public class LoggerService : ILoggerService
{
public void LogInfo(string message)
{
Information($"INFO: {message}");
}
public void LogError(string message)
{
Error($"ERROR: {message}");
}
}
Registering and using the service
#:sdk Cake.Sdk
public static partial class Program
{
static partial void RegisterServices(IServiceCollection services)
{
services.AddSingleton<ILoggerService, LoggerService>();
}
}
var target = Argument("target", "Default");
Task("Default")
.Does(() =>
{
var logger = ServiceProvider.GetRequiredService<ILoggerService>();
logger.LogInfo("Hello from IoC Container!");
});
RunTarget(target);
Multi-file structure
When using a multi-file structure, you can organize your service registrations in separate files:
Main file (build.cs)
#:sdk Cake.Sdk
#:property IncludeAdditionalFiles=build/**/*.cs
var target = Argument("target", "Default");
Task("Default")
.Does(() =>
{
var logger = ServiceProvider.GetRequiredService<ILoggerService>();
logger.LogInfo("Hello from IoC Container!");
});
RunTarget(target);
IoC registration file (build/IoC.cs)
public static partial class Program
{
static partial void RegisterServices(IServiceCollection services)
{
services.AddSingleton<ILoggerService, LoggerService>();
services.AddSingleton<IBuildService, BuildService>();
}
}
Service implementations (build/Services.cs)
public interface ILoggerService
{
void LogInfo(string message);
}
public class LoggerService : ILoggerService
{
public void LogInfo(string message)
{
Information($"INFO: {message}");
}
}
