Hello World2
August 17, 2024
Author: André Silva Gusmão

About Polyglot Notebooks¶
Polyglot Notebooks is an extension, similar to Jupyter Notebooks where you can have files (notebooks) with cells of text and cells of code. In Polyglot Notebooks you can run bash/powershell, C#, and other code by clicking in the play button next to the cell.
You might need to ctrl + shif + p and restart the kernel for this notebook to run the code cells.
I will export the .ipynb file generated by the Polyglot Notebook into HTML but the ipynb file will be available as well.
Obs: You might need to uncomment some powershell commands by removing the # used to comment the line. The character (`) is used in powershell to break a long command into multiple lines.
.NET compiling¶
The traditional way of compiling and running C# code (JIT)¶
In simple terms .NET is a framework, AKA a set of standards that have to be followed. This framework gets source code from a programming language ,usually C# (.cs files in the case of C#), and generates intermediate code called Intermediate Language (IL) or Microsoft Intermediate Language (MSIL) code, this IL/MSIL code along with their metadata is packed into a assemblies, which is either a .dll or .exe files. .exe Files: Are generated for standalone applications (e.g., console applications, Windows Forms, WPF). .dll Files: Are Generated for class libraries and reusable components. You can change which file extension will be produced in the csproj file.
DLLs can be used by multiple EXEs:
The IL/MSIL code will be interpreted and compiled just in time (JIT) into machine code for a machine-specific architecture where the program will run. This way we code and compile the CLI once and can run in any platform, and different languages can generate the CLI.
The new way of compiling and running C# code (AOT)¶
Compiling code JIT has some advantages like runtime optimizations, like when part of the code is often called during runtime (AKA a hotspot) the compiler can optimize to load that code section, which cannot be done in the Ahead of Time (AOT) Compilation process.
There is a trade-off because AOT code usually use less memory, has a faster startup, and has overall faster execution. You can use technologies like .NET Native and CoreRT to compile into Native code.
AOT Self-contained¶
As we talked in the traditional approach the C# source code (.cs file) is compiled into IL/MSIL code that is contained into assemblies (.exe or .dll files). The assemblies are compiled Just In Time (JIT) into machine code for the specific architecture of the machine that will run the program. To run the IL/MSIL code the machine has to have the .NET Common Language Runtime (CLR) installed (Behaves a lot like JVM). Like this:
The SDK (Software Development Kit) version of .NET contains everything contained in the CLR plus some features like debugging features that a person that would only run the program would not need.
The CLR also contain some libraries that are often used in the code like basic IO. We can compile C# code AOT in a self-contained unit, where the libraries from CLR are included in the compiled file. This will make the size of the file bigger since it will have the CLR libraries code, but it will make possible to run the code even in machines where the CLR is not installed. The code in the self-contained compiling process is plataform specific, once produced for an OS and architecture it can run on that platform only.
AOT Platform-specific and framework-dependent¶
You can compile your code AOT for a specific platform but require the machine that has the CLR installed.
.NET, .NET CORE, and .NET Framework¶
All are versions of the same framework, a set of rules to be followed and tools, that allow the developer and the user to create, compile and run code form a .NET compatible language (usually C#) into IL/MSIL and in the end into machine code. .NET framework is an old version of .NET that uses DLLs from the Windows Operational System, this made this version of .NET platform dependent, running only in windows machines. A new version of .NET was created that would NOT rely on Windows, it is named .NET CORE. After version 5 of .NET the term .NET is now refering to .NET CORE.
#Comments in PowerShell start with #.
#Check which version of .NET SDK you have installed (needed to develop, debug, compile, usually what devs want)
dotnet --list-sdks
6.0.321 [C:\Program Files\dotnet\sdk] 7.0.102 [C:\Program Files\dotnet\sdk] 8.0.107 [C:\Program Files\dotnet\sdk]
#Check which version of .NET RUNTIME you have installed (version used only to run the IL/MSIL code)
dotnet --list-runtimes
#Check everything together
dotnet sdk check
.NET SDKs: Version Status --------------------------------------------------- 6.0.321 .NET 6.0 is going out of support soon. 7.0.102 .NET 7.0 is out of support. 8.0.107 Up to date. Try out the newest .NET SDK features with .NET 9.0.100-preview.6.24328.19. .NET Runtimes: Name Version Status ------------------------------------------------------------------------------------- Microsoft.AspNetCore.All 2.1.30 .NET 2.1 is out of support. Microsoft.AspNetCore.App 2.1.30 .NET 2.1 is out of support. Microsoft.NETCore.App 2.1.30 .NET 2.1 is out of support. Microsoft.AspNetCore.App 6.0.13 .NET 6.0 is going out of support soon. Microsoft.NETCore.App 6.0.13 .NET 6.0 is going out of support soon. Microsoft.WindowsDesktop.App 6.0.13 .NET 6.0 is going out of support soon. Microsoft.AspNetCore.App 6.0.26 .NET 6.0 is going out of support soon. Microsoft.NETCore.App 6.0.26 .NET 6.0 is going out of support soon. Microsoft.WindowsDesktop.App 6.0.26 .NET 6.0 is going out of support soon. Microsoft.AspNetCore.App 7.0.2 .NET 7.0 is out of support. Microsoft.NETCore.App 7.0.2 .NET 7.0 is out of support. Microsoft.WindowsDesktop.App 7.0.2 .NET 7.0 is out of support. Microsoft.AspNetCore.App 8.0.7 Up to date. Microsoft.NETCore.App 8.0.7 Up to date. Microsoft.WindowsDesktop.App 8.0.7 Up to date. The latest versions of .NET can be installed from https://aka.ms/dotnet-core-download. For more information about .NET lifecycles, see https://aka.ms/dotnet-core-support.
DOTNET CLI¶
DOTNET Command Line Interface (CLI) is a tool where you can run dotnet commands that comes within the SDK.
COMMANDS STRUCTURE¶
To run DOTNET CLI commands run dotnet, command, and possibly command arguments and options.
DO YOU NEED TO LEARN DOTNET COMMANDS?¶
To be honest a lot of IDE's will run dotnet commands under the hood for you and you might never have used a command, like building a project by simply clicking in one button. Despite that, I believe knowing some commands might give you a better understanding of the whole development process and you might face a situation where you have to run commands in a no GUI environment like a CI/CD pipeline or running your server on the cloud. I would recommend trying to run the commands before going to the IDE.
-h --help¶
You can run -h or --help after a command to get more information about it, or cheching the documentation on Microsoft's website.
DOTNET NEW¶
You can open any text editor like notepad, white some code, save it with .cs extension and have your C# code ready to run, but this is not very efficient. We usually rely on templates with some boilerplate and pre-set already created for us.
DOTNET NEW STRUCTURE¶
dotnet new [TEMPLATE] [OPTIONS]
You can create your own templates, install third party templates, and search for other templates. We will use the default ones from Microsoft only for now.
DOTNET NEW CONSOLE¶
Console is a basic aplication that will open an instance of your machine console terminal, it will often close when the terminal is closed and it will often be interacted by the user using inputs in the console.
OPTIONS AND ARGUMENTS¶
WE WILL USE SOME OF OPTIONS THAT ARE OFTEN NOT USED ONLY TO SHOWCASE THEM. Most are optional, check -h to know more.
- --dry-run : Adding this will "pretend" to run the command and tell you what would be the outcome if it ran without the command, tells if error or success woudl happen as well.
- -n : Give a name for the output
- -o : Give output folder for creation
- --force : Forces the creation, even if it would change existing files
- --no-update-check : Disable checking for templates when instantiating a template
- --project
: If you have a project file .csproj file you could link your code to it - -lang : The programming language used
- --framework : The framework used
- --no-restore : Defines if skip or not the automatic restore on create
- --use-program-main : if you want to use the main method entrypoint or a top-level statement
- --aot : to allow the use of AOT when publishing the program
# To get some help information use -h or --help like this
#dotnet new -h
# To get a list of the templates you can run this command
# dotnet new templates
# DOTNET NEW CONSOLE
#dotnet new console -h
#WE WILL USE SOME OPTIONS THAT ARE OFTEN NOT USED ONLY TO SHOWCASE THEM:
dotnet new console -n myNameInArgName -o consoleAppFolder --force -lang 'C#' `
--use-program-main true --framework 'net8.0' --no-update-check --no-restore true `
#--dry-run
The template "Console App" was created successfully.
DOTNET NEW CONSOLE OUTCOME FILES¶
You might see that the folder was created and the following files were created inside this folder:
There are 2 extensions, .cs and .csproj. We will talk more about them:
.cs (C# source files)¶
Program.cs file:
About:: This is where the C# developper will write his C# code logic. In this particular example the program prints "Hello, World!" in the console.
Namespaces: In the first line we have
. Namespaces are a way to organize code structures, imagine them as folders. If a code belongs to the same namespace it can be referenced, if not, it needs to be linked first with the "using" keyword before being referenced. Namespaces can help to differenciate resources with the same name identifiers from different Namespaces. Namespaces can be nested inside other namespaces as well.
Declaring a namespace: To create a namespace we use the keyword namespace followed by the name you want to give to your namespace. What will be inside this namespace? There are 2 ways to declare the namespace:
- You can either use a file scoped namespace where you include your namespace declaration followed by ";" on the very top of a file after the using statements and the whole file will contain declarations within that namespace.
- Or you can remove the ; after the name of your namespace and include a block after. Now you can include everything you want to declare inside the namespace within that block {}.
Referencing namespaces: We include on top of the file the keyword using followed by the namespace we want to enable to be refenced by that file. It is possible to make a namespace globally available to the whole project, we include global keyword before the using keyword, it is recommended to certer your global usings either in a empty .cs file in the root or in your entrypoint file. You can have using static namespace to make it easier to reference static members of the namespace but it can get confusing, like this:
- Namespaces alias: We can use an alias to the namespace to reduce the typing when referencing them and to help disambiguing. We can do it with using aliasName = namespace, like this:
- Global Namespaces: If some code is not inside a namespace block (not between {} after declaring a namespace) it is in the global namespace and can be referenced directly from anywhere. If you want to reference anything inside the global namespace your have to use global::, but it is not recommended. E.g.
- Implicit using:: The using lets your reference and use code from other libraries. Console is a class and WriteLine a method from that class that takes a string as paramether and print it in the console. But where does Console class and this method definition come from? There is a implicit using System; which is part of the Base Class Library (BCL) which is contained in a bunch of dll files in the SDK when you install it. You can change the csproj to accept only explicit using but it might add more boilerplate to your code:
- What is a "code entrypoint": The code is interpreted tob to bottom left to right, but we have the flexibility when writing code to organize blocks of code freely (blocks of code are delimited by {}). But which block should I start reading in the project code? This is the entry point.
- Conventional aplication entry point: The compiler searches for the .cs files included in the project file for the entrypoint, which by convention is a method in a class named Main. This method can have different signatures but static void Main(string[] args) { } is the most common. Main method signatures:
- "Modern" aplication entry point (top-level statements): Inside our Main method we would have the begining of our code. Now we have something called Top-level statement that aims to reduce the boilerplate code and make C# more "modern". It is a file without classes and that is not contained explicitly in a code block. It is basically removing everything other than what you would keep inside the codeblock of a Main method and it will behave like the body of the Main method, like this:
- Default entry point file naming: You can name the file with the entrypoint anything, as long as it has an implementation of the Main method or it uses the top-level statement, but by convention we name it Program.cs.
- More about entry points:
- Using top level statements is compiled as if it’s inside an anonymous static class generated by the compiler, and therefore you cannot access things from this anonymous class.
- You can't declare methods inside your top-level statement, but you can declare a class or even a namespace and inside it you can declare a method.
- If part of your code in the top-level statement is not explicitly in a namespace it will be inside the global namespace.
- Top level statements is the new default, if you remove the option "--use-program-main true" when we created the console app via CLI or set it as false you would create a top-level statement file.
- You can only have one Main method or only one file with top level statements, otherwise you will get an error(you can work around it but it is not a good practice).
.csproj (XML file: how the project is built and what resources are included)¶
About .csproj (C# project file) (AKA msbuild file):
- When we build something in C# we commonly separate our Systems into different projects. -"So, is it like separating our code into different namespaces for organization purpose?" Yes, but there is more to it.
- Besides grouping and organizing different files the csproj file defines:
- How the project is structured and which files are included in the build process
- How the code is compiled and linked, specifying settings like the target framework (e.g., .NET 6.0), output type (e.g., executable or library), and build configurations (e.g., Debug or Release).
- Lists the external dependencies (like NuGet packages) and references to other projects or assemblies that the code references
- You can have custom actions that should occur during the build process, such as copying files, generating code, or running scripts.
Who reads the project file
- Dotnet SDK install an executable file named MsBuild.exe. This file is used when building a project in a .net language like C#, it takes a language specific project file, AKA msbuild file and calls the compiler for that language according to the configuration to generate MSIL with JIT, it calls another tool to compile this MSIL code into native code when we set the AOT option in the configuration.
- Every native .net language has its own project file, .csproj for C#, .vbproj for Visual Basic, or .fsproj for F#. The language files specified in that msbuild file will be read by the MsBuild.exe and it will compile the files described into the configuration, according to the configuration to the Intermediate Language or native code.
- MsBuild is like an orchestrator for the build process for .net.
C# compiler
- csc.exe is another file installed by the .net SDK. It is the "compiler" for C#.
- In modern applications csc.exe is a command-line tool that wraps around Roslyn. Roslyn is the actual c# and VB compiler for modern applications.
- The compiler ONLY COMPILES C# CODE INTO IL CODE. This code can either be run in any machine that contains .net CLR installed in it or another tool can be called to transform the IL directly into native code for a specific architecture.
The tags our file has
- < Project Sdk="Microsoft.NET.Sdk"> : all other tags will be inside this one. This one sets the generic sdk used for the project. The sdk used sets some tools. There are multiple sdk options like < Project Sdk="Microsoft.NET.Sdk.Web"> for building web applications, < Project Sdk="Microsoft.NET.Sdk.AzureFunctions"> for serverless functions hosted in Azure, etc. generic SDK can be used for any project but specific SDK ensures that you have the right tools for your specific application type and reduces the need for custom configurations.
- < PropertyGroup> : Defines settings that apply to the whole project.
- < OutputType>Exe</ OutputType>: Defines the type of the output being an exe or a library (.dll)
- < TargetFramework>net8.0</ TargetFramework>: Defines the target .NET framework for the project
- < ImplicitUsings>enable</ ImplicitUsings>: Removes the need to write "using" for global usings. Reducing boilerplate code.
- < Nullable>enable</ Nullable>: This makes so you cannot assign null to values types, only if you have a nullable type, like Nullable< int> or int? (both are the same). If you disable you can asign null to value types, it is recommended for new projects to let it enable.
- < PropertyGroup> : Defines settings that apply to the whole project.
- < Project Sdk="Microsoft.NET.Sdk"> : all other tags will be inside this one. This one sets the generic sdk used for the project. The sdk used sets some tools. There are multiple sdk options like < Project Sdk="Microsoft.NET.Sdk.Web"> for building web applications, < Project Sdk="Microsoft.NET.Sdk.AzureFunctions"> for serverless functions hosted in Azure, etc. generic SDK can be used for any project but specific SDK ensures that you have the right tools for your specific application type and reduces the need for custom configurations.
Some other relevant tags you might use
- < PropertyGroup> < LangVersion>:
- < ItemGroup>: Groups together items like references and files. Use separate < ItemGroup> elements for different types of items (e.g., one for NuGet packages, another for project references). Keep your < ItemGroup> organized to make it easy to manage and understand.
- < PackageReference>: Adds NuGet package dependencies.
- < ProjectReference>: References other projects within the solution.
- < Compile>: Specifies source files (.cs files) to compile.
- < Content>: Includes files in the output directory.
- < PackageReference>: Adds NuGet package dependencies. Specify version numbers explicitly to ensure consistent builds (e.g., < PackageReference Include="Newtonsoft.Json" Version="13.0.1" />). Use Version and VersionRange attributes to control package versions and dependencies.
- < ProjectReference>: References other projects within the same solution (we will talk abou solutions soon, but for now conside solution a way to pack different projects together). Use Include to specify the path to the referenced project file. Keep project references relative to the solution root to avoid path issues.
Which files are included in the project to be compiled
- In older versions of .csproj files we neede to explicitly include the files to be compiled in the < ItemGroup> < Compile> like < ItemGroup>< Compile Include="Program.cs" />.
- Now we use a reference to .cs files to include based on the files architecture. cs files in the same directory and subdirectories of the .csproj will be included automatically.
DOTNET NEW SLN¶
SLN, short for solution, is a file used to manage different projects in a single environment. It allows some integrated development environments (IDEs) and text editors to display all projects and their files for that solution. It also help manage dependencies between projects and the compile order (one project might reference code from another project, therefore the one referenced has to be compiled first). It also can define build configurations.
DO I NEED TO GO IN DEPTH ABOUT .SLN FILES?¶
PROBABLY NOT. You will probabbly edit way more a csproj file to edit your projects individually than editing a solution file. Usually we interact with the solution file via IDE or via CLI only.
THE NEW SOLUTION FILE .SLNX¶
The .slnx file serves the same purpose than the .sln file but it uses XML and is more concise.
WHY SHOULD I USE MULTIPLE PROJECTS?¶
You saw that by default when we create the simplest template app possible, a console application, a project file (.csproj) is automatically created as well. This happens because we almost always want C# files to be referenced and centralized in a .csproj file.
Why can't I have all my code in a single project?
- Separation of Concerns: Each project can represent a distinct component or layer of the application, such as data access, business logic, and presentation. We also get more modularity, where there is boundary between different components.
- Reusability and Encapsulation: A project can be used by different projects. We can create a web scraping (AKA extracting information from websites) project for instance and pack it as library (DLL) that can be used by any other project that might use this web scraping functionality. You can also encapsulate part of the library making available only resources you want and hidding internal implementations.
- Build performance: You can build only projects that changed and you can build different projects in parallel.
- Team Collaboration: Since projects are compiled into different units you can work with isolated projects without interfering with other projects someone else could be working on.
- Testing and Deployment: You can build test files to separated projects. You can also deploy one project in a powerful cloud computer because it needs a lot of computational power and keep less demanding parts of the system in another project deployed in a week machine.
- Dependency Management and Versioning: Since projects explicitly state their dependencies it is easier to manage the relationship between different parts of the application. You will have more flexibility about versioning, allowing you to version different parts (projects) within your system.
- Standards: Some organizations require this standard (separation into different projects) to be followed for the reasons above.
OPTIONS AND ARGUMENTS¶
WE WILL USE SOME OF OPTIONS THAT ARE OFTEN NOT USED ONLY TO SHOWCASE THEM. Most are optional, check -h to know more.
- --dry-run : Adding this will "pretend" to run the command and tell you what would be the outcome if it ran without the command, tells if error or success woudl happen as well.