C# args without a main method? - c#

I am new to the C# world but have seen other programming languages give access to command-line arguments from places like main function/method, sys.argv, etc.
It was unusual to see the following statement placed globally in the boilerplate ASP.NET Core Web App MVC (Version 6.0) Program.cs file of Visual Studio:
var builder = WebApplication.CreateBuilder(args);
Hovering over that parameter inside my IDE does seem to suggest it is indeed string[] args, but where is the entry point?

I hope someone brings in further interesting details, but as a minimum, a bit of searching yielded the following result (short answer — Top-level Statements) from Microsoft Docs:
Starting in C# 9, you can omit the Main method, and write C# statements as if they were in the Main method [...] For information about how to write application code with an implicit entry point method, see Top-level statements.
The page covering top-level statements makes it more clear:
args
Top-level statements can reference the args variable to access any command-line arguments that were entered. The args variable is never null but its Length is zero if no command-line arguments were provided.

Related

How to see boilerplate code for top-level statements in C#?

I'm going through this C# intro tutorial by MS, and in the section "Fix the "format" error" I'm supposed to delete code in the namespace, but I'm not seeing that namespace since I'm in the "top-level statements" mode. How do I reveal the boilerplate code that is underneath?
As described by Top-level statements - programs without Main methods:
Starting in C# 9, you don't have to explicitly include a Main method in a console application project. Instead, you can use the top-level statements feature to minimize the code you have to write. In this case, the compiler generates a class and Main method entry point for the application.
Here's a Program.cs file that is a complete C# program in C# 10:
Console.WriteLine("Hello World!");
Top-level statements let you write simple programs for small utilities such as Azure Functions and GitHub Actions. They also make it simpler for new C# programmers to get started learning and writing code.
This means that the Top-Level statements is a feature of a comiler, not of the editor. The Main method and the class (things you call "boilerplate") are not present in the source code - they are generated by the compiler.
Adding to the above answer is its Compiler feature.
The compiler generates a method to serve as the program entry point
for a project with top-level statements. The name of this method isn't
actually Main, it's an implementation detail that your code can't
reference directly. The signature of the method depends on whether the
top-level statements contain the await keyword or the return
statement.
The following table shows what the method signature would look like, using the method name Main in the table for convenience.
Reference:
https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/program-structure/top-level-statements#implicit-entry-point-method
Whoever updated the tutorial to .NET 6 with top-level statements (see the commit) forgot to update the part in question. To see the full previous version of the code you can switch tutorial to VS 2019 version either by using dropdown at the top of table of contents:
Or just by following this link.
The previous version also should work, you should be able to replace the contents of your Program.cs file with code from this section and proceed with tutorial from here.

Can you block a method in mvc library (or really on any class)

We have a project that uses multiple domains (with tenants) and when we need to generate an absolute url we used to do this:
var forgotUrl = Url.Action("Forgot", "Account", null, this.Request.Url.Scheme);
That worked well, and sometimes you need absolute urls when for instance sending out emails with reset password links.
However, we have now implemented SSL with reverse proxy, meaning that this.Request.Url.Scheme no longer gives us the correct domain.
Therefore we have to do something like this instead
var forgotUrl = CurrentHostWithSchemeWithoutTrailingSlash + Url.Action("Forgot", "Account");
To simplify we have made an extension method, like so
Url.AbsoluteAction("Forgot", "Account", *data*)
And that all works like expected, so everything is well, however, you can still mess upp by writing a line calling the original Url.Action and sending in this.Request.Url.Scheme.
So my question is simply: Is there any way of blocking usage of that, either hiding it, or giving compiler errors, warnings, anything?
For general case where the method is class member your real option is to find usages and update code. You can either manually find all the cases of such functions with "find all usages" (VS or VS+R#) from time to time or use automated tools. If you use VS 2015+ see Finding all references to a method with Roslyn. For older versions or build tests you can scan code e.g. by adding unit test that will load assembly, parse IL and assert wrong methods.
For this particular case Since Url.Action is extension method - additional option is to create another extension method with the same signature in another static class that is visible by default in the view (e.g. namespace System; public static class MyHack{ ...Action(UrlHelper...) so compiler will find 2 variants of the method and show an error.
Also educating developers (i.e. during code reviews) and available existing code is often enough. If there is already existing example in the project that does this correctly there is good chance that it will be simply copy-pasted.

Getting first executing assembly returns null

I'm trying to get the first executing assembly using the following code:
AssemblyName entryAssembly = Assembly.GetEntryAssembly().GetName();
I'm getting a null exception though. The GetExecutingAssembly() and GetCallingAssembly() functions do return values though. In the documentation, it mentions that it can return null when called from unmanaged code. I don't think my code falls into this category.
I'm running a ASP.NET MVC 2 application in Visual Studio using the Visual Studio Development Server.
Any ideas why I'm getting a null?
This is by design. Quote from Gendarme (note: I'm quoting myself):
This rule warns when an assembly without an entry point (i.e. a dll or
library) calls Assembly.GetEntryAssembly (). This call is problematic
since it will always return null when called from outside the root
(main) application domain. This may become a problem inside libraries
that can be used, for example, inside ASP.NET applications.
from https://github.com/spouliot/gendarme/wiki/Gendarme.Rules.BadPractice.GetEntryAssemblyMayReturnNullRule%282.10%29
Edit: the above answer the 'why' (your stated question). A possible workaround it to create a StackTrace and iterate each StackFrame until the top to see from which assembly it comes from. However this will only work, like you wish, when done from the main (web) application thread (i.e. take great care on where this is called from).

if __name__ == "__main__": equivalent in C#

With python, I can use if __name__ == "__main__": for using the module both as a library and a program.
Can I mimic this feature in C#?
I see a class in C# can have a 'static void Main()', but I'm not sure if every class can have a Main() without a problem.
ADDED
/m:CLASS_NAME is a way to specify the class to run the Main().
You can put a Main method in as many classes as you like, although only one can be an entry point for an application. (For talks, I often have a main method in every class, and use a helper library to present all of those pseudo-entry-points when I run the project.)
Likewise you can definitely add a reference to a .exe assembly and treat it like a library. For example, you could make a unit testing assembly work like a class library in most cases, but also write a main method so that you could just run it to execute the tests without a GUI or whatever.
You can compile a C# project as a program (executable) with a Main() method, and you'd still be able to use it as a library. No special syntax required.
You could add a Main() method to every class, but I doubt it's useful.
.NET applications usually have different structures than Python ones; trying to fit the same programming model is unlikely to get you good results.
C# project files specify a startup object when multiple entry points are available.
See this article for more info.

main() in C, C++, Java, C#

Is main() (or Main()) in C, C++, Java or C#, a user-defined function or a built-in function?
It's a user-defined function that is necessary for a program to execute. When you go to run your program in the compiled language, the main function is what is executed. For instance, in Java, if you have a function of the signature public static void main(String ... args) in a class then that class can be executed, as the JVM will execute the contents of that main method.
Example in Java:
public class Test {
public static void main(String ... args) {
System.out.println("Hello World");
}
}
...
javac Test.java
...
java Test
Results in "Hello World" being printed to the console.
I'm not sure what you mean by built-in vs. user defined. Almost no language actually gives your user-defined function the privilege of being the true entry-point into the program. C++, any .NET language, and Java all have hidden (built-in) entry point methods that in turn call your user-defined Main method (or whatever the entrypoint method for that language is called -- in .NET it can be named anything, although C# and VB.NET force it to be called Main).
So yes, virtually every language has a concept of a method that is automatically called, and this method is a user-defined method and usually mandatory. But virtually every language also has a built-in entry point method that actually sets up the framework and/or memory management for the process before invoking your user-defined "entry-point" function.
Quote from the C Standard (emphasis is mine):
5.1.2.1 Freestanding environment
In a freestanding environment (in
which C program execution may take
place without any benefit of an
operating system), the name and
type of the function called at
program startup are
implementation-defined. Any
library facilities available to a
freestanding program, other than the
minimal set required by clause 4,
are implementation-defined.
main(), in a freestanding environment, is very much a user-defined function.
It's a required user defined function (the entry point for executables)...
It is not "built-in" in any language, in a sense that there is no standard implemented-for you main() avialable.
For C/C++/Java, it is a function with a special property, namely, the function that will be called at the start of your program after all the static setup is done. E.g. entire C program's execution path is:
Do some initialization code
Call main()
Exit.
As such, it has a standard declaration (# of parameters passed from command line + array of "strings" - however the language implements that - which are the actual arguments from command line)
In C/C++, it a standard so its built in and reconized.
Java, not sure, no experience
C# - Its a part of a class so its defined by you.
All of these are defined by you -- you tell it what to do.
It's a user defined function that is called by the language's runtime library. For example, a C runtime library will grab the command line arguments and sometimes environment variables from the operating system and pass them into to your main() function.
Different language runtimes usually perform the same operation in one form or another, and will throw some sort of error if the function it tries to call doesn't exist.
It's declaration is built-in. It's definition is user supplied, or in some cases supplied by an application framework that has some other entry point, or in the case of most event-driven GUI frameworks, no single user-defined entry point.
In Java main(String[] args) is the entry point for applications by convention (to make C++ programmers comfortable). For applets or servlets the invocation of code happens differently. Note that a jar may contain any or none of these entry points and that each class may contain a main so a given jar can be invoked in many different ways as an applcation if so desired.

Categories

Resources