You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Fix open issues on the file-based apps tutorial (#50568)
* Fix duplicate snippet tags
* General edit pass
Also, add a link to the (in progress) SDK reference article for file-based apps.
* Respond to feedback.
* Remove incomplete `#:` list
Remove the incomplete list of `#:` preprocessor tags from this reference. Instead link to the new SDK reference article.
Copy file name to clipboardExpand all lines: docs/csharp/fundamentals/tutorials/file-based-programs.md
+26-25Lines changed: 26 additions & 25 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,15 +1,15 @@
1
1
---
2
2
title: Build file-based apps
3
3
description: File-based apps are command line utilities that are built and execute without a project file. The build and run commands are implicit. New syntax supports project settings in source.
4
-
ms.date: 08/14/2025
4
+
ms.date: 12/12/2025
5
5
ms.topic: tutorial
6
6
ai-usage: ai-assisted
7
7
#customer intent: As a developer, I want to build utilities so that more work is automated.
8
8
---
9
9
10
10
# Tutorial: Build file-based C# programs
11
11
12
-
*File-based apps* are programs contained within a single `*.cs` file that are built and run without a corresponding project (`*.csproj`) file. File-based apps are ideal for learning C# because they have less complexity: The entire program is stored in a single file. File-based apps are also useful for building command line utilities. On Unix platforms, file-based apps can be run using `#!` (shebang) [directives](../../language-reference/preprocessor-directives.md).
12
+
*File-based apps* are programs contained within a single `*.cs` file that you build and run without a corresponding project (`*.csproj`) file. File-based apps are ideal for learning C# because they have less complexity: The entire program is stored in a single file. File-based apps are also useful for building command line utilities. On Unix platforms, you can run file-based apps by using `#!` (shebang) [directives](../../language-reference/preprocessor-directives.md).
13
13
In this tutorial, you:
14
14
15
15
> [!div class="checklist"]
@@ -23,7 +23,7 @@ In this tutorial, you:
23
23
> * Use parsed command line results.
24
24
> * Test the final application.
25
25
26
-
You build a file-based program that writes text as ASCII art. The app is contained in a single file, uses NuGet packages that implement some of the core features.
26
+
You build a file-based program that writes text as ASCII art. The app is contained in a single file, uses NuGet packages, and implements core features.
27
27
28
28
## Prerequisites
29
29
@@ -45,31 +45,31 @@ You build a file-based program that writes text as ASCII art. The app is contain
45
45
dotnet run AsciiArt.cs
46
46
```
47
47
48
-
The first time you run this program, the `dotnet` host builds the executable from your source file, stores build artifacts in a temporary folder, then runs the created executable. You can verify this experience by typing `dotnet run AsciiArt.cs` again. This time, the `dotnet` host determines that the executable is current, and runs the executable without building it again. You don't see any build output.
48
+
The first time you run this program, the `dotnet` host builds the executable from your source file, stores build artifacts in a temporary folder, and then runs the created executable. You can verify this experience by typing `dotnet run AsciiArt.cs` again. This time, the `dotnet` host determines that the executable is current and runs the executable without building it again. You don't see any build output.
49
49
50
-
The preceding steps demonstrate that file-based apps aren't script files. They're C# source files that are built using a generated project file in a temporary folder. One of the lines of output displayed when you built the program should look something like this (on Windows):
50
+
The preceding steps demonstrate that file-based apps aren't script files. They're C# source files that the `dotnet` host builds by using a generated project file in a temporary folder. One of the lines of output displayed when you build the program should look something like this (on Windows):
That output tells you where the temporary files and build outputs are placed. Throughout this tutorial, anytime you edit the source file, the `dotnet` host updates the executable before it runs.
63
63
64
-
File-based apps are regular C# programs. The only limitation is that they must be written in one source file. You can use top-level statements or a classic `Main` method as an entry point. You can declare any types: classes, interfaces, and structs. You can structure the algorithms in a file-based program the same as you would in any C# program. You can even declare multiple namespaces to organize your code. If you find a file-based program is growing too large for a single file, you can convert it to a projectbased program and split the source into multiple files. File-based apps are a great prototyping tool. You can start experimenting with minimal overhead to prove concepts and build algorithms.
64
+
File-based apps are regular C# programs. The only limitation is that you must write them in one source file. You can use top-level statements or a classic `Main` method as an entry point. You can declare any types: classes, interfaces, and structs. You can structure the algorithms in a file-based program the same as you would in any C# program. You can even declare multiple namespaces to organize your code. If you find a file-based program is growing too large for a single file, you can convert it to a project-based program and split the source into multiple files. File-based apps are a great prototyping tool. You can start experimenting with minimal overhead to prove concepts and build algorithms.
65
65
66
66
## Unix shebang (`#!`) support
67
67
68
68
> [!NOTE]
69
69
>
70
-
> Support for `#!` directives applies on unix platforms only. There isn't a similar directive for Windows to directly execute a C# program. On Windows, you must use `dotnet run` on the command line.
70
+
> Support for `#!` directives applies on Unix platforms only. There's no similar directive for Windows to directly execute a C# program. On Windows, you must use `dotnet run` on the command line.
71
71
72
-
On unix, you can run file-based apps directly, typing the source file name on the command line instead of `dotnet run`. You need to make two changes:
72
+
On Unix, you can run file-based apps directly. Instead of using `dotnet run`, you type the source file name on the command line. You need to make two changes:
73
73
74
74
1. Set *execute* permissions on the source file:
75
75
@@ -83,7 +83,7 @@ On unix, you can run file-based apps directly, typing the source file name on th
83
83
#!/usr/local/share/dotnet/dotnet run
84
84
```
85
85
86
-
The location of `dotnet` can be different on different unix installations. Use the command `which dotnet` to locate the `dotnet` host in your environment.
86
+
The location of `dotnet` can be different on different Unix installations. Use the command `which dotnet` to locate the `dotnet` host in your environment.
87
87
88
88
Alternatively, you can use `#!/usr/bin/env dotnet` to resolve the dotnet path from the PATH environment variable automatically:
89
89
@@ -123,13 +123,13 @@ Now, write all arguments on the command line to the output.
123
123
124
124
This version demonstrates these new concepts:
125
125
126
-
- The command line arguments are passed to the program using the predefined variable `args`. The `args` variable is an array of strings: `string[]`. If the length of `args` is 0, that means no arguments were provided. Otherwise, each word on the argument list is stored in the corresponding entry in the array.
126
+
- The predefined variable `args` passes the command line arguments to the program. The `args` variable is an array of strings: `string[]`. If the length of `args` is 0, no arguments were provided. Otherwise, each word on the argument list is stored in the corresponding entry in the array.
127
127
- The [`string.Join`](xref:System.String.Join*) method joins multiple strings into a single string, with the specified separator. In this case, the separator is a single space.
128
128
-<xref:System.Console.WriteLine*?displayProperty=nameWithType> writes the string to the standard output console, followed by a new line.
129
129
130
130
## Handle standard input
131
131
132
-
That handles command line arguments correctly. Now, add the code to handle reading input from standard input (`stdin`) instead of command line arguments.
132
+
The preceding code handles command line arguments correctly. Now, add the code to handle reading input from standard input (`stdin`) instead of command line arguments.
133
133
134
134
1. Add the following `else` clause to the `if` statement you added in the preceding code:
135
135
@@ -153,25 +153,25 @@ That handles command line arguments correctly. Now, add the code to handle readi
153
153
154
154
1. Run the program again.
155
155
156
-
With bash:
156
+
By using bash:
157
157
158
158
```bash
159
159
cat input.txt | dotnet run AsciiArt.cs
160
160
```
161
161
162
-
Or, with PowerShell:
162
+
Or, by using PowerShell:
163
163
164
164
```powershell
165
165
Get-Content input.txt | dotnet run AsciiArt.cs
166
166
```
167
167
168
168
Now your program can accept either command line arguments or standard input.
169
169
170
-
## Write ASCII Art output
170
+
## Write ASCII art output
171
171
172
-
Next, add a package that supports ASCII art, [Colorful.Console](https://www.nuget.org/packages/Colorful.Console). To add a package to a file-based program, you use the `#:package` directive.
172
+
Next, add a package that supports ASCII art, [Colorful.Console](https://www.nuget.org/packages/Colorful.Console). To add a package to a file-based program, use the `#:package` directive.
173
173
174
-
1. Add the following directive after the `#!` directive in your AsciiArt.cs file:
174
+
1. Add the following directive after the `#!` directive in your `AsciiArt.cs` file:
1. Run the program, and you see ASCII art output instead of echoed text.
185
+
1. Run the program. You see ASCII art output instead of echoed text.
186
186
187
187
## Process command options
188
188
189
-
Next, let's add command line parsing. The current version writes each word as a different line of output. The command line arguments you added support two features:
189
+
Next, add command line parsing. The current version writes each word as a different line of output. The command line arguments you add support two features:
190
190
191
191
1. Quote multiple words that should be written on one line:
192
192
@@ -200,9 +200,9 @@ Next, let's add command line parsing. The current version writes each word as a
200
200
AsciiArt.cs --delay 1000
201
201
```
202
202
203
-
Users should be able to use both arguments together.
203
+
Users can use both arguments together.
204
204
205
-
Most command line applications need to parse command line arguments to handle options, commands, and user input effectively. The [`System.CommandLine` library](../../../standard/commandline/index.md) provides comprehensive capabilities to handle commands, subcommands, options, and arguments, allowing you to concentrate on what your application does rather than the mechanics of parsing command line input.
205
+
Most command line applications need to parse command line arguments to handle options, commands, and user input effectively. The [`System.CommandLine` library](../../../standard/commandline/index.md) provides comprehensive capabilities to handle commands, subcommands, options, and arguments. You can concentrate on what your application does rather than the mechanics of parsing command line input.
206
206
207
207
The `System.CommandLine` library offers several key benefits:
208
208
@@ -238,7 +238,7 @@ The `System.CommandLine` library offers several key benefits:
The preceding code validates all command line arguments. If the validation fails, errors are written to the console, and the app exits.
241
+
The preceding code validates all command line arguments. If the validation fails, the app writes errors to the console and exits.
242
242
243
243
## Use parsed command line results
244
244
@@ -254,9 +254,9 @@ Now, finish the app to use the parsed options and write the output. First, defin
254
254
255
255
1. Create a local function to write the ASCII art with the specified delay. This function writes each message in the record with the specified delay between each message:
In this tutorial, you learned to build a file-based program, where you build the program in a single C# file. These programs don't use a project file, and can use the `#!` directive on unix systems. Learners can create these programs after trying our [online tutorials](../../tour-of-csharp/tutorials/hello-world.md) and before building larger project-based apps. File-based apps are also a great platform for command line utilities.
271
+
In this tutorial, you learned to build a file-based program, where you build the program in a single C# file. These programs don't use a project file, and can use the `#!` directive on Unix systems. Learners can create these programs after trying our [online tutorials](../../tour-of-csharp/tutorials/hello-world.md) and before building larger project-based apps. File-based apps are also a great platform for command line utilities.
Copy file name to clipboardExpand all lines: docs/csharp/language-reference/preprocessor-directives.md
+3-65Lines changed: 3 additions & 65 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -21,9 +21,7 @@ f1_keywords:
21
21
- "#pragma checksum"
22
22
- "defaultline_CSharpKeyword"
23
23
- "#!"
24
-
- "#:sdk"
25
-
- "#:property"
26
-
- "#:package"
24
+
- "#:"
27
25
helpviewer_keywords:
28
26
- "preprocessor directives [C#]"
29
27
- "keywords [C#], preprocessor directives"
@@ -62,69 +60,9 @@ Console.WriteLine("Hello");
62
60
63
61
The preceding code snippet informs a Unix shell to execute the file using `dotnet run`. The `/usr/bin/env` command locates the `dotnet` executable in your PATH, making this approach portable across different Unix and macOS distributions. The `#!` line must be the first line in the file, and the following tokens are the program to run. You need to enable the *execute* (`x`) permission on the C# file for that feature.
64
62
65
-
The `#:` directives that are used in file-based apps include:
66
-
67
-
-`#:sdk`:
68
-
69
-
The first instance specifies the value for the `<Project Sdk="value" />` node. Subsequent instances specify the `<Sdk Name="value" Version="version" />` node. The version can be omitted (i.e. if specified in global.json or included in .NET SDK). For example:
70
-
71
-
```csharp
72
-
#:sdk Microsoft.NET.Sdk.Web
73
-
#:sdk Aspire.AppHost.Sdk@9.4.1
74
-
```
75
-
76
-
The two preceding preprocessors is translated into:
77
-
78
-
```xml
79
-
<ProjectSdk="Microsoft.NET.Sdk.Web" />
80
-
<SdkName="Aspire.AppHost.Sdk"Version="9.4.1" />
81
-
```
82
-
83
-
-`#:property`:
84
-
85
-
Instances of `#:property` are translated into property elements in a `<PropertyGroup>`. A token of the form `Name=value` must follow the `property` token. The following example directives are valid `property` tokens:
86
-
87
-
```csharp
88
-
#:property TargetFramework=net11.0
89
-
#:property LangVersion=preview
90
-
```
91
-
92
-
The preceding two properties are translated into:
93
-
94
-
```xml
95
-
<TargetFramework>net11.0</TargetFramework>
96
-
<LangVersion>preview</LangVersion>
97
-
```
98
-
99
-
-`#:package`:
100
-
101
-
Instances of `#:package` are translated into `PackageReference` elements to include NuGet packages with the specified version to your file. For example:
102
-
103
-
```csharp
104
-
#:package System.CommandLine@2.0.0-*
105
-
```
106
-
107
-
The preceding preprocessor token is translated into:
0 commit comments