Skip to content

Writing Console Apps with DotNet in 2022 - Part 2 - Cocona

<span>Image by Eamonn Flynn</span>
Image by Eamonn Flynn

This blog is part of a series of blog posts looking at .Net packages to help .Net Developers create console apps.

Cocona

Cocona is a "Micro Framework" for building .Net Core console Applications, Written by Mayuki Sawatari

Its available on Github - https://github.com/mayuki/Cocona

and on Nuget https://www.nuget.org/packages/Cocona/

Getting started

You can create a very simple console app with just the following line

CoconaApp.Run((string name, int age) => { Console.WriteLine($"Hello {name} you are {age}.") });

Inspiration

The inspiration for Cocona comes from the work done on .Net Minimal Apis

so a console application can be structured as

using Cocona;

var app = CoconaApp.Create(); // is a shorthand for `CoconaApp.CreateBuilder().Build()`

app.AddCommand("function1", () => { Console.WriteLine("Do function1 Code here"); });
app.AddCommand("function2", () => { Console.WriteLine("Do function2 Code here"); });
app.AddCommand("function3", () => { Console.WriteLine("Do function3 Code here"); });
app.AddCommand("function4", () => { Console.WriteLine("Do function4 Code here"); });

app.Run();

which is very similar to the Minimal Web Api Builder.

Uses Familiar Features

Cocona uses the standard .Net Core "Extensions.*" Libraries for Dependency Injection and Logging

using Cocona;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

var builder = CoconaApp.CreateBuilder();
builder.Services.AddSingleton<IMyService, MyService>();

var app = builder.Build();

app.AddCommand("function1", ( [Argument] string stringInput ,IMyService myService ) 
                => { myService.DoFunction1(stringInput); });
app.AddCommand("function2", ( [Argument] int numberInput ,IMyService myService) 
                => { myService.DoFunction2(numberInput); });
app.AddCommand("function3", ( [Argument] DateTime dateInput ,IMyService myService)
                => { myService.DoFunction3(dateInput); });
app.AddCommand("function4", ( [Argument] bool boolInput ,IMyService myService) 
                => { myService.DoFunction4(boolInput); });

app.Run();


public interface IMyService
{
    void DoFunction1(string input);
    void DoFunction2(int input);
    void DoFunction3(DateTime input);
    void DoFunction4(bool input);
}

public class MyService : IMyService
{
    private readonly ILogger _logger;

    public MyService(ILogger<MyService> logger)
    {
        _logger = logger;
    }
    public void DoFunction1(string input)
    {
        _logger.LogInformation(input);
    }

    public void DoFunction2(int input)
    {
        _logger.LogInformation(input.ToString());
    }

    public void DoFunction3(DateTime input)
    {
        _logger.LogInformation(input.ToLongDateString());
    }

    public void DoFunction4(bool input)
    {
        _logger.LogInformation(input.ToString());
    }
}

Cocona takes care of handing input arguments. As you can see in the Code above , each function requires an argument of a particular primative type.

If say for DoFunction3 I wanted to make the Datetime input optional, I could simply change the type to a Nullable Datetime.

app.AddCommand("function3", ( [Argument] DateTime? dateInput ,IMyService myService)

...

    public void DoFunction3(DateTime? input)
    {
        if (input.HasValue)
        {
            _logger.LogInformation(input.Value.ToLongDateString());
        }
    }

This is not restricted to primitive Types. In the documentation, there is a demo that uses the recently add record class

What is also nice is that if you try to run the Console app with no or invalid arguments. Cocona will generate Help and suggestions automatically

Cocona Help example

If you do not need or want to use the Built in dependencies. There is a Lite version of Cocona which excludes the Microsoft.Extensions.* dependencies.

Summary

I have only scratched the surface of the features here. There are a lot more features such as Sub commands, Input Validation using System.ComponentModel.DataAnnotations, Customizing the Help and Localization.

I hope you can see that Cocona can give you a great out of the box start when writing a console app.

So please go and check out Cocona for yourself and if you like it, Please consider giving the Repo a Github star.