diff --git a/src/ProjectTemplates/Shared/ArgConstants.cs b/src/ProjectTemplates/Shared/ArgConstants.cs
index f68cd1ce4af4..c2cd932e76c8 100644
--- a/src/ProjectTemplates/Shared/ArgConstants.cs
+++ b/src/ProjectTemplates/Shared/ArgConstants.cs
@@ -25,4 +25,5 @@ internal static class ArgConstants
public const string AadB2cInstance = "--aad-b2c-instance";
public const string UseLocalDb = "-uld";
public const string NoHttps = "--no-https";
+ public const string PublishNativeAot = "--publish-native-aot";
}
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/Api-CSharp.csproj.in b/src/ProjectTemplates/Web.ProjectTemplates/Api-CSharp.csproj.in
new file mode 100644
index 000000000000..ead01179c249
--- /dev/null
+++ b/src/ProjectTemplates/Web.ProjectTemplates/Api-CSharp.csproj.in
@@ -0,0 +1,17 @@
+
+
+
+ ${DefaultNetCoreTargetFramework}
+ enable
+ enable
+ true
+ Company.WebApplication1
+ False
+
+ true
+ full
+ false
+
+
+
+
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/Microsoft.DotNet.Web.ProjectTemplates.csproj b/src/ProjectTemplates/Web.ProjectTemplates/Microsoft.DotNet.Web.ProjectTemplates.csproj
index 8528b64842df..67ffc2559937 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/Microsoft.DotNet.Web.ProjectTemplates.csproj
+++ b/src/ProjectTemplates/Web.ProjectTemplates/Microsoft.DotNet.Web.ProjectTemplates.csproj
@@ -30,7 +30,7 @@
-
+
@@ -59,6 +59,7 @@
+
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/.template.config/dotnetcli.host.json b/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/.template.config/dotnetcli.host.json
new file mode 100644
index 000000000000..5ab517c8b695
--- /dev/null
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/.template.config/dotnetcli.host.json
@@ -0,0 +1,33 @@
+{
+ "$schema": "http://json.schemastore.org/dotnetcli.host",
+ "symbolInfo": {
+ "Framework": {
+ "longName": "framework"
+ },
+ "skipRestore": {
+ "longName": "no-restore",
+ "shortName": ""
+ },
+ "kestrelHttpPort": {
+ "isHidden": true
+ },
+ "iisHttpPort": {
+ "isHidden": true
+ },
+ "ExcludeLaunchSettings": {
+ "longName": "exclude-launch-settings",
+ "shortName": ""
+ },
+ "UseProgramMain": {
+ "longName": "use-program-main",
+ "shortName": ""
+ },
+ "NativeAot": {
+ "longName": "publish-native-aot",
+ "shortName": "aot"
+ }
+ },
+ "usageExamples": [
+ ""
+ ]
+}
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/.template.config/ide.host.json b/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/.template.config/ide.host.json
new file mode 100644
index 000000000000..d073830080c1
--- /dev/null
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/.template.config/ide.host.json
@@ -0,0 +1,23 @@
+{
+ "$schema": "http://json.schemastore.org/ide.host",
+ "order": 100,
+ "icon": "ide/API.png",
+ "supportsDocker": true,
+ "symbolInfo": [
+ {
+ "id": "UseProgramMain",
+ "isVisible": true,
+ "persistenceScope": "shared",
+ "persistenceScopeName": "Microsoft"
+ },
+ {
+ "id": "NativeAot",
+ "isVisible": true
+ }
+ ],
+ "unsupportedHosts": [
+ {
+ "id": "vs"
+ }
+ ]
+}
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/.template.config/ide/API.png b/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/.template.config/ide/API.png
new file mode 100644
index 000000000000..53de7c7be061
Binary files /dev/null and b/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/.template.config/ide/API.png differ
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/.template.config/localize/templatestrings.cs.json b/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/.template.config/localize/templatestrings.cs.json
new file mode 100644
index 000000000000..ae777401202e
--- /dev/null
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/.template.config/localize/templatestrings.cs.json
@@ -0,0 +1,17 @@
+{
+ "author": "Microsoft",
+ "name": "ASP.NET Core API",
+ "description": "A project template for creating an ASP.NET Core API application.",
+ "symbols/ExcludeLaunchSettings/description": "Whether to exclude launchSettings.json from the generated template.",
+ "symbols/kestrelHttpPort/description": "Port number to use for the HTTP endpoint in launchSettings.json.",
+ "symbols/iisHttpPort/description": "Port number to use for the IIS Express HTTP endpoint in launchSettings.json.",
+ "symbols/Framework/description": "The target framework for the project.",
+ "symbols/Framework/choices/net8.0/description": "Target net8.0",
+ "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.",
+ "symbols/UseProgramMain/displayName": "Do not use _top-level statements",
+ "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.",
+ "symbols/NativeAot/displayName": "Enable _native AOT publish",
+ "symbols/NativeAot/description": "Whether to enable the project for publishing as native AOT.",
+ "postActions/restore/description": "Restore NuGet packages required by this project.",
+ "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'"
+}
\ No newline at end of file
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/.template.config/localize/templatestrings.de.json b/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/.template.config/localize/templatestrings.de.json
new file mode 100644
index 000000000000..ae777401202e
--- /dev/null
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/.template.config/localize/templatestrings.de.json
@@ -0,0 +1,17 @@
+{
+ "author": "Microsoft",
+ "name": "ASP.NET Core API",
+ "description": "A project template for creating an ASP.NET Core API application.",
+ "symbols/ExcludeLaunchSettings/description": "Whether to exclude launchSettings.json from the generated template.",
+ "symbols/kestrelHttpPort/description": "Port number to use for the HTTP endpoint in launchSettings.json.",
+ "symbols/iisHttpPort/description": "Port number to use for the IIS Express HTTP endpoint in launchSettings.json.",
+ "symbols/Framework/description": "The target framework for the project.",
+ "symbols/Framework/choices/net8.0/description": "Target net8.0",
+ "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.",
+ "symbols/UseProgramMain/displayName": "Do not use _top-level statements",
+ "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.",
+ "symbols/NativeAot/displayName": "Enable _native AOT publish",
+ "symbols/NativeAot/description": "Whether to enable the project for publishing as native AOT.",
+ "postActions/restore/description": "Restore NuGet packages required by this project.",
+ "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'"
+}
\ No newline at end of file
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/.template.config/localize/templatestrings.en.json b/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/.template.config/localize/templatestrings.en.json
new file mode 100644
index 000000000000..ae777401202e
--- /dev/null
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/.template.config/localize/templatestrings.en.json
@@ -0,0 +1,17 @@
+{
+ "author": "Microsoft",
+ "name": "ASP.NET Core API",
+ "description": "A project template for creating an ASP.NET Core API application.",
+ "symbols/ExcludeLaunchSettings/description": "Whether to exclude launchSettings.json from the generated template.",
+ "symbols/kestrelHttpPort/description": "Port number to use for the HTTP endpoint in launchSettings.json.",
+ "symbols/iisHttpPort/description": "Port number to use for the IIS Express HTTP endpoint in launchSettings.json.",
+ "symbols/Framework/description": "The target framework for the project.",
+ "symbols/Framework/choices/net8.0/description": "Target net8.0",
+ "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.",
+ "symbols/UseProgramMain/displayName": "Do not use _top-level statements",
+ "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.",
+ "symbols/NativeAot/displayName": "Enable _native AOT publish",
+ "symbols/NativeAot/description": "Whether to enable the project for publishing as native AOT.",
+ "postActions/restore/description": "Restore NuGet packages required by this project.",
+ "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'"
+}
\ No newline at end of file
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/.template.config/localize/templatestrings.es.json b/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/.template.config/localize/templatestrings.es.json
new file mode 100644
index 000000000000..ae777401202e
--- /dev/null
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/.template.config/localize/templatestrings.es.json
@@ -0,0 +1,17 @@
+{
+ "author": "Microsoft",
+ "name": "ASP.NET Core API",
+ "description": "A project template for creating an ASP.NET Core API application.",
+ "symbols/ExcludeLaunchSettings/description": "Whether to exclude launchSettings.json from the generated template.",
+ "symbols/kestrelHttpPort/description": "Port number to use for the HTTP endpoint in launchSettings.json.",
+ "symbols/iisHttpPort/description": "Port number to use for the IIS Express HTTP endpoint in launchSettings.json.",
+ "symbols/Framework/description": "The target framework for the project.",
+ "symbols/Framework/choices/net8.0/description": "Target net8.0",
+ "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.",
+ "symbols/UseProgramMain/displayName": "Do not use _top-level statements",
+ "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.",
+ "symbols/NativeAot/displayName": "Enable _native AOT publish",
+ "symbols/NativeAot/description": "Whether to enable the project for publishing as native AOT.",
+ "postActions/restore/description": "Restore NuGet packages required by this project.",
+ "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'"
+}
\ No newline at end of file
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/.template.config/localize/templatestrings.fr.json b/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/.template.config/localize/templatestrings.fr.json
new file mode 100644
index 000000000000..ae777401202e
--- /dev/null
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/.template.config/localize/templatestrings.fr.json
@@ -0,0 +1,17 @@
+{
+ "author": "Microsoft",
+ "name": "ASP.NET Core API",
+ "description": "A project template for creating an ASP.NET Core API application.",
+ "symbols/ExcludeLaunchSettings/description": "Whether to exclude launchSettings.json from the generated template.",
+ "symbols/kestrelHttpPort/description": "Port number to use for the HTTP endpoint in launchSettings.json.",
+ "symbols/iisHttpPort/description": "Port number to use for the IIS Express HTTP endpoint in launchSettings.json.",
+ "symbols/Framework/description": "The target framework for the project.",
+ "symbols/Framework/choices/net8.0/description": "Target net8.0",
+ "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.",
+ "symbols/UseProgramMain/displayName": "Do not use _top-level statements",
+ "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.",
+ "symbols/NativeAot/displayName": "Enable _native AOT publish",
+ "symbols/NativeAot/description": "Whether to enable the project for publishing as native AOT.",
+ "postActions/restore/description": "Restore NuGet packages required by this project.",
+ "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'"
+}
\ No newline at end of file
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/.template.config/localize/templatestrings.it.json b/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/.template.config/localize/templatestrings.it.json
new file mode 100644
index 000000000000..ae777401202e
--- /dev/null
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/.template.config/localize/templatestrings.it.json
@@ -0,0 +1,17 @@
+{
+ "author": "Microsoft",
+ "name": "ASP.NET Core API",
+ "description": "A project template for creating an ASP.NET Core API application.",
+ "symbols/ExcludeLaunchSettings/description": "Whether to exclude launchSettings.json from the generated template.",
+ "symbols/kestrelHttpPort/description": "Port number to use for the HTTP endpoint in launchSettings.json.",
+ "symbols/iisHttpPort/description": "Port number to use for the IIS Express HTTP endpoint in launchSettings.json.",
+ "symbols/Framework/description": "The target framework for the project.",
+ "symbols/Framework/choices/net8.0/description": "Target net8.0",
+ "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.",
+ "symbols/UseProgramMain/displayName": "Do not use _top-level statements",
+ "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.",
+ "symbols/NativeAot/displayName": "Enable _native AOT publish",
+ "symbols/NativeAot/description": "Whether to enable the project for publishing as native AOT.",
+ "postActions/restore/description": "Restore NuGet packages required by this project.",
+ "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'"
+}
\ No newline at end of file
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/.template.config/localize/templatestrings.ja.json b/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/.template.config/localize/templatestrings.ja.json
new file mode 100644
index 000000000000..ae777401202e
--- /dev/null
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/.template.config/localize/templatestrings.ja.json
@@ -0,0 +1,17 @@
+{
+ "author": "Microsoft",
+ "name": "ASP.NET Core API",
+ "description": "A project template for creating an ASP.NET Core API application.",
+ "symbols/ExcludeLaunchSettings/description": "Whether to exclude launchSettings.json from the generated template.",
+ "symbols/kestrelHttpPort/description": "Port number to use for the HTTP endpoint in launchSettings.json.",
+ "symbols/iisHttpPort/description": "Port number to use for the IIS Express HTTP endpoint in launchSettings.json.",
+ "symbols/Framework/description": "The target framework for the project.",
+ "symbols/Framework/choices/net8.0/description": "Target net8.0",
+ "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.",
+ "symbols/UseProgramMain/displayName": "Do not use _top-level statements",
+ "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.",
+ "symbols/NativeAot/displayName": "Enable _native AOT publish",
+ "symbols/NativeAot/description": "Whether to enable the project for publishing as native AOT.",
+ "postActions/restore/description": "Restore NuGet packages required by this project.",
+ "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'"
+}
\ No newline at end of file
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/.template.config/localize/templatestrings.ko.json b/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/.template.config/localize/templatestrings.ko.json
new file mode 100644
index 000000000000..ae777401202e
--- /dev/null
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/.template.config/localize/templatestrings.ko.json
@@ -0,0 +1,17 @@
+{
+ "author": "Microsoft",
+ "name": "ASP.NET Core API",
+ "description": "A project template for creating an ASP.NET Core API application.",
+ "symbols/ExcludeLaunchSettings/description": "Whether to exclude launchSettings.json from the generated template.",
+ "symbols/kestrelHttpPort/description": "Port number to use for the HTTP endpoint in launchSettings.json.",
+ "symbols/iisHttpPort/description": "Port number to use for the IIS Express HTTP endpoint in launchSettings.json.",
+ "symbols/Framework/description": "The target framework for the project.",
+ "symbols/Framework/choices/net8.0/description": "Target net8.0",
+ "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.",
+ "symbols/UseProgramMain/displayName": "Do not use _top-level statements",
+ "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.",
+ "symbols/NativeAot/displayName": "Enable _native AOT publish",
+ "symbols/NativeAot/description": "Whether to enable the project for publishing as native AOT.",
+ "postActions/restore/description": "Restore NuGet packages required by this project.",
+ "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'"
+}
\ No newline at end of file
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/.template.config/localize/templatestrings.pl.json b/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/.template.config/localize/templatestrings.pl.json
new file mode 100644
index 000000000000..ae777401202e
--- /dev/null
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/.template.config/localize/templatestrings.pl.json
@@ -0,0 +1,17 @@
+{
+ "author": "Microsoft",
+ "name": "ASP.NET Core API",
+ "description": "A project template for creating an ASP.NET Core API application.",
+ "symbols/ExcludeLaunchSettings/description": "Whether to exclude launchSettings.json from the generated template.",
+ "symbols/kestrelHttpPort/description": "Port number to use for the HTTP endpoint in launchSettings.json.",
+ "symbols/iisHttpPort/description": "Port number to use for the IIS Express HTTP endpoint in launchSettings.json.",
+ "symbols/Framework/description": "The target framework for the project.",
+ "symbols/Framework/choices/net8.0/description": "Target net8.0",
+ "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.",
+ "symbols/UseProgramMain/displayName": "Do not use _top-level statements",
+ "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.",
+ "symbols/NativeAot/displayName": "Enable _native AOT publish",
+ "symbols/NativeAot/description": "Whether to enable the project for publishing as native AOT.",
+ "postActions/restore/description": "Restore NuGet packages required by this project.",
+ "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'"
+}
\ No newline at end of file
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/.template.config/localize/templatestrings.pt-BR.json b/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/.template.config/localize/templatestrings.pt-BR.json
new file mode 100644
index 000000000000..ae777401202e
--- /dev/null
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/.template.config/localize/templatestrings.pt-BR.json
@@ -0,0 +1,17 @@
+{
+ "author": "Microsoft",
+ "name": "ASP.NET Core API",
+ "description": "A project template for creating an ASP.NET Core API application.",
+ "symbols/ExcludeLaunchSettings/description": "Whether to exclude launchSettings.json from the generated template.",
+ "symbols/kestrelHttpPort/description": "Port number to use for the HTTP endpoint in launchSettings.json.",
+ "symbols/iisHttpPort/description": "Port number to use for the IIS Express HTTP endpoint in launchSettings.json.",
+ "symbols/Framework/description": "The target framework for the project.",
+ "symbols/Framework/choices/net8.0/description": "Target net8.0",
+ "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.",
+ "symbols/UseProgramMain/displayName": "Do not use _top-level statements",
+ "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.",
+ "symbols/NativeAot/displayName": "Enable _native AOT publish",
+ "symbols/NativeAot/description": "Whether to enable the project for publishing as native AOT.",
+ "postActions/restore/description": "Restore NuGet packages required by this project.",
+ "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'"
+}
\ No newline at end of file
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/.template.config/localize/templatestrings.ru.json b/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/.template.config/localize/templatestrings.ru.json
new file mode 100644
index 000000000000..ae777401202e
--- /dev/null
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/.template.config/localize/templatestrings.ru.json
@@ -0,0 +1,17 @@
+{
+ "author": "Microsoft",
+ "name": "ASP.NET Core API",
+ "description": "A project template for creating an ASP.NET Core API application.",
+ "symbols/ExcludeLaunchSettings/description": "Whether to exclude launchSettings.json from the generated template.",
+ "symbols/kestrelHttpPort/description": "Port number to use for the HTTP endpoint in launchSettings.json.",
+ "symbols/iisHttpPort/description": "Port number to use for the IIS Express HTTP endpoint in launchSettings.json.",
+ "symbols/Framework/description": "The target framework for the project.",
+ "symbols/Framework/choices/net8.0/description": "Target net8.0",
+ "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.",
+ "symbols/UseProgramMain/displayName": "Do not use _top-level statements",
+ "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.",
+ "symbols/NativeAot/displayName": "Enable _native AOT publish",
+ "symbols/NativeAot/description": "Whether to enable the project for publishing as native AOT.",
+ "postActions/restore/description": "Restore NuGet packages required by this project.",
+ "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'"
+}
\ No newline at end of file
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/.template.config/localize/templatestrings.tr.json b/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/.template.config/localize/templatestrings.tr.json
new file mode 100644
index 000000000000..ae777401202e
--- /dev/null
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/.template.config/localize/templatestrings.tr.json
@@ -0,0 +1,17 @@
+{
+ "author": "Microsoft",
+ "name": "ASP.NET Core API",
+ "description": "A project template for creating an ASP.NET Core API application.",
+ "symbols/ExcludeLaunchSettings/description": "Whether to exclude launchSettings.json from the generated template.",
+ "symbols/kestrelHttpPort/description": "Port number to use for the HTTP endpoint in launchSettings.json.",
+ "symbols/iisHttpPort/description": "Port number to use for the IIS Express HTTP endpoint in launchSettings.json.",
+ "symbols/Framework/description": "The target framework for the project.",
+ "symbols/Framework/choices/net8.0/description": "Target net8.0",
+ "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.",
+ "symbols/UseProgramMain/displayName": "Do not use _top-level statements",
+ "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.",
+ "symbols/NativeAot/displayName": "Enable _native AOT publish",
+ "symbols/NativeAot/description": "Whether to enable the project for publishing as native AOT.",
+ "postActions/restore/description": "Restore NuGet packages required by this project.",
+ "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'"
+}
\ No newline at end of file
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/.template.config/localize/templatestrings.zh-Hans.json b/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/.template.config/localize/templatestrings.zh-Hans.json
new file mode 100644
index 000000000000..ae777401202e
--- /dev/null
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/.template.config/localize/templatestrings.zh-Hans.json
@@ -0,0 +1,17 @@
+{
+ "author": "Microsoft",
+ "name": "ASP.NET Core API",
+ "description": "A project template for creating an ASP.NET Core API application.",
+ "symbols/ExcludeLaunchSettings/description": "Whether to exclude launchSettings.json from the generated template.",
+ "symbols/kestrelHttpPort/description": "Port number to use for the HTTP endpoint in launchSettings.json.",
+ "symbols/iisHttpPort/description": "Port number to use for the IIS Express HTTP endpoint in launchSettings.json.",
+ "symbols/Framework/description": "The target framework for the project.",
+ "symbols/Framework/choices/net8.0/description": "Target net8.0",
+ "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.",
+ "symbols/UseProgramMain/displayName": "Do not use _top-level statements",
+ "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.",
+ "symbols/NativeAot/displayName": "Enable _native AOT publish",
+ "symbols/NativeAot/description": "Whether to enable the project for publishing as native AOT.",
+ "postActions/restore/description": "Restore NuGet packages required by this project.",
+ "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'"
+}
\ No newline at end of file
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/.template.config/localize/templatestrings.zh-Hant.json b/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/.template.config/localize/templatestrings.zh-Hant.json
new file mode 100644
index 000000000000..ae777401202e
--- /dev/null
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/.template.config/localize/templatestrings.zh-Hant.json
@@ -0,0 +1,17 @@
+{
+ "author": "Microsoft",
+ "name": "ASP.NET Core API",
+ "description": "A project template for creating an ASP.NET Core API application.",
+ "symbols/ExcludeLaunchSettings/description": "Whether to exclude launchSettings.json from the generated template.",
+ "symbols/kestrelHttpPort/description": "Port number to use for the HTTP endpoint in launchSettings.json.",
+ "symbols/iisHttpPort/description": "Port number to use for the IIS Express HTTP endpoint in launchSettings.json.",
+ "symbols/Framework/description": "The target framework for the project.",
+ "symbols/Framework/choices/net8.0/description": "Target net8.0",
+ "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.",
+ "symbols/UseProgramMain/displayName": "Do not use _top-level statements",
+ "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.",
+ "symbols/NativeAot/displayName": "Enable _native AOT publish",
+ "symbols/NativeAot/description": "Whether to enable the project for publishing as native AOT.",
+ "postActions/restore/description": "Restore NuGet packages required by this project.",
+ "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'"
+}
\ No newline at end of file
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/.template.config/template.json b/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/.template.config/template.json
new file mode 100644
index 000000000000..3861a38bdbb1
--- /dev/null
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/.template.config/template.json
@@ -0,0 +1,160 @@
+{
+ "$schema": "http://json.schemastore.org/template",
+ "author": "Microsoft",
+ "classifications": [
+ "Web",
+ "API"
+ ],
+ "name": "ASP.NET Core API",
+ "generatorVersions": "[1.0.0.0-*)",
+ "description": "A project template for creating an ASP.NET Core API application.",
+ "groupIdentity": "Microsoft.Web.Api",
+ "precedence": "9000",
+ "identity": "Microsoft.Web.Api.CSharp.8.0",
+ "shortName": "api",
+ "tags": {
+ "language": "C#",
+ "type": "project"
+ },
+ "sourceName": "Company.ApiApplication1",
+ "preferNameDirectory": true,
+ "guids": [
+ "53bc9b9d-9d6a-45d4-8429-2a2761773502"
+ ],
+ "sources": [
+ {
+ "modifiers": [
+ {
+ "condition": "(ExcludeLaunchSettings)",
+ "exclude": [
+ "Properties/launchSettings.json"
+ ]
+ },
+ {
+ "condition": "(!UseProgramMain)",
+ "exclude": [
+ "Program.Main.cs"
+ ]
+ },
+ {
+ "condition": "(UseProgramMain)",
+ "exclude": [
+ "Program.cs"
+ ],
+ "rename": {
+ "Program.Main.cs": "Program.cs"
+ }
+ }
+ ]
+ }
+ ],
+ "symbols": {
+ "ExcludeLaunchSettings": {
+ "type": "parameter",
+ "datatype": "bool",
+ "defaultValue": "false",
+ "description": "Whether to exclude launchSettings.json from the generated template."
+ },
+ "kestrelHttpPort": {
+ "type": "parameter",
+ "datatype": "integer",
+ "description": "Port number to use for the HTTP endpoint in launchSettings.json."
+ },
+ "kestrelHttpPortGenerated": {
+ "type": "generated",
+ "generator": "port",
+ "parameters": {
+ "low": 5000,
+ "high": 5300
+ }
+ },
+ "kestrelHttpPortReplacer": {
+ "type": "generated",
+ "generator": "coalesce",
+ "parameters": {
+ "sourceVariableName": "kestrelHttpPort",
+ "fallbackVariableName": "kestrelHttpPortGenerated"
+ },
+ "replaces": "5000"
+ },
+ "iisHttpPort": {
+ "type": "parameter",
+ "datatype": "integer",
+ "description": "Port number to use for the IIS Express HTTP endpoint in launchSettings.json."
+ },
+ "iisHttpPortGenerated": {
+ "type": "generated",
+ "generator": "port"
+ },
+ "iisHttpPortReplacer": {
+ "type": "generated",
+ "generator": "coalesce",
+ "parameters": {
+ "sourceVariableName": "iisHttpPort",
+ "fallbackVariableName": "iisHttpPortGenerated"
+ },
+ "replaces": "8080"
+ },
+ "Framework": {
+ "type": "parameter",
+ "description": "The target framework for the project.",
+ "datatype": "choice",
+ "choices": [
+ {
+ "choice": "net8.0",
+ "description": "Target net8.0"
+ }
+ ],
+ "replaces": "net8.0",
+ "defaultValue": "net8.0"
+ },
+ "copyrightYear": {
+ "type": "generated",
+ "generator": "now",
+ "replaces": "copyrightYear",
+ "parameters": {
+ "format": "yyyy"
+ }
+ },
+ "skipRestore": {
+ "type": "parameter",
+ "datatype": "bool",
+ "description": "If specified, skips the automatic restore of the project on create.",
+ "defaultValue": "false"
+ },
+ "UseProgramMain": {
+ "type": "parameter",
+ "datatype": "bool",
+ "defaultValue": "false",
+ "displayName": "Do not use _top-level statements",
+ "description": "Whether to generate an explicit Program class and Main method instead of top-level statements."
+ },
+ "NativeAot" : {
+ "type": "parameter",
+ "datatype": "bool",
+ "defaultValue": "false",
+ "displayName": "Enable _native AOT publish",
+ "description": "Whether to enable the project for publishing as native AOT."
+ }
+ },
+ "primaryOutputs": [
+ {
+ "path": "Company.ApiApplication1.csproj"
+ }
+ ],
+ "defaultName": "ApiApplication",
+ "postActions": [
+ {
+ "id": "restore",
+ "condition": "(!skipRestore)",
+ "description": "Restore NuGet packages required by this project.",
+ "manualInstructions": [
+ {
+ "text": "Run 'dotnet restore'"
+ }
+ ],
+ "actionId": "210D431B-A78B-4D2F-B762-4ED3E3EA9025",
+ "continueOnError": true
+ }
+ ]
+}
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/Program.Main.cs b/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/Program.Main.cs
new file mode 100644
index 000000000000..1e7082c4f9cb
--- /dev/null
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/Program.Main.cs
@@ -0,0 +1,42 @@
+using System.Text.Json.Serialization;
+#if NativeAot
+using Microsoft.AspNetCore.Http.Json;
+using Microsoft.Extensions.Options;
+#endif
+namespace Company.ApiApplication1;
+
+public class Program
+{
+ public static void Main(string[] args)
+ {
+ var builder = WebApplication.CreateBuilder(args);
+ builder.Logging.AddConsole();
+
+ #if (NativeAot)
+ builder.Services.ConfigureHttpJsonOptions(options =>
+ {
+ options.SerializerOptions.AddContext();
+ });
+
+ #endif
+ var app = builder.Build();
+
+ var sampleTodos = TodoGenerator.GenerateTodos().ToArray();
+
+ var todosApi = app.MapGroup("/todos");
+ todosApi.MapGet("/", () => sampleTodos);
+ todosApi.MapGet("/{id}", (int id) =>
+ sampleTodos.FirstOrDefault(a => a.Id == id) is { } todo
+ ? Results.Ok(todo)
+ : Results.NotFound());
+
+ app.Run();
+ }
+}
+
+#if (NativeAot)
+[JsonSerializable(typeof(Todo[]))]
+internal partial class AppJsonSerializerContext : JsonSerializerContext
+{
+
+}
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/Program.cs b/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/Program.cs
new file mode 100644
index 000000000000..be0ffccde6fa
--- /dev/null
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/Program.cs
@@ -0,0 +1,34 @@
+#if (NativeAot)
+using System.Text.Json.Serialization;
+#endif
+using Company.ApiApplication1;
+
+var builder = WebApplication.CreateBuilder(args);
+builder.Logging.AddConsole();
+
+#if (NativeAot)
+builder.Services.ConfigureHttpJsonOptions(options =>
+{
+ options.SerializerOptions.AddContext();
+});
+
+#endif
+var app = builder.Build();
+
+var sampleTodos = TodoGenerator.GenerateTodos().ToArray();
+
+var todosApi = app.MapGroup("/todos");
+todosApi.MapGet("/", () => sampleTodos);
+todosApi.MapGet("/{id}", (int id) =>
+ sampleTodos.FirstOrDefault(a => a.Id == id) is { } todo
+ ? Results.Ok(todo)
+ : Results.NotFound());
+
+app.Run();
+
+#if (NativeAot)
+[JsonSerializable(typeof(Todo[]))]
+internal partial class AppJsonSerializerContext : JsonSerializerContext
+{
+
+}
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/Properties/launchSettings.json b/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/Properties/launchSettings.json
new file mode 100644
index 000000000000..444a41bf94bf
--- /dev/null
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/Properties/launchSettings.json
@@ -0,0 +1,36 @@
+{
+//#if (!NativeAot)
+ "iisSettings": {
+ "windowsAuthentication": false,
+ "anonymousAuthentication": true,
+ "iisExpress": {
+ "applicationUrl": "http://localhost:8080",
+ "sslPort": 0
+ }
+ },
+//#endif
+ "profiles": {
+ "http": {
+ "commandName": "Project",
+ "dotnetRunMessages": true,
+ "launchBrowser": true,
+ "launchUrl": "todos",
+ "applicationUrl": "http://localhost:5000",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+//#if (!NativeAot)
+ },
+ "IIS Express": {
+ "commandName": "IISExpress",
+ "launchBrowser": true,
+ "launchUrl": "todos",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ }
+//#else
+ }
+//#endif
+ }
+}
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/Todo.cs b/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/Todo.cs
new file mode 100644
index 000000000000..74990e150827
--- /dev/null
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/Todo.cs
@@ -0,0 +1,64 @@
+namespace Company.ApiApplication1;
+
+public class Todo
+{
+ public int Id { get; set; }
+
+ public string? Title { get; set; }
+
+ public DateOnly? DueBy { get; set; }
+
+ public bool IsComplete { get; set; }
+}
+
+static class TodoGenerator
+{
+ private static readonly (string[] Prefixes, string[] Suffixes)[] _parts = new[]
+ {
+ (new[] { "Walk the", "Feed the" }, new[] { "dog", "cat", "goat" }),
+ (new[] { "Do the", "Put away the" }, new[] { "groceries", "dishes", "laundry" }),
+ (new[] { "Clean the" }, new[] { "bathroom", "pool", "blinds", "car" })
+ };
+
+ internal static IEnumerable GenerateTodos(int count = 5)
+ {
+ var titleMap = new List<(int Row, int Prefix, int Suffix)>();
+ for (var i = 0; i < _parts.Length; i++)
+ {
+ var prefixes = _parts[i].Prefixes;
+ var suffixes = _parts[i].Suffixes;
+ for (int j = 0; j < prefixes.Length; j++)
+ {
+ for (int k = 0; k < suffixes.Length; k++)
+ {
+ titleMap.Add((i, j, k));
+ }
+ }
+ }
+
+ var random = new Random();
+
+ for (var id = 1; id <= count; id++)
+ {
+ yield return new Todo
+ {
+ Id = id,
+ Title = GetNextTitle(),
+ DueBy = random.Next(-200, 365) switch
+ {
+ < 0 => null,
+ var days => DateOnly.FromDateTime(DateTime.Now.AddDays(days))
+ }
+ };
+
+ string GetNextTitle()
+ {
+ var index = random.Next(0, titleMap.Count - 1);
+ var map = titleMap[index];
+ var row = _parts[map.Row];
+ titleMap.RemoveAt(index);
+ return string.Join(' ', row.Prefixes[map.Prefix], row.Suffixes[map.Suffix]);
+ }
+ }
+ }
+}
diff --git a/src/ProjectTemplates/scripts/Run-Angular-Locally.ps1 b/src/ProjectTemplates/scripts/Run-Angular-Locally.ps1
index 606071f0618c..d7456ebf9c7f 100644
--- a/src/ProjectTemplates/scripts/Run-Angular-Locally.ps1
+++ b/src/ProjectTemplates/scripts/Run-Angular-Locally.ps1
@@ -9,4 +9,4 @@ $ErrorActionPreference = 'Stop'
. $PSScriptRoot\Test-Template.ps1
-Test-Template "angular" "angular" "Microsoft.DotNet.Web.Spa.ProjectTemplates.7.0.7.0.0-dev.nupkg" $false
+Test-Template "angular" "angular" "Microsoft.DotNet.Web.Spa.ProjectTemplates.8.0.8.0.0-dev.nupkg" $false
diff --git a/src/ProjectTemplates/scripts/Run-AngularProgramMain-Locally.ps1 b/src/ProjectTemplates/scripts/Run-AngularProgramMain-Locally.ps1
index 955b9450bab9..37bd91bda683 100644
--- a/src/ProjectTemplates/scripts/Run-AngularProgramMain-Locally.ps1
+++ b/src/ProjectTemplates/scripts/Run-AngularProgramMain-Locally.ps1
@@ -9,4 +9,4 @@ $ErrorActionPreference = 'Stop'
. $PSScriptRoot\Test-Template.ps1
-Test-Template "angular" "angular --use-program-main" "Microsoft.DotNet.Web.Spa.ProjectTemplates.7.0.7.0.0-dev.nupkg" $false
+Test-Template "angular" "angular --use-program-main" "Microsoft.DotNet.Web.Spa.ProjectTemplates.8.0.8.0.0-dev.nupkg" $false
diff --git a/src/ProjectTemplates/scripts/Run-Api-Locally.ps1 b/src/ProjectTemplates/scripts/Run-Api-Locally.ps1
new file mode 100644
index 000000000000..1833059b765b
--- /dev/null
+++ b/src/ProjectTemplates/scripts/Run-Api-Locally.ps1
@@ -0,0 +1,12 @@
+#!/usr/bin/env pwsh
+#requires -version 4
+
+[CmdletBinding(PositionalBinding = $false)]
+param()
+
+Set-StrictMode -Version 2
+$ErrorActionPreference = 'Stop'
+
+. $PSScriptRoot\Test-Template.ps1
+
+Test-Template "api" "api" "Microsoft.DotNet.Web.ProjectTemplates.8.0.8.0.0-dev.nupkg" $false
diff --git a/src/ProjectTemplates/scripts/Run-ApiNativeAot-Locally.ps1 b/src/ProjectTemplates/scripts/Run-ApiNativeAot-Locally.ps1
new file mode 100644
index 000000000000..940ac2e085ff
--- /dev/null
+++ b/src/ProjectTemplates/scripts/Run-ApiNativeAot-Locally.ps1
@@ -0,0 +1,12 @@
+#!/usr/bin/env pwsh
+#requires -version 4
+
+[CmdletBinding(PositionalBinding = $false)]
+param()
+
+Set-StrictMode -Version 2
+$ErrorActionPreference = 'Stop'
+
+. $PSScriptRoot\Test-Template.ps1
+
+Test-Template "api" "api -aot" "Microsoft.DotNet.Web.ProjectTemplates.8.0.8.0.0-dev.nupkg" $false
diff --git a/src/ProjectTemplates/scripts/Run-ApiProgramMain-Locally.ps1 b/src/ProjectTemplates/scripts/Run-ApiProgramMain-Locally.ps1
new file mode 100644
index 000000000000..607250bd2e82
--- /dev/null
+++ b/src/ProjectTemplates/scripts/Run-ApiProgramMain-Locally.ps1
@@ -0,0 +1,12 @@
+#!/usr/bin/env pwsh
+#requires -version 4
+
+[CmdletBinding(PositionalBinding = $false)]
+param()
+
+Set-StrictMode -Version 2
+$ErrorActionPreference = 'Stop'
+
+. $PSScriptRoot\Test-Template.ps1
+
+Test-Template "api" "api --use-program-main" "Microsoft.DotNet.Web.ProjectTemplates.8.0.8.0.0-dev.nupkg" $false
diff --git a/src/ProjectTemplates/scripts/Run-ApiProgramMainNativeAot-Locally.ps1 b/src/ProjectTemplates/scripts/Run-ApiProgramMainNativeAot-Locally.ps1
new file mode 100644
index 000000000000..142ca4478cbd
--- /dev/null
+++ b/src/ProjectTemplates/scripts/Run-ApiProgramMainNativeAot-Locally.ps1
@@ -0,0 +1,12 @@
+#!/usr/bin/env pwsh
+#requires -version 4
+
+[CmdletBinding(PositionalBinding = $false)]
+param()
+
+Set-StrictMode -Version 2
+$ErrorActionPreference = 'Stop'
+
+. $PSScriptRoot\Test-Template.ps1
+
+Test-Template "api" "api -aot --use-program-main" "Microsoft.DotNet.Web.ProjectTemplates.8.0.8.0.0-dev.nupkg" $false
diff --git a/src/ProjectTemplates/scripts/Run-Blazor-Locally.ps1 b/src/ProjectTemplates/scripts/Run-Blazor-Locally.ps1
index 22b9f6db9671..35cca9a4abb2 100644
--- a/src/ProjectTemplates/scripts/Run-Blazor-Locally.ps1
+++ b/src/ProjectTemplates/scripts/Run-Blazor-Locally.ps1
@@ -10,4 +10,4 @@ $ErrorActionPreference = 'Stop'
. $PSScriptRoot\Test-Template.ps1
-Test-Template "blazorserver" "blazorserver" "Microsoft.DotNet.Web.ProjectTemplates.7.0.7.0.0-dev.nupkg" $false
+Test-Template "blazorserver" "blazorserver" "Microsoft.DotNet.Web.ProjectTemplates.8.0.8.0.0-dev.nupkg" $false
diff --git a/src/ProjectTemplates/scripts/Run-BlazorProgramMain-Locally.ps1 b/src/ProjectTemplates/scripts/Run-BlazorProgramMain-Locally.ps1
index a5f89a1201d1..cd289c916dc0 100644
--- a/src/ProjectTemplates/scripts/Run-BlazorProgramMain-Locally.ps1
+++ b/src/ProjectTemplates/scripts/Run-BlazorProgramMain-Locally.ps1
@@ -10,4 +10,4 @@ $ErrorActionPreference = 'Stop'
. $PSScriptRoot\Test-Template.ps1
-Test-Template "blazorserver" "blazorserver --use-program-main" "Microsoft.DotNet.Web.ProjectTemplates.7.0.7.0.0-dev.nupkg" $false
+Test-Template "blazorserver" "blazorserver --use-program-main" "Microsoft.DotNet.Web.ProjectTemplates.8.0.8.0.0-dev.nupkg" $false
diff --git a/src/ProjectTemplates/scripts/Run-BlazorWasm-Locally.ps1 b/src/ProjectTemplates/scripts/Run-BlazorWasm-Locally.ps1
index 184f3c28f886..9eede752aac6 100644
--- a/src/ProjectTemplates/scripts/Run-BlazorWasm-Locally.ps1
+++ b/src/ProjectTemplates/scripts/Run-BlazorWasm-Locally.ps1
@@ -10,4 +10,4 @@ $ErrorActionPreference = 'Stop'
. $PSScriptRoot\Test-Template.ps1
-Test-Template "blazorwasm" "blazorwasm --hosted --auth Individual" "Microsoft.DotNet.Web.ProjectTemplates.7.0.7.0.0-dev.nupkg" $true
+Test-Template "blazorwasm" "blazorwasm --hosted --auth Individual" "Microsoft.DotNet.Web.ProjectTemplates.8.0.8.0.0-dev.nupkg" $true
diff --git a/src/ProjectTemplates/scripts/Run-BlazorWasmProgramMain-Locally.ps1 b/src/ProjectTemplates/scripts/Run-BlazorWasmProgramMain-Locally.ps1
index 4c28a987937b..a4e4e360addc 100644
--- a/src/ProjectTemplates/scripts/Run-BlazorWasmProgramMain-Locally.ps1
+++ b/src/ProjectTemplates/scripts/Run-BlazorWasmProgramMain-Locally.ps1
@@ -10,4 +10,4 @@ $ErrorActionPreference = 'Stop'
. $PSScriptRoot\Test-Template.ps1
-Test-Template "blazorwasm" "blazorwasm --use-program-main --hosted --auth Individual" "Microsoft.DotNet.Web.ProjectTemplates.7.0.7.0.0-dev.nupkg" $true
+Test-Template "blazorwasm" "blazorwasm --use-program-main --hosted --auth Individual" "Microsoft.DotNet.Web.ProjectTemplates.8.0.8.0.0-dev.nupkg" $true
diff --git a/src/ProjectTemplates/scripts/Run-EmptyWeb-Locally.ps1 b/src/ProjectTemplates/scripts/Run-EmptyWeb-Locally.ps1
index 9d55079bf9bf..3a7607863305 100644
--- a/src/ProjectTemplates/scripts/Run-EmptyWeb-Locally.ps1
+++ b/src/ProjectTemplates/scripts/Run-EmptyWeb-Locally.ps1
@@ -9,4 +9,4 @@ $ErrorActionPreference = 'Stop'
. $PSScriptRoot\Test-Template.ps1
-Test-Template "web" "web" "Microsoft.DotNet.Web.ProjectTemplates.7.0.7.0.0-dev.nupkg" $false
+Test-Template "web" "web" "Microsoft.DotNet.Web.ProjectTemplates.8.0.8.0.0-dev.nupkg" $false
diff --git a/src/ProjectTemplates/scripts/Run-EmptyWebProgramMain-Locally.ps1 b/src/ProjectTemplates/scripts/Run-EmptyWebProgramMain-Locally.ps1
index 4fd0f95af099..6a20bf49489a 100644
--- a/src/ProjectTemplates/scripts/Run-EmptyWebProgramMain-Locally.ps1
+++ b/src/ProjectTemplates/scripts/Run-EmptyWebProgramMain-Locally.ps1
@@ -9,4 +9,4 @@ $ErrorActionPreference = 'Stop'
. $PSScriptRoot\Test-Template.ps1
-Test-Template "web" "web --use-program-main" "Microsoft.DotNet.Web.ProjectTemplates.7.0.7.0.0-dev.nupkg" $false
+Test-Template "web" "web --use-program-main" "Microsoft.DotNet.Web.ProjectTemplates.8.0.8.0.0-dev.nupkg" $false
diff --git a/src/ProjectTemplates/scripts/Run-Razor-Locally.ps1 b/src/ProjectTemplates/scripts/Run-Razor-Locally.ps1
index 9dfe0c217816..81ad557a86ca 100644
--- a/src/ProjectTemplates/scripts/Run-Razor-Locally.ps1
+++ b/src/ProjectTemplates/scripts/Run-Razor-Locally.ps1
@@ -6,4 +6,4 @@ param()
. $PSScriptRoot\Test-Template.ps1
-Test-Template "webapp" "webapp -au Individual" "Microsoft.DotNet.Web.ProjectTemplates.7.0.7.0.0-dev.nupkg" $false
+Test-Template "webapp" "webapp -au Individual" "Microsoft.DotNet.Web.ProjectTemplates.8.0.8.0.0-dev.nupkg" $false
diff --git a/src/ProjectTemplates/scripts/Run-RazorProgramMain-Locally.ps1 b/src/ProjectTemplates/scripts/Run-RazorProgramMain-Locally.ps1
index ada9e210b673..6a63b579a12b 100644
--- a/src/ProjectTemplates/scripts/Run-RazorProgramMain-Locally.ps1
+++ b/src/ProjectTemplates/scripts/Run-RazorProgramMain-Locally.ps1
@@ -6,4 +6,4 @@ param()
. $PSScriptRoot\Test-Template.ps1
-Test-Template "webapp" "webapp -au Individual --use-program-main" "Microsoft.DotNet.Web.ProjectTemplates.7.0.7.0.0-dev.nupkg" $false
+Test-Template "webapp" "webapp -au Individual --use-program-main" "Microsoft.DotNet.Web.ProjectTemplates.8.0.8.0.0-dev.nupkg" $false
diff --git a/src/ProjectTemplates/scripts/Run-React-Locally.ps1 b/src/ProjectTemplates/scripts/Run-React-Locally.ps1
index 5be4be7ff5a4..4136d4b02cdd 100644
--- a/src/ProjectTemplates/scripts/Run-React-Locally.ps1
+++ b/src/ProjectTemplates/scripts/Run-React-Locally.ps1
@@ -9,4 +9,4 @@ $ErrorActionPreference = 'Stop'
. $PSScriptRoot\Test-Template.ps1
-Test-Template "react" "react" "Microsoft.DotNet.Web.Spa.ProjectTemplates.7.0.7.0.0-dev.nupkg" $false
+Test-Template "react" "react" "Microsoft.DotNet.Web.Spa.ProjectTemplates.8.0.8.0.0-dev.nupkg" $false
diff --git a/src/ProjectTemplates/scripts/Run-ReactProgramMain-Locally.ps1 b/src/ProjectTemplates/scripts/Run-ReactProgramMain-Locally.ps1
index ef8cc77d324b..7b5c366de665 100644
--- a/src/ProjectTemplates/scripts/Run-ReactProgramMain-Locally.ps1
+++ b/src/ProjectTemplates/scripts/Run-ReactProgramMain-Locally.ps1
@@ -9,4 +9,4 @@ $ErrorActionPreference = 'Stop'
. $PSScriptRoot\Test-Template.ps1
-Test-Template "react" "react --use-program-main" "Microsoft.DotNet.Web.Spa.ProjectTemplates.7.0.7.0.0-dev.nupkg" $false
+Test-Template "react" "react --use-program-main" "Microsoft.DotNet.Web.Spa.ProjectTemplates.8.0.8.0.0-dev.nupkg" $false
diff --git a/src/ProjectTemplates/scripts/Run-ReactRedux-Locally.ps1 b/src/ProjectTemplates/scripts/Run-ReactRedux-Locally.ps1
index 06303a076a04..c90fb6dd9c13 100644
--- a/src/ProjectTemplates/scripts/Run-ReactRedux-Locally.ps1
+++ b/src/ProjectTemplates/scripts/Run-ReactRedux-Locally.ps1
@@ -9,4 +9,4 @@ $ErrorActionPreference = 'Stop'
. $PSScriptRoot\Test-Template.ps1
-Test-Template "reactredux" "reactredux" "Microsoft.DotNet.Web.Spa.ProjectTemplates.7.0.7.0.0-dev.nupkg" $false
+Test-Template "reactredux" "reactredux" "Microsoft.DotNet.Web.Spa.ProjectTemplates.8.0.8.0.0-dev.nupkg" $false
diff --git a/src/ProjectTemplates/scripts/Run-Starterweb-Locally.ps1 b/src/ProjectTemplates/scripts/Run-Starterweb-Locally.ps1
index c411befc5a08..1e37fa976fa2 100644
--- a/src/ProjectTemplates/scripts/Run-Starterweb-Locally.ps1
+++ b/src/ProjectTemplates/scripts/Run-Starterweb-Locally.ps1
@@ -9,4 +9,4 @@ $ErrorActionPreference = 'Stop'
. $PSScriptRoot\Test-Template.ps1
-Test-Template "mvc" "mvc -au Individual" "Microsoft.DotNet.Web.ProjectTemplates.7.0.7.0.0-dev.nupkg" $false
+Test-Template "mvc" "mvc -au Individual" "Microsoft.DotNet.Web.ProjectTemplates.8.0.8.0.0-dev.nupkg" $false
diff --git a/src/ProjectTemplates/scripts/Run-StarterwebProgramMain-Locally.ps1 b/src/ProjectTemplates/scripts/Run-StarterwebProgramMain-Locally.ps1
index d262c5eb50a3..17396806d9f1 100644
--- a/src/ProjectTemplates/scripts/Run-StarterwebProgramMain-Locally.ps1
+++ b/src/ProjectTemplates/scripts/Run-StarterwebProgramMain-Locally.ps1
@@ -9,4 +9,4 @@ $ErrorActionPreference = 'Stop'
. $PSScriptRoot\Test-Template.ps1
-Test-Template "mvc" "mvc -au Individual --use-program-main" "Microsoft.DotNet.Web.ProjectTemplates.7.0.7.0.0-dev.nupkg" $false
+Test-Template "mvc" "mvc -au Individual --use-program-main" "Microsoft.DotNet.Web.ProjectTemplates.8.0.8.0.0-dev.nupkg" $false
diff --git a/src/ProjectTemplates/scripts/Run-WebApi-Locally.ps1 b/src/ProjectTemplates/scripts/Run-WebApi-Locally.ps1
index 14f003acfdda..27c064433eae 100644
--- a/src/ProjectTemplates/scripts/Run-WebApi-Locally.ps1
+++ b/src/ProjectTemplates/scripts/Run-WebApi-Locally.ps1
@@ -9,4 +9,4 @@ $ErrorActionPreference = 'Stop'
. $PSScriptRoot\Test-Template.ps1
-Test-Template "webapi" "webapi" "Microsoft.DotNet.Web.ProjectTemplates.7.0.7.0.0-dev.nupkg" $false
+Test-Template "webapi" "webapi" "Microsoft.DotNet.Web.ProjectTemplates.8.0.8.0.0-dev.nupkg" $false
diff --git a/src/ProjectTemplates/scripts/Run-WebApiMinimal-Locally.ps1 b/src/ProjectTemplates/scripts/Run-WebApiMinimal-Locally.ps1
index 4e32b826f804..feee0afcb44f 100644
--- a/src/ProjectTemplates/scripts/Run-WebApiMinimal-Locally.ps1
+++ b/src/ProjectTemplates/scripts/Run-WebApiMinimal-Locally.ps1
@@ -9,4 +9,4 @@ $ErrorActionPreference = 'Stop'
. $PSScriptRoot\Test-Template.ps1
-Test-Template "webapimin" "webapi -minimal" "Microsoft.DotNet.Web.ProjectTemplates.7.0.7.0.0-dev.nupkg" $false
+Test-Template "webapimin" "webapi -minimal" "Microsoft.DotNet.Web.ProjectTemplates.8.0.8.0.0-dev.nupkg" $false
diff --git a/src/ProjectTemplates/scripts/Run-WebApiProgamMain-Locally.ps1 b/src/ProjectTemplates/scripts/Run-WebApiProgamMain-Locally.ps1
index dafce7776393..fb3565c9c6d9 100644
--- a/src/ProjectTemplates/scripts/Run-WebApiProgamMain-Locally.ps1
+++ b/src/ProjectTemplates/scripts/Run-WebApiProgamMain-Locally.ps1
@@ -9,4 +9,4 @@ $ErrorActionPreference = 'Stop'
. $PSScriptRoot\Test-Template.ps1
-Test-Template "webapi" "webapi --use-program-main" "Microsoft.DotNet.Web.ProjectTemplates.7.0.7.0.0-dev.nupkg" $false
+Test-Template "webapi" "webapi --use-program-main" "Microsoft.DotNet.Web.ProjectTemplates.8.0.8.0.0-dev.nupkg" $false
diff --git a/src/ProjectTemplates/scripts/Run-WebApiProgamMainMinimal-Locally.ps1 b/src/ProjectTemplates/scripts/Run-WebApiProgamMainMinimal-Locally.ps1
index e4c2eb0f36ed..63fa1e8ae9d1 100644
--- a/src/ProjectTemplates/scripts/Run-WebApiProgamMainMinimal-Locally.ps1
+++ b/src/ProjectTemplates/scripts/Run-WebApiProgamMainMinimal-Locally.ps1
@@ -9,4 +9,4 @@ $ErrorActionPreference = 'Stop'
. $PSScriptRoot\Test-Template.ps1
-Test-Template "webapi" "webapi --use-program-main --use-minimal-apis" "Microsoft.DotNet.Web.ProjectTemplates.7.0.7.0.0-dev.nupkg" $false
+Test-Template "webapi" "webapi --use-program-main --use-minimal-apis" "Microsoft.DotNet.Web.ProjectTemplates.8.0.8.0.0-dev.nupkg" $false
diff --git a/src/ProjectTemplates/scripts/Run-Worker-Locally.ps1 b/src/ProjectTemplates/scripts/Run-Worker-Locally.ps1
index 7ccf87d528f4..b2320d5adfe8 100644
--- a/src/ProjectTemplates/scripts/Run-Worker-Locally.ps1
+++ b/src/ProjectTemplates/scripts/Run-Worker-Locally.ps1
@@ -9,4 +9,4 @@ $ErrorActionPreference = 'Stop'
. $PSScriptRoot\Test-Template.ps1
-Test-Template "worker" "worker" "Microsoft.DotNet.Web.ProjectTemplates.7.0.7.0.0-dev.nupkg" $false
+Test-Template "worker" "worker" "Microsoft.DotNet.Web.ProjectTemplates.8.0.8.0.0-dev.nupkg" $false
diff --git a/src/ProjectTemplates/scripts/Run-WorkerProgramMain-Locally.ps1 b/src/ProjectTemplates/scripts/Run-WorkerProgramMain-Locally.ps1
index 42b013ef277d..fa9119dea0bd 100644
--- a/src/ProjectTemplates/scripts/Run-WorkerProgramMain-Locally.ps1
+++ b/src/ProjectTemplates/scripts/Run-WorkerProgramMain-Locally.ps1
@@ -9,4 +9,4 @@ $ErrorActionPreference = 'Stop'
. $PSScriptRoot\Test-Template.ps1
-Test-Template "worker" "worker --use-program-main" "Microsoft.DotNet.Web.ProjectTemplates.7.0.7.0.0-dev.nupkg" $false
+Test-Template "worker" "worker --use-program-main" "Microsoft.DotNet.Web.ProjectTemplates.8.0.8.0.0-dev.nupkg" $false
diff --git a/src/ProjectTemplates/scripts/Run-gRPC-Locally.ps1 b/src/ProjectTemplates/scripts/Run-gRPC-Locally.ps1
index d201cda0479d..9d8c5bffdcb8 100644
--- a/src/ProjectTemplates/scripts/Run-gRPC-Locally.ps1
+++ b/src/ProjectTemplates/scripts/Run-gRPC-Locally.ps1
@@ -9,4 +9,4 @@ $ErrorActionPreference = 'Stop'
. $PSScriptRoot\Test-Template.ps1
-Test-Template "grpc" "grpc" "Microsoft.DotNet.Web.ProjectTemplates.7.0.7.0.0-dev.nupkg" $false
+Test-Template "grpc" "grpc" "Microsoft.DotNet.Web.ProjectTemplates.8.0.8.0.0-dev.nupkg" $false
diff --git a/src/ProjectTemplates/scripts/Test-Template.ps1 b/src/ProjectTemplates/scripts/Test-Template.ps1
index 2fe07cc5e2d4..fa06ad55a2a5 100644
--- a/src/ProjectTemplates/scripts/Test-Template.ps1
+++ b/src/ProjectTemplates/scripts/Test-Template.ps1
@@ -57,6 +57,8 @@ function Test-Template($templateName, $templateArgs, $templateNupkg, $isBlazorWa
true
+ False
+ false
'))
$projContent | Set-Content $projPath
}
@@ -67,8 +69,17 @@ function Test-Template($templateName, $templateArgs, $templateNupkg, $isBlazorWa
if ($templateArgs -match '-au') {
dotnet.exe ef migrations add Initial
}
- dotnet.exe publish --configuration Release
- Set-Location .\bin\Release\net8.0\publish
+
+ $publishOutputDir = ".\.publish";
+ dotnet.exe publish --configuration Release --output $publishOutputDir
+
+ if (Test-Path $publishOutputDir) {
+ Set-Location $publishOutputDir
+ }
+ else {
+ throw "Publish output directory could not be found";
+ }
+
if ($isBlazorWasm -eq $false) {
Invoke-Expression "./$templateName.exe"
}
diff --git a/src/ProjectTemplates/test/Templates.Tests/ApiTemplateTest.cs b/src/ProjectTemplates/test/Templates.Tests/ApiTemplateTest.cs
new file mode 100644
index 000000000000..319c7054207e
--- /dev/null
+++ b/src/ProjectTemplates/test/Templates.Tests/ApiTemplateTest.cs
@@ -0,0 +1,109 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using Microsoft.AspNetCore.Testing;
+using Templates.Test.Helpers;
+using Xunit.Abstractions;
+
+namespace Templates.Test;
+
+public class ApiTemplateTest : LoggedTest
+{
+ public ApiTemplateTest(ProjectFactoryFixture factoryFixture)
+ {
+ ProjectFactory = factoryFixture;
+ }
+
+ public ProjectFactoryFixture ProjectFactory { get; }
+
+ private ITestOutputHelper _output;
+ public ITestOutputHelper Output
+ {
+ get
+ {
+ if (_output == null)
+ {
+ _output = new TestOutputLogger(Logger);
+ }
+ return _output;
+ }
+ }
+
+ [ConditionalFact]
+ public async Task ApiTemplateCSharp()
+ {
+ await ApiTemplateCore(languageOverride: null);
+ }
+
+ [ConditionalFact(Skip = "Unskip when there are no more build or publish warnings for native AOT.")]
+ public async Task ApiTemplateNativeAotCSharp()
+ {
+ await ApiTemplateCore(languageOverride: null, args: new[] { ArgConstants.PublishNativeAot });
+ }
+
+ [ConditionalFact]
+ public async Task ApiTemplateProgramMainCSharp()
+ {
+ await ApiTemplateCore(languageOverride: null, args: new[] { ArgConstants.UseProgramMain });
+ }
+
+ [ConditionalFact(Skip = "Unskip when there are no more build or publish warnings for native AOT.")]
+ public async Task ApiTemplateProgramMainNativeAotCSharp()
+ {
+ await ApiTemplateCore(languageOverride: null, args: new[] { ArgConstants.UseProgramMain, ArgConstants.PublishNativeAot });
+ }
+
+ private async Task ApiTemplateCore(string languageOverride, string[] args = null)
+ {
+ var project = await ProjectFactory.CreateProject(Output);
+
+ await project.RunDotNetNewAsync("api", args: args, language: languageOverride);
+
+ var nativeAot = args?.Contains(ArgConstants.PublishNativeAot) ?? false;
+ var expectedLaunchProfileNames = nativeAot
+ ? new[] { "http" }
+ : new[] { "http", "IIS Express" };
+ await project.VerifyLaunchSettings(expectedLaunchProfileNames);
+
+ // Avoid the F# compiler. See https://github.com/dotnet/aspnetcore/issues/14022
+ if (languageOverride != null)
+ {
+ return;
+ }
+
+ // Force a restore if native AOT so that RID-specific assets are restored
+ await project.RunDotNetPublishAsync(noRestore: !nativeAot);
+
+ // Run dotnet build after publish. The reason is that one uses Config = Debug and the other uses Config = Release
+ // The output from publish will go into bin/Release/netcoreappX.Y/publish and won't be affected by calling build
+ // later, while the opposite is not true.
+
+ await project.RunDotNetBuildAsync();
+
+ using (var aspNetProcess = project.StartBuiltProjectAsync())
+ {
+ Assert.False(
+ aspNetProcess.Process.HasExited,
+ ErrorMessages.GetFailedProcessMessageOrEmpty("Run built project", project, aspNetProcess.Process));
+
+ await AssertEndpoints(aspNetProcess);
+ }
+
+ using (var aspNetProcess = project.StartPublishedProjectAsync())
+ {
+ Assert.False(
+ aspNetProcess.Process.HasExited,
+ ErrorMessages.GetFailedProcessMessageOrEmpty("Run published project", project, aspNetProcess.Process));
+
+ await AssertEndpoints(aspNetProcess);
+ }
+ }
+
+ private async Task AssertEndpoints(AspNetProcess aspNetProcess)
+ {
+ await aspNetProcess.AssertOk("/todos");
+ await aspNetProcess.AssertOk("/todos/1");
+ await aspNetProcess.AssertNotFound("/todos/100");
+ await aspNetProcess.AssertNotFound("/");
+ }
+}
diff --git a/src/ProjectTemplates/test/Templates.Tests/template-baselines.json b/src/ProjectTemplates/test/Templates.Tests/template-baselines.json
index e751f7e95982..39cef80de61b 100644
--- a/src/ProjectTemplates/test/Templates.Tests/template-baselines.json
+++ b/src/ProjectTemplates/test/Templates.Tests/template-baselines.json
@@ -527,6 +527,48 @@
"AuthOption": "None"
}
},
+ "api": {
+ "Default": {
+ "Template": "api",
+ "Arguments": "new api",
+ "Files": [
+ "Todo.cs",
+ "Program.cs",
+ "Properties/launchSettings.json"
+ ],
+ "AuthOption": "None"
+ },
+ "NativeAot": {
+ "Template": "api",
+ "Arguments": "new api -aot",
+ "Files": [
+ "Todo.cs",
+ "Program.cs",
+ "Properties/launchSettings.json"
+ ],
+ "AuthOption": "None"
+ },
+ "ProgramMain": {
+ "Template": "api",
+ "Arguments": "new api --use-program-main",
+ "Files": [
+ "Todo.cs",
+ "Program.cs",
+ "Properties/launchSettings.json"
+ ],
+ "AuthOption": "None"
+ },
+ "ProgramMainNativeAot": {
+ "Template": "api",
+ "Arguments": "new api -aot --use-program-main",
+ "Files": [
+ "Todo.cs",
+ "Program.cs",
+ "Properties/launchSettings.json"
+ ],
+ "AuthOption": "None"
+ }
+ },
"webapi": {
"IndividualB2C": {
"Template": "webapi",