In this article, we will learn how to set the exit code for a console application in .NET.
Let’s dive in.
What Are Exit Codes
Exit codes are integer values we return after executing a process.
A zero exit code usually indicates success, while a non-zero code indicates an error. For a complete list of possible error codes returned by Windows desktop apps visit system error codes.
The exit codes are useful because they give us feedback on a program’s execution. This is extremely helpful in automated processes.
In automated use cases, we use those codes to allow the parent processes to know the state of the child processes. Another common scenario is to combine error handling to control the exit codes and finish the processes gracefully with logging to get more details during debugging and troubleshooting.
Setting the Exit Code in .NET
In .NET, we have multiple ways to set the exit code.
We can accomplish this by changing the Main()
method’s return type from void to int and then returning the exit code.
Let’s see an example:
static int Main() { return 1; }
Here, we set 1 as the exit code, which indicates an error.
Alternatively, we can set the exit code using a void Main()
method.
For this approach, we will set the property of Environment.ExitCode
in the Program
class:
Environment.ExitCode = 1;
Alternatively, we can use the method Environment.Exit()
, which terminates a process and returns the exit code to the operating system:
Environment.Exit(1);
Let’s take note to avoid combining the return type and Environment.Exit()
approaches, as the Environment.Exit()
method takes precedence, even if executed first:
static int Main(string[] args) { Environment.Exit(1); return 0; }
Reading the Exit Code
Operating systems provide ways to get the exit code from processes.
In Windows, from the command line, we can use the environment variable %ERRORLEVEL%
to read the exit code from the executed program:
ExitCodesInDotNet.exe echo %ERRORLEVEL%
In GNU/Linux-based and Unix-like systems, we can use $?
:
./ExitCodesInDotNet.exe echo $?
Alternatively, we can programmatically start a process and read its exit code:
var startInfo = new ProcessStartInfo() { FileName = "ping", Arguments = "256.256.256.256" }; using (Process process = Process.Start(startInfo)) { process.WaitForExit(); int exitCode = process.ExitCode; Console.WriteLine($"Exit code: {exitCode}"); if (exitCode != 0) { exitCode = 1; } Environment.Exit(exitCode); }
Here, we start a process for the ping
command, write the exit code to the console, and then finally return the exit code.
We pinged an invalid IP Address, which caused the command to fail, and then we returned the exit code 1 to complete the process.
Cross-Platform Considerations
In Windows, exit codes are represented by 32-bit integers, representing positive and negative numbers from -2,147,483,648 to 2,147,483,647.
In GNU/Linux-based and Unix-like systems, exit codes usually represent unsigned 8-bit integers, representing only positive numbers from 0 to 255.
It’s important to graciously handle the exceptions using the Main()
method so we can control the exit codes. Otherwise, unhandled exceptions can produce unpredictable or different exit codes:
throw new NotImplementedException();
Here, as we throw a NotImplementedException()
, the exit code in Windows is -532462766, while on Ubuntu, it’s 82.
If we want to support GNU/Linux-based and Unix-like systems, like Ubuntu, it’s important to avoid using exit codes higher than 255 as they get translated and, as such, hide potential errors:
Environment.Exit(256);
Here, if we execute this method on a GNU/Linux-based or Unix-like system, like Ubuntu, the exit code would be 0.
Conclusion
In this article, we have looked into setting up and reading exit codes. We have also looked at the importance of considering the choice of exit codes suitable for cross-platform operating systems.
Generally, exit codes are crucial to programming, and we use them to indicate whether a program ran successfully.
When we develop a console application, it’s helpful to follow some common practices, such as returning 0 when there are no errors and documenting the exit codes to ensure other developers know what to expect.
If there are cross-platform requirements, it would be important to use exit codes supported in both operating systems.