Introducing Cake Bridge Dependency Injection

Utilize Cake abstractions and addins using Microsoft dependency injection

A couple of years ago I blogged Dispelling the magic!, a post explaining the internals of the Cake build orchestration tool, with that post as a proof of concept I created Cake.Bridge assembly which provided an easy way from any .NET language get access to Cake abstractions and addins from a single instance static class.

The Need

Cake has some real nice testable abstractions around working with the filesystem, processes, tools, etc. and for a .NET project, we had just that need. But a static instance isn’t very testable, and for most of our .NET projects (console apps, APIs, Azure Functions, WPF, etc.) we now use dependency injection using Microsoft.Extensions.DependencyInjection.

So with that in mind, I created an extension method to IServiceCollection that easily provided me a way to get a IFileSystem injected and utilizing the FakeFileSystem provided by Cake.Testing for testing. That grew into supporting most core Cake types including the more complex ICakeContext and IScriptHost.

Introducing Cake.Bridge.DependencyInjection

If we got a need, chances are someone else has it too, so I’ve open-sourced the code and made it available as a NuGet package. It’s early bits tailored for a specific need, so you should expect some rough edges, but sharing is caring.

Usage

Obtain

The assembly is published at NuGet.org/packages/Cake.Bridge.DependencyInjection.

dotnet add package Cake.Bridge.DependencyInjection
<PackageReference Include="Cake.Bridge.DependencyInjection" Version="0.1.0" />

Register

using Cake.Bridge.DependencyInjection; ... serviceCollection .AddCakeCore();

Resolve

using Cake.Core; ... var cakeContext = serviceProvider.GetRequiredService<ICakeContext>();

Use

Once registered you can now via dependency injection access the majority Cake.Core interfaces with ease, i.e:

  • ICakeContext — Gives access to Cake built-in and addin aliases, and most Cake abstractions.
  • IScriptHost — Gives access to script/task runner.
  • ICakeLog — Cake logging implementation.
  • IFileSystem — Cake file system abstraction.

Example ICakeContext

using Cake.Bridge.DependencyInjection;
using Cake.Core;
using Cake.Core.Diagnostics;
using Microsoft.Extensions.DependencyInjection;

var serviceCollection = new ServiceCollection()
.AddCakeCore();

var serviceProvider = serviceCollection.BuildServiceProvider();

var cakeContext = serviceProvider.GetRequiredService<ICakeContext>();

cakeContext.Log.Write(
Verbosity.Normal,
LogLevel.Information,
"Hello World!");

will output

Hello World!

Example IScriptHost and Cake.Common

Cake.Common contains Cake aliases normally ships together with the Cake script runner, when using Cake Bridge you’ll need to add it to you project (same for any Cake addin).

dotnet add package Cake.Common --version 1.0.0-rc0002
<PackageReference Include="Cake.Common" Version="1.0.0-rc0002" />

then add the appropriate using statements and you can achieve something very similar to a Cake “script”

using Cake.Bridge.DependencyInjection;
using Cake.Core;
using Cake.Common.Diagnostics;
using Cake.Core.Scripting;
using Microsoft.Extensions.DependencyInjection;

var serviceCollection = new ServiceCollection()
.AddCakeCore();

var serviceProvider = serviceCollection.BuildServiceProvider();

var scriptHost = serviceProvider.GetRequiredService<IScriptHost>();

scriptHost.Task("Hello")
.Does(ctx => ctx.Information("Hello"));

scriptHost.Task("World")
.IsDependentOn("Hello")
.Does(ctx => ctx.Information("World"));

await scriptHost.RunTargetAsync("World");

will output

========================================
Hello
========================================
Hello

========================================
World
========================================
World

Task Duration
--------------------------------------------------
Hello 00:00:00.0226275
World 00:00:00.0002682
--------------------------------------------------
Total: 00:00:00.0228957

Complete example project

A full example console application using Spectre.Console demonstrating usage of both ICakeContext and IScriptHost can be found in project’s GitHub repository at src/Cake.Bridge.DependencyInjection.Example.

Resources

Originally published at https://www.devlead.se on January 12, 2021.

Partner & Technical fellow at WCOM AB. Microsoft Azure & Developer Technologies MVP. Been coding since I 80’s (C128 & Amiga). Father of 2, husband of 1.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store