Base16.Exec 1.0.0

dotnet add package Base16.Exec --version 1.0.0                
NuGet\Install-Package Base16.Exec -Version 1.0.0                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Base16.Exec" Version="1.0.0" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Base16.Exec --version 1.0.0                
#r "nuget: Base16.Exec, 1.0.0"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// 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.

  1. Create a new Console Application using .NET 4.5 or greater or .Net Core 2.0 or greater
  2. Add a reference to Base16.Exec using NuGet
  3. 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);
}
  1. 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

  1. 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}");
    }
}
  1. Run your application and in the console type hello-world and press ENTER. Your method will now be invoked and Hello World will be printed to the console. Try typing hello-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 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • .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