To complement the article on how to create a Blank Visual Studio 2017 solution, I'll post how to create a blank project.

Unfortunately, I've only been able to test this technique with C# projects, and F# is not guaranteed to work with this method yet. I have not tested this with Visual Basic.

Drop this text into a file with a .csproj extension:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFrameworks>net461</TargetFrameworks>
  </PropertyGroup>
</Project>

That's all there is to it! You can then add this existing project to your solution in Visual Studio.

Portable CLI Executable

In order to create an executable command line program, you will want to add this property under the <PropertyGroup> section:

  <OutputType>exe</OutputType>

Note that this only mandates you have an entry point (static Main()) somewhere in your application, but it does not generate an EXE. The output format will be DLL. The difference is, it can now be run with dotnet run. You will also need to specify that it targets a netcoreapp framework.

Windows CLI Executable

To create an EXE that can be run directly from Windows, use this in the <PropertyGroup> section:

  <OutputType>winexe</OutputType>

You will also need to specify that it targets a netcoreapp framework.

Windows Forms Executable

To create an EXE that can be run directly from Windows and have Windows Forms functionality, use these in the <PropertyGroup> section:

  <OutputType>winexe</OutputType>
  <UseWindowsForms>true</UseWindowsForms>

Also, you will need to change the SDK type to Microsoft.NET.Sdk.WindowsDesktop at the top of the file, in the <Project> element. You will then have access to System.Windows.Forms without the need for a direct reference. Note that this requires at least netcoreapp3.0.

Target Frameworks

It is required to specify which framework you are targeting. This is included in the markup above already, but if you want to use something other than .NET Framework 4.5, see the below table for which value to use.

FrameworkValue
.NET 5.0net5.0
.NET Core App 1.0netcoreapp1.0
.NET Core App 1.1netcoreapp1.1
.NET Core App 2.0netcoreapp2.0
.NET Core App 2.1netcoreapp2.1
.NET Core App 2.2netcoreapp2.2
.NET Core App 3.0netcoreapp3.0
.NET Framework 1.1net11
.NET Framework 2.0net20
.NET Framework 3.5net35
.NET Framework 4.0net40
.NET Framework 4.5net45
.NET Framework 4.5.1net451
.NET Framework 4.5.2net452
.NET Framework 4.6net46
.NET Framework 4.6.1net461
.NET Framework 4.6.2net462
.NET Framework 4.7net47
.NET Framework 4.7.1net471
.NET Framework 4.7.2net472
.NET Framework 4.8net48
.NET Standard 1.0netstandard1.0
.NET Standard 1.1netstandard1.1
.NET Standard 1.2netstandard1.2
.NET Standard 1.3netstandard1.3
.NET Standard 1.4netstandard1.4
.NET Standard 1.5netstandard1.5
.NET Standard 1.6netstandard1.6
.NET Standard 2.0netstandard2.0
.NET Standard 2.1netstandard2.1

There's even more on the Microsoft website.

Multiple Target Frameworks

You can even specify multiple target frameworks by separating them with semicolons. Here's an example which targets both .NET Framework 4.6.1 and .NET Standard 2.0 per the recommendation of the guidance document (see the next section for more on that):

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFrameworks>net461;netstandard2.0</TargetFrameworks>
  </PropertyGroup>
</Project>

Guidelines

Microsoft has released the Guidance for Library Authors. Definitely check this out.

Happy coding!