Base16.Exec
1.0.0
dotnet add package Base16.Exec --version 1.0.0
NuGet\Install-Package Base16.Exec -Version 1.0.0
<PackageReference Include="Base16.Exec" Version="1.0.0" />
paket add Base16.Exec --version 1.0.0
#r "nuget: Base16.Exec, 1.0.0"
// Install Base16.Exec as a Cake Addin #addin nuget:?package=Base16.Exec&version=1.0.0 // Install Base16.Exec as a Cake Tool #tool nuget:?package=Base16.Exec&version=1.0.0
Base16.Exec
Introduction
Base16.Exec is a library intended to simplify and unify development of console application used for testing purposes or for "power tools". The library utilizes reflection to find methods hence forth denoted Commands
and provides an interface for invoking said commands.
Platforms
Base16.Exec supports .NET 4.5+ and .NET Core 2.0+.
Getting started
This guide will lead you through the process of using Base16.Exec and help you get started with some of the basics.
Getting started - Step 1 - Boilerplate
The first thing we need to do is hookup Base16.Exec to whatever project we've created. We'll here create a new console application that utilizes the library.
- Create a new
Console Application
using .NET 4.5 or greater or .Net Core 2.0 or greater - Add a reference to
Base16.Exec
using NuGet - Replace the content of
Program.cs
with the template below
internal static class Program
{
private static void Main(String[] args) => RunnerFactory
.CreateDefault()
.AsRunner()
.Run(args);
}
- Start your newly created application and observe what gets printed in the console
Getting started - Step 2 - Exploring Base16.Exec
Now that we got something running we can start exploring how once can Base16.Exec. We've not created any commands ourself yet but Base16.Exec comes with a couple of builtin commands for listing and describing commands.
Start by typing list-commands
in the console and observe the output.
To get more information about a command you can type help
followed by the command that you want more information about - for example help list-commands
.
Getting started - Step 3 - Adding custom commands
- Create a new class in your solution called
TestCommands
and add the method below to the class
internal class HelloCommands
{
[Base16.Exec.Annotations.Invokable]
public void World(string what = "World")
{
Console.WriteLine($"Hello {what}");
}
}
- Run your application and in the console type
hello-world
and press ENTER. Your method will now be invoked andHello World
will be printed to the console. Try typinghello-world Ahlman
and observe the output.Ahlman
is automatically mapped to the first parameter in the command.
Beyond Getting started
You can add any amount of parameters to your methods, Base16.Exec has builtin support for all common value types.
The library also supports async methods and will await any method returning a Task
or Task<T>
(IEnumerable<Task>
are not awaited).
Custom value converters
Base16.Exec supports mappings of all common value types in .NET. If the type you're working with is not supported you can create your own converter for it by implementing the interface IArgumentConverter
defined in Base16.Exec.Conversion
. Classes implementing this interface will be automatically picked up from the assembly calling RunnerFactory.CreateDefault()
. The interface contains the following two methods;
Boolean CanConvert([NotNull] Type type);
Boolean TryConvert([NotNull] Type type, [NotNull] String value, out Object result);
CanConvert
will be called by the framework when attempting to find a converter for a given argument required for invoking a command. If the converter supports the given type it should return true
else false
.
TryConvert
will be called for a converter that previously returned true
when CanConvert
was called. TryConvert
should try to convert the value given in value
to the type specified by type
. If a valid conversion cant not be performed false
should be returned so that subsequent converters can have a go at converting the value. The converted value, given that the conversion succeeded should be set in result
and true
should be returned.
Note that result
can be set to null
and true
returned if that's valid for the given converter.
Custom validators
After Base16.Exec has found a command matching specified input arguments if will validate all arguments before invoking the underlying method. Base16.Exec does not add any custom validators so these you'll have to create yourself if you wish to utilize this feature. This can be quite powerful since it allows you to annotate your methods with requirements for execution.
Consider the following commands;
internal class FileSystemCommands
{
[Invokable(Name = "get-file-size")]
public Int64 GetFileSize(String filename) => new FileInfo(filename).Length;
[Invokable(Name = "get-file-last-access-time")]
public DateTime GetFileLastAccessTime(String filename) => new FileInfo(filename).LastAccessTime;
}
Invoking get-file-size
for a file that exists will output the file to the console but if you try to invoke the command with a file that does not exist an exception will be thrown. You could handle this in each method, wrap the methods, let Base16.Exec catch the exceptions or you could add a custom validator that ensures that whatever file you're trying to access actually exists before invoking the commands.
Adding a custom validator is simple - just add the following class to your project;
[AttributeUsage(AttributeTargets.Parameter)]
internal class ExistingFileAttribute : ValidationAttribute
{
public override Task<String> ValidateAsync(CommandExecutionContext context, Object value)
{
return File.Exists(value as String)
? Task.FromResult(String.Empty)
: Task.FromResult($"The file '{value}' was not found");
}
}
Then modify your FileSystemCommands
to;
internal class FileSystemCommands
{
[Invokable(Name = "get-file-last-access-time")]
public DateTime GetFileLastAccessTime([ExistingFile] String filename) => new FileInfo(filename).LastAccessTime;
[Invokable(Name = "get-file-size")]
public Int64 GetFileSize([ExistingFile] String filename) => new FileInfo(filename).Length;
}
Now try invoking get-file-size
with an non-existing file again and observe the difference. Files have been chosen as an example but you get the idea.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
.NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
.NET Framework | net45 is compatible. net451 was computed. net452 was computed. net46 was computed. net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen40 was computed. tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETFramework 4.5
- No dependencies.
-
.NETStandard 2.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
1.0.0 | 1,308 | 11/4/2018 |