Top Level Statements and Dependency Injection in .NET 5.0

Exploring Top Level statements in .NET 5 and manually setting up and using dependency injection with the Microsoft container.

Published on 05 January 2021

Introduction

As part of the .NET 5 release one of the added features was to add "Top Level" statements. This removed the ceremony of adding a program class with a main method for a simple console application. To be honest when they were first announced I didn't really see the point. However as we will see through this post removing a lot of boilerplate code and ceremony allows us to get to the core coding which could be very handy for learning C#.

Another concept that Top Level statements initially removes is the concept of namespaces. There is no program class so there is no default namespace for it to be in. It is another concept that new developers to the C# language will need to learn at some point but aren't forced to straight away.

In this post I will walk through how to setup a Top Level statement program with basic dependency injection setup.

Walkthrough

New Console Application

First off you will need to create a new .NET 5 console application. This can be done either on the command line or through the new project wizard in Visual Studio 2019. This will generate the default Program.cs file. Once opened in your editor of choice all the contents of this file can be removed.

Nuget Packages

To work with dependency injection a nuget package will need to be referenced. The package required is Microsoft.Extensions.DependencyInjection and will need to be referenced in the csproj file.

This can be added on the command line with the following command:

dotnet add package Microsoft.Extensions.DependencyInjection --version 5.0.1

Register Services

Now we have the nuget references we require we can start registering the services for our dependency tree.

First need to add a using statement to bring in the Microsoft dependency injection namespace.

using Microsoft.Extensions.DependencyInjection;

This example is specifically simple to show the concepts and using dependency injection for this one demo service is overkill however this is more of an example of what you could do to show setting up DI.

var services = new ServiceCollection();
services.AddTransient<ISayHello, SayHello>();
var sp = services.BuildServiceProvider();

The above code adds a transient service registration to the service collection. This uses the standard extension methods for service registration you will find in a standard ASPNET Web Application/Web Api project. Once all the dependencies are registered a service provider needs to be created to allow for requesting a fully formed service and it's dependencies. In this example the SayHello service does not have any dependencies but if it did they would also need to be registered before the service provider was built.

Full Implementation

As you can see from the example below there isn't much to it. The full example including service and interface is 18 lines long including the empty lines for formatting!

using Microsoft.Extensions.DependencyInjection;

var services = new ServiceCollection();
services.AddTransient<ISayHello, SayHello>();
var sp = services.BuildServiceProvider();

var sayHello = sp.GetRequiredService<ISayHello>();
sayHello.Say();

public class SayHello : ISayHello
{
    public void Say() => System.Console.WriteLine($"Hello World from {nameof(SayHello)}");
}

public interface ISayHello
{
    void Say();
}

Conclusion

As you can see from this basic example setting up and using the basic Microsoft container is relatively straight forward and then can be used in console applications etc. You have full control over which services and dependencies are registered however unlike ASPNET Core and the HostBuilder usages you don't get certain items "for free" eg. Logging and Configuration, and you will need to reference the specific nuget packages and add the service registrations yourself to use this functionality.

As for Top Level statements I can see there is a time and place for them but I don't believe they are applicable for enterprise software at the moment although happy to be proved wrong. What they are ideal for is examples and learning paths to reduce the cognative load of concepts for new developers. I will be using them for blog examples and testing things more in the future that is for sure!

What are your thoughts on using Dependency Injection in Top Level statements in .NET 5?

Any questions/comments then please contact me on Twitter @WestDiscGolf