← Back to main site

CoreUi - An app host for non-web .NET applications

January 25, 2019

ASP.NET Core introduced a new clean way of wiring MVC applications — the hosting startup assemblies. The .NET Core web applications are simply dotnet console applications with the main method as a starting point. These apps configure and launch a host. The host is responsible for app startup, dependancy injection wiring and lifetime management.

This approach is fantastically simple and extensible. Up until .NET Core 2.1, this approach was only available to web applications, leaving the console apps and .NET framework applications on their own devices. For my own console applications, I needed a way to wire up dependancy injection and take advantage of this pattern. So, I started digging up in the ASP.NET Core GitHub repo and built a generic application host library on .NET Standard 2.0. Choosing .NET Standard 2.0 means that the library can be used for .NET Framework Windows Forms and Console Applications as well as .NET Core applications.

CoreUi is built to bring ASP.NET Core dependancy injection and host builder pattern to any .NET standard application.

CoreUi can be used in console or Windows Forms applications built with .NET Framework 4.6.1+ or with .NET Core console applications.

Installation

Adding CoreUi to your application is very simple. Just add a reference to it using NuGet.

Using .NET CLI

dotnet add package Vhc.CoreUi 

Using Package Manager Console

PM> Install-Package Vhc.CoreUi

Usage

The interface IAppHost is at the heart of the pattern. We first create an app host using the AppHostBuilder. This is typically done in the entry point on the application. Similar to .NET Core, Startup class can be configured in the builder, which can be used to register various services to dependancy injection.

Simple console application

AppHostBuilder is used to prepare the application. The action passed to the Run() method is executed by the host.

Hello World

    class Program
    {
        static void Main(string[] args) =>
            new AppHostBuilder()
                .Build()
                .Run(app => Console.WriteLine("Hello World!"));
    }

Console application

Services and command-line arguments are registered at the AppHostBuilder. To use them, IAppHost app is provided by the host in the Run() lambda function.

    static void Main(string[] args)
    {
        IAppHost host = new AppHostBuilder()
            .UseArguments(args)                                             // Register command line arguments
            .ConfigureServices(s => s.AddSingleton<IDemo, Demo>() )         // Register service
            .Build();

        host.Run(app =>
        {
            var demo = app.Services.GetService<IDemo>();                    // Get registered service 
            app.Arguments.ToList().ForEach(arg => Console.WriteLine(arg));  // Use command line arguments
            Console.ReadKey();
        });
    }

Using a Startup class

Implement interface IStartup from Vhc.CoreUi.Abstractions from your startup class, and register the startup class in AppHostBuilder instance.

Startup.cs

    class Startup : IStartup
    {
        // Register the configuration files
        public void Configure(IConfigurationBuilder config)
        {
            config.AddJsonFile("appsettings.json", optional: true);
        }
        
        // Register services for dependancy injection
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddTransient<IFoo, Foo>();
            services.AddSingleton<Bar>();
        }
    
        // Start point of the application, this is called by Run() method of the application host
        public void Start(IAppHost app)
        {
            var foo = app.Services.GetService<IFoo>();
            Console.WriteLine(foo.ToString());
        }
    }

Program.cs

    static void Main(string[] args)
    {
        new AppHostBuilder()
            .UseStartup<Startup>()
            .Build()
            .Run();
    }

As the ASP.NET Core ServiceCollection used in ConfigureServices, you can use any suitable library here. For example, Sqlite can be used alongwith Entity Framework Core. All the .NET Standard 2.0 libraries that provide an extension method for IServiceCollection work here.

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<MyDbContext>(options =>
        options.UseSqlite(Constants.ConnectionString));
    ...
}

Running Asynchronously

Starting from C# 7.1, Main() method can be made asynchronous and the whole application can be run in async manner. IAppHost can take advantage of this with RunAsync() method.

async static void Main(string[] args)
{
    await new AppHostBuilder()
        .Build()
        .RunAsync(async (app, token) =>
        {
            if(!token.IsCancellationRequested)
                await Task.Run(() => Console.WriteLine("Running Task"));
        });
}

Running AWS Lambda function

Function.cs

    public class Function
    {
        public void FunctionHandler(Request payload, ILambdaContext context)
        {
            new AppHostBuilder()
               .ConfigureServices(services =>
               {
                   services.AddSingleton<ILambdaContext>(context);  // Register the context to be available everywhere
                   services.AddSingleton<Request>(payload);
               })
               .UseStartup<Startup>()
               .Build()
               .Run();
        }
    }

CoreUi is open-source and available on GitHub.

UPDATE: Since ASP.NET Core 2.1, Microsoft added a new generic app host builder HostBuilder which is very similar in idea (albeit, much powerful and hence a little more complex) and can be used for non-web .NET core applications instead of CoreUi.


{author}

Written by
Vibhav Churi