Dev.to WebDev πŸ›  Dev πŸ‘ 0 πŸ“– 5 min read

What Really Happens When You Run `dotnet run`?

πŸ‡§πŸ‡· Prefer reading in Portuguese? Read the Brazilian Portuguese version. If you work with .NET, you've probably typed this command countless times: dotnet run And a few seconds later, your application is runnin

What Really Happens When You Run `dotnet run`?

πŸ‡§πŸ‡· Prefer reading in Portuguese? Read the Brazilian Portuguese version.

If you work with .NET, you've probably typed this command countless times:

dotnet run

And a few seconds later, your application is running. Simple as that.

But what actually happened between pressing Enter and your application starting to run?

Who found the project? Who compiled the C# code? What gets generated during compilation? Can the processor execute C# directly? And where do the SDK, Runtime, and CLR fit into all of this?

Trying to answer these questions is exactly why I chose this topic for the first day of my 30 Days of .NET challenge.

So let's follow the journey of a dotnet run, from the terminal all the way to application execution.

You type dotnet run in the terminal

The first piece we encounter is the .NET CLI (Command-Line Interface).

But what exactly is a CLI?

A CLI is an interface that allows us to interact with a program through written commands. So no, the CLI isn't exactly that "black screen" we call the terminal. The terminal is the program we use to type commands, while the .NET CLI is the tool that receives and interprets commands like dotnet run.

On Windows, for example, we can use the .NET CLI through PowerShell, Command Prompt, or Windows Terminal. On Linux and macOS, we can use it through their respective terminals.

When we install the .NET SDK, we get access to the dotnet command, which serves as the entry point for several tools in the platform:

dotnet new       # creates a new project from a template
dotnet restore   # restores project dependencies
dotnet build     # builds the project
dotnet test      # runs tests
dotnet run       # builds and runs the application
dotnet publish   # prepares the application for distribution

When we execute dotnet run, we're basically saying: find my project, prepare it for execution, and run it.

But the CLI didn't magically appear on our machine. It came along with another important piece: the .NET SDK.

The SDK - Software Development Kit

The SDK brings together the tools we developers need to build our .NET applications. Think of it as a toolbox with a hammer and a screwdriver, except the SDK comes with the CLI, build tools, compilers, libraries, and other components needed to build our applications.

Because of all these tools, when we're developing an application, we need to make sure the SDK is installed. We can check which SDKs are installed using:

dotnet --list-sdks

Terminal showing the output of the dotnet --list-sdks command

So, when we execute dotnet run, we're using the tools provided by the SDK to prepare our application.

Our C# code needs to be compiled, right?

Our processor has absolutely no idea what to do with a random line like this:

Console.WriteLine("Help, I don't understand");

After writing our C# code and before executing it, it needs to go through a compilation process.

In simple terms, compiling means transforming the code we write into a representation that can move on to the next stages of execution. In C#, the compiler transforms our code into IL (Intermediate Language) and includes metadata about our code.

IL is an intermediate language. In other words, at this point, we're still not speaking the "machine language" that the processor can execute.

This is where we start moving away from the SDK's territory and into the actual execution process of our application.

.NET Runtime

The .NET Runtime is the set of components required to execute a .NET application after it has been compiled.

It includes components such as the CLR, fundamental .NET libraries, and other files needed to run an application.

That's why the SDK and Runtime have different purposes. If we're developing an application, we need the tools provided by the SDK. But if we only want to run an application, depending on how it was published, we might only need the Runtime.

We can check which runtimes are installed on our machine using:

dotnet --list-runtimes

Terminal showing the output of the dotnet --list-runtimes command

When our application starts executing, the Runtime provides the environment needed for the IL we generated earlier to finally run.

And one of the most important pieces of this process is the CLR.

CLR - Common Language Runtime

The CLR (Common Language Runtime) is the environment responsible for executing managed .NET code.

But it doesn't just "run the code". During execution, the CLR takes care of several other things for us. When we create objects in our code, for example, we need memory to store them. The CLR participates in memory management, and the Garbage Collector identifies objects that are no longer being used so their memory can be reclaimed.

It also provides other services that we constantly use without having to implement everything manually, such as:

  • memory management;
  • exception handling;
  • thread management;
  • type safety.

During traditional execution, another important component comes into play: the JIT β€” Just-In-Time compiler.

It transforms IL (the Intermediate Language we talked about earlier) into machine code that the processor can actually execute.

And here's something really important about .NET: it's cross-platform!

Description of .NET on Microsoft's website

The IL generated during compilation is an intermediate representation and isn't directly tied to the instructions of a specific CPU. When the application runs, the Runtime for that platform handles execution, and the JIT generates machine code appropriate for the processor's architecture.

The same .NET code can run on Windows, Linux, and macOS, as long as .NET supports that operating system and architecture.

Putting it all together

Now we can see the entire journey:

All of this started with a single two-word command, probably one of the most frequently used:

dotnet run

So what's the difference between SDK, CLI, Runtime, and CLR?

After following the command's journey, these definitions become much less abstract. Here's a quick summary to keep in your memory (yours, not your computer's).

Term In a tweet
SDK A set of tools we use to develop .NET applications.
CLI A command-line interface that gives us access to various .NET tools.
Runtime A set of components required to execute a .NET application.
CLR The execution environment for managed code.
IL The intermediate language generated when C# code is compiled.
JIT A compiler that transforms IL into machine code.

So instead of memorizing four separate definitions, we can think of them as pieces that come into play at different stages of our application's lifecycle.

And the next time I type dotnet run, I'll know just how much is happening behind that simple command.

References

πŸ“° Read the original article on Dev.to WebDev

Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes β€” full credit and traffic to the original publisher.