diff --git a/.editorconfig b/.editorconfig
index d7ec0b83dec420209faacdf4f75508d92fba411a..8583569cfc7d1f6bd53c294282fb9090735eb64e 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -208,7 +208,7 @@ dotnet_diagnostic.IDE0044.severity = warning
 dotnet_diagnostic.IDE0073.severity = warning
 file_header_template = Licensed to the .NET Foundation under one or more agreements.\nThe .NET Foundation licenses this file to you under the MIT license.
 
-[**/{test,samples,perf}/**.{cs,vb}]
+[{eng/tools/**.cs,**/{test,testassets,samples,Samples,perf,scripts}/**.cs}]
 # CA1018: Mark attributes with AttributeUsageAttribute
 dotnet_diagnostic.CA1018.severity = suggestion
 # CA1507: Use nameof to express symbol names
@@ -241,6 +241,10 @@ dotnet_diagnostic.CA1844.severity = suggestion
 dotnet_diagnostic.CA1845.severity = suggestion
 # CA1846: Prefer AsSpan over Substring
 dotnet_diagnostic.CA1846.severity = suggestion
+# CA1847: Use string.Contains(char) instead of string.Contains(string) with single characters
+dotnet_diagnostic.CA1847.severity = suggestion
+# CA2007: Consider calling ConfigureAwait on the awaited task
+dotnet_diagnostic.CA2007.severity = suggestion
 # CA2008: Do not create tasks without passing a TaskScheduler
 dotnet_diagnostic.CA2008.severity = suggestion
 # CA2012: Use ValueTask correctly
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/dotnetcli.host.json b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/dotnetcli.host.json
index 3c34f96f85e3a9cacb7a084e070f4281f297fe57..02abad32e7eb18e40f03f69d8f5022836d4ef1d5 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/dotnetcli.host.json
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/dotnetcli.host.json
@@ -85,6 +85,10 @@
     "CallsMicrosoftGraph": {
         "longName": "calls-graph",
         "shortName": ""
+    },
+    "UseProgramMain": {
+      "longName": "use-program-main",
+      "shortName": ""
     }
   },
   "usageExamples": [
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/ide.host.json b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/ide.host.json
index e891e5f2df9789b29cd84d065c37e6119482c9f8..947fd0caa52b18cccf1709a260058fe8c961bd52 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/ide.host.json
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/ide.host.json
@@ -43,6 +43,12 @@
       "useHttps": true
     }
   ],
+  "symbolInfo": [
+    {
+      "id": "UseProgramMain",
+      "isVisible": true
+    }
+  ],
   "disableHttpsSymbol": "NoHttps",
   "supportsDocker": true
 }
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/template.json b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/template.json
index 254598a9cfe2493e8536d3bfb2e2c2fdd9775fac..4b203fdd52b6770d9cdc1770d2da06373c0059f7 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/template.json
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/template.json
@@ -34,6 +34,21 @@
         "wwwroot/**"
       ],
       "modifiers": [
+        {
+          "condition": "(!UseProgramMain)",
+          "exclude": [
+            "Program.Main.cs"
+          ]
+        },
+        {
+          "condition": "(UseProgramMain)",
+          "exclude": [
+            "Program.cs"
+          ],
+          "rename": {
+            "Program.Main.cs": "Program.cs"
+          }
+        },
         {
           "condition": "(!IndividualLocalAuth || UseLocalDB)",
           "exclude": [
@@ -490,6 +505,13 @@
       "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."
     }
   },
   "primaryOutputs": [
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/Program.Main.cs b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/Program.Main.cs
new file mode 100644
index 0000000000000000000000000000000000000000..92eb45d80a910c5048bac031e5a0ff6f558f29c8
--- /dev/null
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/Program.Main.cs
@@ -0,0 +1,169 @@
+#if (OrganizationalAuth || IndividualB2CAuth)
+using Microsoft.AspNetCore.Authentication;
+using Microsoft.AspNetCore.Authentication.OpenIdConnect;
+using Microsoft.Identity.Web;
+using Microsoft.Identity.Web.UI;
+#endif
+#if (WindowsAuth)
+using Microsoft.AspNetCore.Authentication.Negotiate;
+#endif
+#if (OrganizationalAuth)
+#if (MultiOrgAuth)
+using Microsoft.AspNetCore.Authentication.OpenIdConnect;
+#endif
+using Microsoft.AspNetCore.Authorization;
+#endif
+using Microsoft.AspNetCore.Components;
+using Microsoft.AspNetCore.Components.Web;
+#if (IndividualLocalAuth)
+using Microsoft.AspNetCore.Components.Authorization;
+using Microsoft.AspNetCore.Identity;
+using Microsoft.AspNetCore.Identity.UI;
+#endif
+#if (OrganizationalAuth)
+using Microsoft.AspNetCore.Mvc.Authorization;
+#endif
+#if (IndividualLocalAuth)
+using Microsoft.EntityFrameworkCore;
+#endif
+#if (GenerateGraph)
+using Graph = Microsoft.Graph;
+#endif
+#if(MultiOrgAuth)
+using Microsoft.IdentityModel.Tokens;
+#endif
+#if (IndividualLocalAuth)
+using BlazorServerWeb_CSharp.Areas.Identity;
+#endif
+using BlazorServerWeb_CSharp.Data;
+
+namespace Company.WebApplication1;
+
+public class Program
+{
+    public static void Main(string[] args)
+    {
+        var builder = WebApplication.CreateBuilder(args);
+
+        // Add services to the container.
+        #if (IndividualLocalAuth)
+        var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found.");
+        builder.Services.AddDbContext<ApplicationDbContext>(options =>
+        #if (UseLocalDB)
+            options.UseSqlServer(connectionString));
+        #else
+            options.UseSqlite(connectionString));
+        #endif
+        builder.Services.AddDatabaseDeveloperPageExceptionFilter();
+        builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
+            .AddEntityFrameworkStores<ApplicationDbContext>();
+        #elif (OrganizationalAuth)
+        #if (GenerateApiOrGraph)
+        var initialScopes = builder.Configuration["DownstreamApi:Scopes"]?.Split(' ');
+
+        #endif
+        builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
+        #if (GenerateApiOrGraph)
+            .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"))
+                .EnableTokenAcquisitionToCallDownstreamApi(initialScopes)
+        #if (GenerateApi)
+                    .AddDownstreamWebApi("DownstreamApi", builder.Configuration.GetSection("DownstreamApi"))
+        #endif
+        #if (GenerateGraph)
+                    .AddMicrosoftGraph(builder.Configuration.GetSection("DownstreamApi"))
+        #endif
+                    .AddInMemoryTokenCaches();
+        #else
+            .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"));
+        #endif
+        #elif (IndividualB2CAuth)
+        #if (GenerateApi)
+        var initialScopes = builder.Configuration["DownstreamApi:Scopes"]?.Split(' ');
+
+        #endif
+        builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
+        #if (GenerateApi)
+            .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAdB2C"))
+                .EnableTokenAcquisitionToCallDownstreamApi(initialScopes)
+                    .AddDownstreamWebApi("DownstreamApi", builder.Configuration.GetSection("DownstreamApi"))
+                    .AddInMemoryTokenCaches();
+        #else
+            .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAdB2C"));
+        #endif
+        #endif
+        #if (OrganizationalAuth || IndividualB2CAuth)
+        builder.Services.AddControllersWithViews()
+            .AddMicrosoftIdentityUI();
+
+        builder.Services.AddAuthorization(options =>
+        {
+            // By default, all incoming requests will be authorized according to the default policy
+            options.FallbackPolicy = options.DefaultPolicy;
+        });
+
+        #elif (WindowsAuth)
+        builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme)
+        .AddNegotiate();
+
+        builder.Services.AddAuthorization(options =>
+        {
+            // By default, all incoming requests will be authorized according to the default policy.
+            options.FallbackPolicy = options.DefaultPolicy;
+        });
+
+        #endif
+        builder.Services.AddRazorPages();
+        #if (OrganizationalAuth || IndividualB2CAuth)
+        builder.Services.AddServerSideBlazor()
+            .AddMicrosoftIdentityConsentHandler();
+        #else
+        builder.Services.AddServerSideBlazor();
+        #endif
+        #if (IndividualLocalAuth)
+        builder.Services.AddScoped<AuthenticationStateProvider, RevalidatingIdentityAuthenticationStateProvider<IdentityUser>>();
+        #endif
+        builder.Services.AddSingleton<WeatherForecastService>();
+
+        var app = builder.Build();
+
+        // Configure the HTTP request pipeline.
+        #if (IndividualLocalAuth)
+        if (app.Environment.IsDevelopment())
+        {
+            app.UseMigrationsEndPoint();
+        }
+        else
+        #else
+        if (!app.Environment.IsDevelopment())
+        #endif
+        {
+            app.UseExceptionHandler("/Error");
+        #if (RequiresHttps)
+            // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
+            app.UseHsts();
+        }
+
+        app.UseHttpsRedirection();
+        #else
+        }
+
+        #endif
+
+        app.UseStaticFiles();
+
+        app.UseRouting();
+
+        #if (OrganizationalAuth || IndividualAuth || WindowsAuth)
+        app.UseAuthentication();
+        app.UseAuthorization();
+
+        #endif
+        #if (OrganizationalAuth || IndividualAuth)
+        app.MapControllers();
+        #endif
+        app.MapBlazorHub();
+        app.MapFallbackToPage("/_Host");
+
+        app.Run();
+    }
+}
\ No newline at end of file
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/dotnetcli.host.json b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/dotnetcli.host.json
index 93b2c5a3bc03932beb9f8251bd42b9240337302a..3d2007dc58684e2fa3d852ceeab7fdfe2c42f75e 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/dotnetcli.host.json
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/dotnetcli.host.json
@@ -95,6 +95,10 @@
     "CallsMicrosoftGraph": {
         "longName": "calls-graph",
         "shortName": ""
+    },
+    "UseProgramMain": {
+      "longName": "use-program-main",
+      "shortName": ""
     }
   }
 }
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/ide.host.json b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/ide.host.json
index 9005a4d171a3732fedadfc12b6fdb143b1030222..2ed03203a45728b2a7fbd80cb1870e127516b32d 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/ide.host.json
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/ide.host.json
@@ -47,6 +47,10 @@
         "text": "_Progressive Web Application"
       },
       "isVisible": "true"
+    },
+    {
+      "id": "UseProgramMain",
+      "isVisible": true
     }
   ]
 }
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/template.json b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/template.json
index cd44728a48949ef2fcf12764ffe39ba1e4deb17e..9b261b76d232e27e69eb953cf566bab646255910 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/template.json
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/template.json
@@ -94,6 +94,24 @@
             "Client/wwwroot/icon-512.png"
           ]
         },
+        {
+          "condition": "(!UseProgramMain)",
+          "exclude": [
+            "Server/Program.Main.cs",
+            "Client/Program.Main.cs"
+          ]
+        },
+        {
+          "condition": "(UseProgramMain)",
+          "exclude": [
+            "Server/Program.cs",
+            "Client/Program.cs"
+          ],
+          "rename": {
+            "Server/Program.Main.cs": "Server/Program.cs",
+            "Client/Program.Main.cs": "Client/Program.cs"
+          }
+        },
         {
           "condition": "(!IndividualLocalAuth || UseLocalDB)",
           "exclude": [
@@ -591,6 +609,13 @@
     "GenerateApiOrGraph": {
         "type": "computed",
         "value": "(GenerateApi || GenerateGraph)"
+    },
+    "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."
     }
   },
   "tags": {
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/Client/Program.Main.cs b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/Client/Program.Main.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8b870e5dc9d3232df639a5d5bd40c0243fb470d0
--- /dev/null
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/Client/Program.Main.cs
@@ -0,0 +1,69 @@
+using Microsoft.AspNetCore.Components.Web;
+#if (!NoAuth && Hosted)
+using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
+#endif
+using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
+#if (Hosted)
+using ComponentsWebAssembly_CSharp.Client;
+#else
+using ComponentsWebAssembly_CSharp;
+#endif
+
+namespace Company.WebApplication1;
+
+public class Program
+{
+    public static async Task Main(string[] args)
+    {
+        var builder = WebAssemblyHostBuilder.CreateDefault(args);
+        builder.RootComponents.Add<App>("#app");
+        builder.RootComponents.Add<HeadOutlet>("head::after");
+
+        #if (!Hosted || NoAuth)
+        builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
+        #else
+        builder.Services.AddHttpClient("ComponentsWebAssembly_CSharp.ServerAPI", client => client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress))
+            .AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();
+
+        // Supply HttpClient instances that include access tokens when making requests to the server project
+        builder.Services.AddScoped(sp => sp.GetRequiredService<IHttpClientFactory>().CreateClient("ComponentsWebAssembly_CSharp.ServerAPI"));
+        #endif
+        #if(!NoAuth)
+
+        #endif
+        #if (IndividualLocalAuth)
+            #if (Hosted)
+        builder.Services.AddApiAuthorization();
+            #else
+        builder.Services.AddOidcAuthentication(options =>
+        {
+            #if(MissingAuthority)
+            // Configure your authentication provider options here.
+            // For more information, see https://aka.ms/blazor-standalone-auth
+            #endif
+            builder.Configuration.Bind("Local", options.ProviderOptions);
+        });
+            #endif
+        #endif
+        #if (IndividualB2CAuth)
+        builder.Services.AddMsalAuthentication(options =>
+        {
+            builder.Configuration.Bind("AzureAdB2C", options.ProviderOptions.Authentication);
+        #if (Hosted)
+            options.ProviderOptions.DefaultAccessTokenScopes.Add("https://qualified.domain.name/api.id.uri/api-scope");
+        #endif
+        });
+        #endif
+        #if(OrganizationalAuth)
+        builder.Services.AddMsalAuthentication(options =>
+        {
+            builder.Configuration.Bind("AzureAd", options.ProviderOptions.Authentication);
+        #if (Hosted)
+            options.ProviderOptions.DefaultAccessTokenScopes.Add("api://api.id.uri/api-scope");
+        #endif
+        });
+        #endif
+
+        await builder.Build().RunAsync();
+    }
+}
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/Server/Program.Main.cs b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/Server/Program.Main.cs
new file mode 100644
index 0000000000000000000000000000000000000000..31835439cd28607e4f5603d90431e94334cacb2d
--- /dev/null
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/Server/Program.Main.cs
@@ -0,0 +1,125 @@
+#if (OrganizationalAuth || IndividualB2CAuth || IndividualLocalAuth)
+using Microsoft.AspNetCore.Authentication;
+#endif
+#if (OrganizationalAuth || IndividualB2CAuth)
+using Microsoft.AspNetCore.Authentication.JwtBearer;
+#endif
+using Microsoft.AspNetCore.ResponseCompression;
+#if (IndividualLocalAuth)
+using Microsoft.EntityFrameworkCore;
+#endif
+#if (GenerateGraph)
+using Graph = Microsoft.Graph;
+#endif
+#if (OrganizationalAuth || IndividualB2CAuth)
+using Microsoft.Identity.Web;
+#endif
+#if (IndividualLocalAuth)
+using ComponentsWebAssembly_CSharp.Server.Data;
+using ComponentsWebAssembly_CSharp.Server.Models;
+#endif
+
+namespace Company.WebApplication1;
+
+public class Program
+{
+    public static void Main(string[] args)
+    {
+        var builder = WebApplication.CreateBuilder(args);
+
+        // Add services to the container.
+        #if (IndividualLocalAuth)
+        var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found.");
+        builder.Services.AddDbContext<ApplicationDbContext>(options =>
+        #if (UseLocalDB)
+            options.UseSqlServer(connectionString));
+        #else
+            options.UseSqlite(connectionString));
+        #endif
+        builder.Services.AddDatabaseDeveloperPageExceptionFilter();
+
+        builder.Services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
+            .AddEntityFrameworkStores<ApplicationDbContext>();
+
+        builder.Services.AddIdentityServer()
+            .AddApiAuthorization<ApplicationUser, ApplicationDbContext>();
+
+        builder.Services.AddAuthentication()
+            .AddIdentityServerJwt();
+        #endif
+        #if (OrganizationalAuth)
+        builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
+        #if (GenerateApiOrGraph)
+            .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"))
+                .EnableTokenAcquisitionToCallDownstreamApi()
+        #if (GenerateApi)
+                    .AddDownstreamWebApi("DownstreamApi", builder.Configuration.GetSection("DownstreamApi"))
+        #endif
+        #if (GenerateGraph)
+                    .AddMicrosoftGraph(builder.Configuration.GetSection("DownstreamApi"))
+        #endif
+                    .AddInMemoryTokenCaches();
+        #else
+            .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"));
+        #endif
+        #elif (IndividualB2CAuth)
+        builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
+        #if (GenerateApi)
+            .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAdB2C"))
+                .EnableTokenAcquisitionToCallDownstreamApi()
+                    .AddDownstreamWebApi("DownstreamApi", builder.Configuration.GetSection("DownstreamApi"))
+                    .AddInMemoryTokenCaches();
+        #else
+            .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAdB2C"));
+        #endif
+        #endif
+
+        builder.Services.AddControllersWithViews();
+        builder.Services.AddRazorPages();
+
+        var app = builder.Build();
+
+        // Configure the HTTP request pipeline.
+        if (app.Environment.IsDevelopment())
+        {
+        #if (IndividualLocalAuth)
+            app.UseMigrationsEndPoint();
+        #endif
+            app.UseWebAssemblyDebugging();
+        }
+        else
+        {
+            app.UseExceptionHandler("/Error");
+        #if (RequiresHttps)
+            // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
+            app.UseHsts();
+        #endif
+        }
+
+        #if (RequiresHttps)
+        app.UseHttpsRedirection();
+
+        #endif
+        app.UseBlazorFrameworkFiles();
+        app.UseStaticFiles();
+
+        app.UseRouting();
+
+        #if (IndividualLocalAuth)
+        app.UseIdentityServer();
+        #endif
+        #if (OrganizationalAuth || IndividualAuth)
+        app.UseAuthentication();
+        #endif
+        #if (!NoAuth)
+        app.UseAuthorization();
+
+        #endif
+
+        app.MapRazorPages();
+        app.MapControllers();
+        app.MapFallbackToFile("index.html");
+
+        app.Run();
+    }
+}
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/dotnetcli.host.json b/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/dotnetcli.host.json
index d97858472b807514d1a7c5705d1fb5634f691673..6f4f4fb8936d4f1af7beba4d355a5b671dd011fd 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/dotnetcli.host.json
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/dotnetcli.host.json
@@ -27,6 +27,10 @@
     "NoHttps": {
       "longName": "no-https",
       "shortName": ""
+    },
+    "UseProgramMain": {
+      "longName": "use-program-main",
+      "shortName": ""
     }
   },
   "usageExamples": [
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/ide.host.json b/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/ide.host.json
index 751a95c5b2ff59107ebc97fb70824774418a0ba8..f30c4753e2a8b974c00c44ff8589b3f6c861834a 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/ide.host.json
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/ide.host.json
@@ -20,5 +20,11 @@
       "useHttps": true
     }
   ],
+  "symbolInfo": [
+    {
+      "id": "UseProgramMain",
+      "isVisible": true
+    }
+  ],
   "disableHttpsSymbol": "NoHttps"
 }
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/template.json b/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/template.json
index 3b7edb411a86669637dbd82c1236960d63d6a33f..c85130f420f930026749f0a87cb15e63091bc360 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/template.json
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/template.json
@@ -29,6 +29,21 @@
           "exclude": [
             "Properties/launchSettings.json"
           ]
+        },
+        {
+          "condition": "(!UseProgramMain)",
+          "exclude": [
+            "Program.Main.cs"
+          ]
+        },
+        {
+          "condition": "(UseProgramMain)",
+          "exclude": [
+            "Program.cs"
+          ],
+          "rename": {
+            "Program.Main.cs": "Program.cs"
+          }
         }
       ]
     }
@@ -156,6 +171,13 @@
       "datatype": "bool",
       "defaultValue": "false",
       "description": "Whether to turn off HTTPS. This option only applies if Individual, IndividualB2C, SingleOrg, or MultiOrg aren't used for --auth."
+    },
+    "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."
     }
   },
   "primaryOutputs": [
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/Program.Main.cs b/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/Program.Main.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6a106499828e08eb2ad5d0f665757a0266ad22ad
--- /dev/null
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/Program.Main.cs
@@ -0,0 +1,14 @@
+namespace Company.WebApplication1;
+
+public class Program
+{
+    public static void Main(string[] args)
+    {
+        var builder = WebApplication.CreateBuilder(args);
+        var app = builder.Build();
+
+        app.MapGet("/", () => "Hello World!");
+
+        app.Run();
+    }
+}
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/dotnetcli.host.json b/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/dotnetcli.host.json
index 684bc1e734f3bf56908c1d6ede0a49ade0519be5..ded3cbf35f232b0b77002c75e06b8c177b63aa23 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/dotnetcli.host.json
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/dotnetcli.host.json
@@ -14,6 +14,10 @@
     "ExcludeLaunchSettings": {
       "longName": "exclude-launch-settings",
       "shortName": ""
+    },
+    "UseProgramMain": {
+      "longName": "use-program-main",
+      "shortName": ""
     }
   },
   "usageExamples": [
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/ide.host.json b/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/ide.host.json
index 2cb41909519c551548e0f86ccbf68a0db4e7738c..5c3a869512fdcb137cf2820c63800851be04151b 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/ide.host.json
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/ide.host.json
@@ -2,5 +2,11 @@
   "$schema": "http://json.schemastore.org/vs-2017.3.host",
   "order": 500,
   "icon": "ide/gRPC.png",
-  "supportsDocker": true
+  "supportsDocker": true,
+  "symbolInfo": [
+    {
+      "id": "UseProgramMain",
+      "isVisible": true
+    }
+  ]
 }
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/template.json b/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/template.json
index 2fd14ec9251fe22d8b847b3eed7d646290bb7e61..fc4288d8738493e55d5e7cc3f7c0f03dd161fad7 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/template.json
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/template.json
@@ -26,6 +26,21 @@
           "exclude": [
             "Properties/launchSettings.json"
           ]
+        },
+        {
+          "condition": "(!UseProgramMain)",
+          "exclude": [
+            "Program.Main.cs"
+          ]
+        },
+        {
+          "condition": "(UseProgramMain)",
+          "exclude": [
+            "Program.cs"
+          ],
+          "rename": {
+            "Program.Main.cs": "Program.cs"
+          }
         }
       ]
     }
@@ -102,6 +117,13 @@
         "fallbackVariableName": "kestrelHttpsPortGenerated"
       },
       "replaces": "5001"
+    },
+    "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."
     }
   },
   "primaryOutputs": [
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/Program.Main.cs b/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/Program.Main.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ec1af1a7e9c636fc71117ca7b4cb8686f926220f
--- /dev/null
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/Program.Main.cs
@@ -0,0 +1,25 @@
+using GrpcService_CSharp.Services;
+
+namespace Company.WebApplication1;
+
+public class Program
+{
+    public static void Main(string[] args)
+    {
+        var builder = WebApplication.CreateBuilder(args);
+
+        // Additional configuration is required to successfully run gRPC on macOS.
+        // For instructions on how to configure Kestrel and gRPC clients on macOS, visit https://go.microsoft.com/fwlink/?linkid=2099682
+
+        // Add services to the container.
+        builder.Services.AddGrpc();
+
+        var app = builder.Build();
+
+        // Configure the HTTP request pipeline.
+        app.MapGrpcService<GreeterService>();
+        app.MapGet("/", () => "Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909");
+
+        app.Run();
+    }
+}
\ No newline at end of file
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/dotnetcli.host.json b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/dotnetcli.host.json
index 6ce1fbe6eb27bd168daaec0ec5686f156a11286e..a00ae64f281e9524a4614b446377fc4fb090de45 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/dotnetcli.host.json
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/dotnetcli.host.json
@@ -85,6 +85,10 @@
     "CallsMicrosoftGraph": {
         "longName": "calls-graph",
         "shortName": ""
+    },
+    "UseProgramMain": {
+      "longName": "use-program-main",
+      "shortName": ""
     }
   },
   "usageExamples": [
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/ide.host.json b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/ide.host.json
index f176b8df2a9c6b452f48c804b5c98741f063007d..0dc542e09b82b34dcf1033f2af59f064806e471e 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/ide.host.json
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/ide.host.json
@@ -45,7 +45,10 @@
     }
   ],
   "symbolInfo": [
-    
+    {
+      "id": "UseProgramMain",
+      "isVisible": true
+    }
   ],
   "disableHttpsSymbol": "NoHttps"
 }
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/template.json b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/template.json
index d7226586d37dffd5bc7098bbdb0c41fa006a03bc..989dbb8ab86bd26ede7438da82696fe40f240682 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/template.json
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/template.json
@@ -94,6 +94,21 @@
           "exclude": [
             "Data/SqlServer/**"
           ]
+        },
+        {
+          "condition": "(!UseProgramMain)",
+          "exclude": [
+            "Program.Main.cs"
+          ]
+        },
+        {
+          "condition": "(UseProgramMain)",
+          "exclude": [
+            "Program.cs"
+          ],
+          "rename": {
+            "Program.Main.cs": "Program.cs"
+          }
         }
       ]
     }
@@ -406,6 +421,13 @@
     "GenerateApiOrGraph": {
         "type": "computed",
         "value": "(GenerateApi || GenerateGraph)"
+    },
+    "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."
     }
   },
   "primaryOutputs": [
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/Program.Main.cs b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/Program.Main.cs
new file mode 100644
index 0000000000000000000000000000000000000000..3a1a1d68cc066fe9140295b60d46e6e7de371386
--- /dev/null
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/Program.Main.cs
@@ -0,0 +1,155 @@
+#if (OrganizationalAuth || IndividualB2CAuth)
+using Microsoft.AspNetCore.Authentication;
+using Microsoft.AspNetCore.Authentication.OpenIdConnect;
+using Microsoft.AspNetCore.Authorization;
+#endif
+#if (WindowsAuth)
+using Microsoft.AspNetCore.Authentication.Negotiate;
+#endif
+#if (IndividualLocalAuth)
+using Microsoft.AspNetCore.Identity;
+#endif
+#if (OrganizationalAuth)
+using Microsoft.AspNetCore.Mvc.Authorization;
+#endif
+#if (IndividualLocalAuth)
+using Microsoft.EntityFrameworkCore;
+#endif
+#if (OrganizationalAuth || IndividualB2CAuth)
+using Microsoft.Identity.Web;
+using Microsoft.Identity.Web.UI;
+#endif
+#if (MultiOrgAuth)
+using Microsoft.IdentityModel.Tokens;
+#endif
+#if (GenerateGraph)
+using Graph = Microsoft.Graph;
+#endif
+#if (IndividualLocalAuth)
+using Company.WebApplication1.Data;
+#endif
+#if (OrganizationalAuth || IndividualB2CAuth || IndividualLocalAuth || MultiOrgAuth || GenerateGraph || WindowsAuth)
+
+#endif
+namespace Company.WebApplication1;
+
+public class Program
+{
+    public static void Main(string[] args)
+    {
+        var builder = WebApplication.CreateBuilder(args);
+
+        // Add services to the container.
+        #if (IndividualLocalAuth)
+        var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found.");
+        builder.Services.AddDbContext<ApplicationDbContext>(options =>
+        #if (UseLocalDB)
+            options.UseSqlServer(connectionString));
+        #else
+            options.UseSqlite(connectionString));
+        #endif
+        builder.Services.AddDatabaseDeveloperPageExceptionFilter();
+
+        builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
+            .AddEntityFrameworkStores<ApplicationDbContext>();
+        #elif (OrganizationalAuth)
+        #if (GenerateApiOrGraph)
+        var initialScopes = builder.Configuration["DownstreamApi:Scopes"]?.Split(' ');
+
+        #endif
+        builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
+        #if (GenerateApiOrGraph)
+            .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"))
+                .EnableTokenAcquisitionToCallDownstreamApi(initialScopes)
+        #if (GenerateApi)
+                    .AddDownstreamWebApi("DownstreamApi", builder.Configuration.GetSection("DownstreamApi"))
+        #endif
+        #if (GenerateGraph)
+                    .AddMicrosoftGraph(builder.Configuration.GetSection("DownstreamApi"))
+        #endif
+                    .AddInMemoryTokenCaches();
+        #else
+            .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"));
+        #endif
+        #elif (IndividualB2CAuth)
+        #if (GenerateApi)
+        var initialScopes = builder.Configuration["DownstreamApi:Scopes"]?.Split(' ');
+
+        #endif
+        builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
+        #if (GenerateApi)
+            .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAdB2C"))
+                .EnableTokenAcquisitionToCallDownstreamApi(initialScopes)
+                    .AddDownstreamWebApi("DownstreamApi", builder.Configuration.GetSection("DownstreamApi"))
+                    .AddInMemoryTokenCaches();
+        #else
+            .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAdB2C"));
+        #endif
+        #endif
+        #if (OrganizationalAuth)
+
+        builder.Services.AddAuthorization(options =>
+        {
+            // By default, all incoming requests will be authorized according to the default policy.
+            options.FallbackPolicy = options.DefaultPolicy;
+        });
+        builder.Services.AddRazorPages()
+            .AddMicrosoftIdentityUI();
+        #elif (IndividualB2CAuth)
+        builder.Services.AddRazorPages()
+            .AddMicrosoftIdentityUI();
+        #elif (WindowsAuth)
+
+        builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme)
+        .AddNegotiate();
+
+        builder.Services.AddAuthorization(options =>
+        {
+            // By default, all incoming requests will be authorized according to the default policy.
+            options.FallbackPolicy = options.DefaultPolicy;
+        });
+        builder.Services.AddRazorPages();
+        #else
+        builder.Services.AddRazorPages();
+        #endif
+
+        var app = builder.Build();
+
+        // Configure the HTTP request pipeline.
+        #if (IndividualLocalAuth)
+        if (app.Environment.IsDevelopment())
+        {
+            app.UseMigrationsEndPoint();
+        }
+        else
+        #else
+        if (!app.Environment.IsDevelopment())
+        #endif
+        {
+            app.UseExceptionHandler("/Error");
+        #if (RequiresHttps)
+            // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
+            app.UseHsts();
+        }
+
+        app.UseHttpsRedirection();
+        #else
+        }
+        #endif
+        app.UseStaticFiles();
+
+        app.UseRouting();
+
+        #if (OrganizationalAuth || IndividualAuth || WindowsAuth)
+        app.UseAuthentication();
+        #endif
+        app.UseAuthorization();
+
+        app.MapRazorPages();
+        #if (IndividualB2CAuth || OrganizationalAuth)
+        app.MapControllers();
+        #endif
+
+        app.Run();
+    }
+}
\ No newline at end of file
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/dotnetcli.host.json b/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/dotnetcli.host.json
index 3c34f96f85e3a9cacb7a084e070f4281f297fe57..02abad32e7eb18e40f03f69d8f5022836d4ef1d5 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/dotnetcli.host.json
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/dotnetcli.host.json
@@ -85,6 +85,10 @@
     "CallsMicrosoftGraph": {
         "longName": "calls-graph",
         "shortName": ""
+    },
+    "UseProgramMain": {
+      "longName": "use-program-main",
+      "shortName": ""
     }
   },
   "usageExamples": [
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/ide.host.json b/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/ide.host.json
index 12bb6ec5db17bba5f5b9d64cc90799469627e933..995a75bea9a06c1c95781a3f73ea7c2d289a4ed4 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/ide.host.json
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/ide.host.json
@@ -45,7 +45,10 @@
     }
   ],
   "symbolInfo": [
-    
+    {
+      "id": "UseProgramMain",
+      "isVisible": true
+    }
   ],
   "disableHttpsSymbol": "NoHttps"
 }
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/template.json b/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/template.json
index b67fe4f719ef4bc23bc3a8a3adbbb5d8b61c78c5..558a4e818d356ea307c9a917770b2be03f38e203 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/template.json
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/template.json
@@ -90,6 +90,21 @@
           "exclude": [
             "Data/SqlServer/**"
           ]
+        },
+        {
+          "condition": "(!UseProgramMain)",
+          "exclude": [
+            "Program.Main.cs"
+          ]
+        },
+        {
+          "condition": "(UseProgramMain)",
+          "exclude": [
+            "Program.cs"
+          ],
+          "rename": {
+            "Program.Main.cs": "Program.cs"
+          }
         }
       ]
     }
@@ -402,6 +417,13 @@
     "GenerateApiOrGraph": {
         "type": "computed",
         "value": "(GenerateApi || GenerateGraph)"
+    },
+    "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."
     }
   },
   "primaryOutputs": [
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/Program.Main.cs b/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/Program.Main.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5fda9092d06ac5a12394e824a953c6e35654cec5
--- /dev/null
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/Program.Main.cs
@@ -0,0 +1,159 @@
+#if (OrganizationalAuth || IndividualB2CAuth)
+using Microsoft.AspNetCore.Authentication;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Authentication.OpenIdConnect;
+#endif
+#if (WindowsAuth)
+using Microsoft.AspNetCore.Authentication.Negotiate;
+#endif
+#if (IndividualLocalAuth)
+using Microsoft.AspNetCore.Identity;
+#endif
+#if (OrganizationalAuth)
+using Microsoft.AspNetCore.Mvc.Authorization;
+#endif
+#if (IndividualLocalAuth)
+using Microsoft.EntityFrameworkCore;
+#endif
+#if (OrganizationalAuth || IndividualB2CAuth)
+using Microsoft.Identity.Web;
+using Microsoft.Identity.Web.UI;
+#endif
+#if (MultiOrgAuth)
+using Microsoft.IdentityModel.Tokens;
+#endif
+#if (GenerateGraph)
+using Graph = Microsoft.Graph;
+#endif
+#if (IndividualLocalAuth)
+using Company.WebApplication1.Data;
+#endif
+#if (OrganizationalAuth || IndividualB2CAuth || IndividualLocalAuth || MultiOrgAuth || GenerateGraph || WindowsAuth)
+
+#endif
+namespace Company.WebApplication1;
+
+public class Program
+{
+    public static void Main(string[] args)
+    {
+        var builder = WebApplication.CreateBuilder(args);
+
+        // Add services to the container.
+        #if (IndividualLocalAuth)
+        var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found.");
+        builder.Services.AddDbContext<ApplicationDbContext>(options =>
+        #if (UseLocalDB)
+            options.UseSqlServer(connectionString));
+        #else
+            options.UseSqlite(connectionString));
+        #endif
+        builder.Services.AddDatabaseDeveloperPageExceptionFilter();
+
+        builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
+            .AddEntityFrameworkStores<ApplicationDbContext>();
+        #elif (OrganizationalAuth)
+        #if (GenerateApiOrGraph)
+        var initialScopes = builder.Configuration["DownstreamApi:Scopes"]?.Split(' ');
+
+        #endif
+        builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
+        #if (GenerateApiOrGraph)
+            .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"))
+                .EnableTokenAcquisitionToCallDownstreamApi(initialScopes)
+        #if (GenerateApi)
+                    .AddDownstreamWebApi("DownstreamApi", builder.Configuration.GetSection("DownstreamApi"))
+        #endif
+        #if (GenerateGraph)
+                    .AddMicrosoftGraph(builder.Configuration.GetSection("DownstreamApi"))
+        #endif
+                    .AddInMemoryTokenCaches();
+        #else
+            .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"));
+        #endif
+        #elif (IndividualB2CAuth)
+        #if (GenerateApi)
+        var initialScopes = builder.Configuration["DownstreamApi:Scopes"]?.Split(' ');
+
+        #endif
+        builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
+        #if (GenerateApi)
+            .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAdB2C"))
+                .EnableTokenAcquisitionToCallDownstreamApi(initialScopes)
+                    .AddDownstreamWebApi("DownstreamApi", builder.Configuration.GetSection("DownstreamApi"))
+                    .AddInMemoryTokenCaches();
+        #else
+            .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAdB2C"));
+        #endif
+        #endif
+        #if (OrganizationalAuth)
+
+        builder.Services.AddControllersWithViews(options =>
+        {
+            var policy = new AuthorizationPolicyBuilder()
+                .RequireAuthenticatedUser()
+                .Build();
+            options.Filters.Add(new AuthorizeFilter(policy));
+        });
+        #else
+        builder.Services.AddControllersWithViews();
+        #endif
+        #if (OrganizationalAuth || IndividualB2CAuth)
+        builder.Services.AddRazorPages()
+            .AddMicrosoftIdentityUI();
+        #endif
+        #if (WindowsAuth)
+
+        builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme)
+        .AddNegotiate();
+
+        builder.Services.AddAuthorization(options =>
+        {
+            // By default, all incoming requests will be authorized according to the default policy.
+            options.FallbackPolicy = options.DefaultPolicy;
+        });
+        builder.Services.AddRazorPages();
+        #endif
+
+        var app = builder.Build();
+
+        // Configure the HTTP request pipeline.
+        #if (IndividualLocalAuth)
+        if (app.Environment.IsDevelopment())
+        {
+            app.UseMigrationsEndPoint();
+        }
+        else
+        #else
+        if (!app.Environment.IsDevelopment())
+        #endif
+        {
+            app.UseExceptionHandler("/Home/Error");
+        #if (RequiresHttps)
+            // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
+            app.UseHsts();
+        }
+
+        app.UseHttpsRedirection();
+        #else
+        }
+        #endif
+        app.UseStaticFiles();
+
+        app.UseRouting();
+
+        #if (OrganizationalAuth || IndividualAuth || WindowsAuth)
+        app.UseAuthentication();
+        #endif
+        app.UseAuthorization();
+
+        app.MapControllerRoute(
+            name: "default",
+            pattern: "{controller=Home}/{action=Index}/{id?}");
+        #if (OrganizationalAuth || IndividualAuth)
+        app.MapRazorPages();
+        #endif
+
+        app.Run();
+    }
+}
\ No newline at end of file
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/dotnetcli.host.json b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/dotnetcli.host.json
index 9b97a61820662f3e28b5b5f06229a614690cbce4..79217f16803f2aeecf881cf04945eae05479fd27 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/dotnetcli.host.json
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/dotnetcli.host.json
@@ -85,6 +85,10 @@
     "DisableOpenAPI": {
       "longName": "no-openapi",
       "shortName": ""
+    },
+    "UseProgramMain": {
+      "longName": "use-program-main",
+      "shortName": ""
     }
   },
   "usageExamples": [
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/ide.host.json b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/ide.host.json
index c8fdd64b6acd763a50dfd8d95c245db7af90231f..19355a4eecac6a8b6b924bf45845c6571fa287b1 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/ide.host.json
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/ide.host.json
@@ -55,6 +55,10 @@
       "invertBoolean": true,
       "isVisible": true,
       "defaultValue": true
+    },
+    {
+      "id": "UseProgramMain",
+      "isVisible": true
     }
   ],
   "disableHttpsSymbol": "NoHttps"
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/template.json b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/template.json
index ee1f9c886b38f98df927d323107596ae558f3912..5c9b53aedcd1519fb2fd57ceffa6293e8a94556d 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/template.json
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/template.json
@@ -37,6 +37,21 @@
             "Properties/launchSettings.json"
           ]
         },
+        {
+          "condition": "(!UseProgramMain)",
+          "exclude": [
+            "Program.Main.cs"
+          ]
+        },
+        {
+          "condition": "(UseProgramMain && !UseMinimalAPIs)",
+          "exclude": [
+            "Program.cs"
+          ],
+          "rename": {
+            "Program.Main.cs": "Program.cs"
+          }
+        },
         {
           "condition": "(UseMinimalAPIs)",
           "exclude": [
@@ -364,6 +379,13 @@
     "UseControllers": {
       "type": "computed",
       "value": "(!UseMinimalAPIs)"
+    },
+    "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."
     }
   },
   "primaryOutputs": [
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/Program.Main.cs b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/Program.Main.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a0c9ad67e817faff6c3ff1516284735d65d72813
--- /dev/null
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/Program.Main.cs
@@ -0,0 +1,95 @@
+#if (OrganizationalAuth || IndividualB2CAuth)
+using Microsoft.AspNetCore.Authentication;
+using Microsoft.AspNetCore.Authentication.JwtBearer;
+#endif
+#if (WindowsAuth)
+using Microsoft.AspNetCore.Authentication.Negotiate;
+#endif
+#if (GenerateGraph)
+using Graph = Microsoft.Graph;
+#endif
+#if (OrganizationalAuth || IndividualB2CAuth)
+using Microsoft.Identity.Web;
+#endif
+#if (OrganizationalAuth || IndividualB2CAuth || GenerateGraph || WindowsAuth)
+
+#endif
+namespace Company.WebApplication1;
+
+public class Program
+{
+    public static void Main(string[] args)
+    {
+    var builder = WebApplication.CreateBuilder(args);
+
+    // Add services to the container.
+    #if (OrganizationalAuth)
+    builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
+    #if (GenerateApiOrGraph)
+        .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"))
+            .EnableTokenAcquisitionToCallDownstreamApi()
+    #if (GenerateApi)
+                .AddDownstreamWebApi("DownstreamApi", builder.Configuration.GetSection("DownstreamApi"))
+    #endif
+    #if (GenerateGraph)
+                .AddMicrosoftGraph(builder.Configuration.GetSection("DownstreamApi"))
+    #endif
+                .AddInMemoryTokenCaches();
+    #else
+        .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"));
+    #endif
+    #elif (IndividualB2CAuth)
+    builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
+    #if (GenerateApi)
+        .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAdB2C"))
+            .EnableTokenAcquisitionToCallDownstreamApi()
+                .AddDownstreamWebApi("DownstreamApi", builder.Configuration.GetSection("DownstreamApi"))
+                .AddInMemoryTokenCaches();
+    #else
+        .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAdB2C"));
+    #endif
+    #endif
+
+    builder.Services.AddControllers();
+    #if (EnableOpenAPI)
+    // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
+    builder.Services.AddEndpointsApiExplorer();
+    builder.Services.AddSwaggerGen();
+    #endif
+    #if (WindowsAuth)
+
+    builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme)
+    .AddNegotiate();
+
+    builder.Services.AddAuthorization(options =>
+    {
+        // By default, all incoming requests will be authorized according to the default policy.
+        options.FallbackPolicy = options.DefaultPolicy;
+    });
+    #endif
+
+    var app = builder.Build();
+
+    // Configure the HTTP request pipeline.
+    #if (EnableOpenAPI)
+    if (app.Environment.IsDevelopment())
+    {
+        app.UseSwagger();
+        app.UseSwaggerUI();
+    }
+    #endif
+    #if (RequiresHttps)
+
+    app.UseHttpsRedirection();
+    #endif
+
+    #if (OrganizationalAuth || IndividualAuth || WindowsAuth)
+    app.UseAuthentication();
+    #endif
+    app.UseAuthorization();
+
+    app.MapControllers();
+
+    app.Run();
+    }
+}
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/dotnetcli.host.json b/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/dotnetcli.host.json
index b1cf98e39bb87b5088daac22bba7d10a2dfa866b..36493a3a4ac71fe862da45ad709884241eb4c190 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/dotnetcli.host.json
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/dotnetcli.host.json
@@ -11,6 +11,10 @@
     "ExcludeLaunchSettings": {
       "longName": "exclude-launch-settings",
       "shortName": ""
+    },
+    "UseProgramMain": {
+      "longName": "use-program-main",
+      "shortName": ""
     }
   },
   "usageExamples": [
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/ide.host.json b/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/ide.host.json
index 13a025d034fa03f52f8c8bc122b5841d22474a25..59f260a583df5b692057a862a61a2d8c02f12990 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/ide.host.json
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/ide.host.json
@@ -3,4 +3,10 @@
   "order": 300,
   "icon": "ide/Worker.png",
   "supportsDocker": true,
+  "symbolInfo": [
+    {
+      "id": "UseProgramMain",
+      "isVisible": true
+    }
+  ]
 }
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/template.json b/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/template.json
index 19358bf86a30e57244bf0bbb1ce6225fa371d5f2..d2789afed3ff7131dd80ac2e2850be01fc5fe878 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/template.json
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/template.json
@@ -30,6 +30,21 @@
           "exclude": [
             "Properties/launchSettings.json"
           ]
+        },
+        {
+          "condition": "(!UseProgramMain)",
+          "exclude": [
+            "Program.Main.cs"
+          ]
+        },
+        {
+          "condition": "(UseProgramMain)",
+          "exclude": [
+            "Program.cs"
+          ],
+          "rename": {
+            "Program.Main.cs": "Program.cs"
+          }
         }
       ]
     }
@@ -67,6 +82,13 @@
       "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."
     }
   },
   "primaryOutputs": [
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/Program.Main.cs b/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/Program.Main.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d69747f38d51aba1d6a3b7e618e2e014c3f6f10e
--- /dev/null
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/Program.Main.cs
@@ -0,0 +1,18 @@
+using Company.Application1;
+
+namespace Company.WebApplication1;
+
+public class Program
+{
+    public static void Main(string[] args)
+    {
+        IHost host = Host.CreateDefaultBuilder(args)
+            .ConfigureServices(services =>
+            {
+                services.AddHostedService<Worker>();
+            })
+            .Build();
+
+        host.Run();
+    }
+}
\ No newline at end of file
diff --git a/src/ProjectTemplates/scripts/Run-AngularProgramMain-Locally.ps1 b/src/ProjectTemplates/scripts/Run-AngularProgramMain-Locally.ps1
new file mode 100644
index 0000000000000000000000000000000000000000..93127bb08be03fbab39259e5eda5940c81d9ddfc
--- /dev/null
+++ b/src/ProjectTemplates/scripts/Run-AngularProgramMain-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 "angular" "angular --use-program-main" "Microsoft.DotNet.Web.Spa.ProjectTemplates.6.0.6.0.0-dev.nupkg" $false
diff --git a/src/ProjectTemplates/scripts/Run-BlazorProgramMain-Locally.ps1 b/src/ProjectTemplates/scripts/Run-BlazorProgramMain-Locally.ps1
new file mode 100644
index 0000000000000000000000000000000000000000..3d9fdd64a70dbb4bd9e5ac93ba2597d437b23392
--- /dev/null
+++ b/src/ProjectTemplates/scripts/Run-BlazorProgramMain-Locally.ps1
@@ -0,0 +1,13 @@
+#!/usr/bin/env pwsh
+#requires -version 4
+
+# This script packages, installs and creates a template to help with rapid iteration in the templating area.
+[CmdletBinding(PositionalBinding = $false)]
+param()
+
+Set-StrictMode -Version 2
+$ErrorActionPreference = 'Stop'
+
+. $PSScriptRoot\Test-Template.ps1
+
+Test-Template "blazorserver" "blazorserver --use-program-main" "Microsoft.DotNet.Web.ProjectTemplates.6.0.6.0.0-dev.nupkg" $false
diff --git a/src/ProjectTemplates/scripts/Run-BlazorWasmProgramMain-Locally.ps1 b/src/ProjectTemplates/scripts/Run-BlazorWasmProgramMain-Locally.ps1
new file mode 100644
index 0000000000000000000000000000000000000000..7c8755a8bba3a8e9ae38d2701851349bb908fc1d
--- /dev/null
+++ b/src/ProjectTemplates/scripts/Run-BlazorWasmProgramMain-Locally.ps1
@@ -0,0 +1,13 @@
+#!/usr/bin/env pwsh
+#requires -version 4
+
+# This script packages, installs and creates a template to help with rapid iteration in the templating area.
+[CmdletBinding(PositionalBinding = $false)]
+param()
+
+Set-StrictMode -Version 2
+$ErrorActionPreference = 'Stop'
+
+. $PSScriptRoot\Test-Template.ps1
+
+Test-Template "blazorwasm" "blazorwasm --use-program-main --hosted --auth Individual" "Microsoft.DotNet.Web.ProjectTemplates.6.0.6.0.0-dev.nupkg" $true
diff --git a/src/ProjectTemplates/scripts/Run-EmptyWebProgramMain-Locally.ps1 b/src/ProjectTemplates/scripts/Run-EmptyWebProgramMain-Locally.ps1
new file mode 100644
index 0000000000000000000000000000000000000000..7453063baf21c4757850aed57b1f3bd7ec7cc262
--- /dev/null
+++ b/src/ProjectTemplates/scripts/Run-EmptyWebProgramMain-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 "web" "web --use-program-main" "Microsoft.DotNet.Web.ProjectTemplates.6.0.6.0.0-dev.nupkg" $false
diff --git a/src/ProjectTemplates/scripts/Run-RazorProgramMain-Locally.ps1 b/src/ProjectTemplates/scripts/Run-RazorProgramMain-Locally.ps1
new file mode 100644
index 0000000000000000000000000000000000000000..4224cf985dd2873b91232b3483cfc795dab1a1e6
--- /dev/null
+++ b/src/ProjectTemplates/scripts/Run-RazorProgramMain-Locally.ps1
@@ -0,0 +1,9 @@
+#!/usr/bin/env powershell
+#requires -version 4
+
+[CmdletBinding(PositionalBinding = $false)]
+param()
+
+. $PSScriptRoot\Test-Template.ps1
+
+Test-Template "webapp" "webapp -au Individual --use-program-main" "Microsoft.DotNet.Web.ProjectTemplates.6.0.6.0.0-dev.nupkg" $false
diff --git a/src/ProjectTemplates/scripts/Run-ReactProgramMain-Locally.ps1 b/src/ProjectTemplates/scripts/Run-ReactProgramMain-Locally.ps1
new file mode 100644
index 0000000000000000000000000000000000000000..df61a5a117403cc0f168897b73d0fe2b242c7b56
--- /dev/null
+++ b/src/ProjectTemplates/scripts/Run-ReactProgramMain-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 "react" "react --use-program-main" "Microsoft.DotNet.Web.Spa.ProjectTemplates.6.0.6.0.0-dev.nupkg" $false
diff --git a/src/ProjectTemplates/scripts/Run-StarterwebProgramMain-Locally.ps1 b/src/ProjectTemplates/scripts/Run-StarterwebProgramMain-Locally.ps1
new file mode 100644
index 0000000000000000000000000000000000000000..076106d3e861714f1f96fec6baf0ff54d7a4d0e3
--- /dev/null
+++ b/src/ProjectTemplates/scripts/Run-StarterwebProgramMain-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 "mvc" "mvc -au Individual --use-program-main" "Microsoft.DotNet.Web.ProjectTemplates.6.0.6.0.0-dev.nupkg" $false
diff --git a/src/ProjectTemplates/scripts/Run-WebApiProgamMain-Locally.ps1 b/src/ProjectTemplates/scripts/Run-WebApiProgamMain-Locally.ps1
new file mode 100644
index 0000000000000000000000000000000000000000..41f794b7eaaf9958c39fa2cb0f6946b7ea1cb170
--- /dev/null
+++ b/src/ProjectTemplates/scripts/Run-WebApiProgamMain-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 "webapi" "webapi --use-program-main" "Microsoft.DotNet.Web.ProjectTemplates.6.0.6.0.0-dev.nupkg" $false
diff --git a/src/ProjectTemplates/scripts/Run-WorkerProgramMain-Locally.ps1 b/src/ProjectTemplates/scripts/Run-WorkerProgramMain-Locally.ps1
new file mode 100644
index 0000000000000000000000000000000000000000..9e0aa3d4607b24154a0ccaf42587a3911b5c666d
--- /dev/null
+++ b/src/ProjectTemplates/scripts/Run-WorkerProgramMain-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 "worker" "worker --use-program-main" "Microsoft.DotNet.Web.ProjectTemplates.6.0.6.0.0-dev.nupkg" $false
diff --git a/src/ProjectTemplates/scripts/Test-Template.ps1 b/src/ProjectTemplates/scripts/Test-Template.ps1
index 349174ad3d06207ac3eca1b98f07138ad63ea491..05cf0ef7128b244589f3826c92721e0cf94b8f95 100644
--- a/src/ProjectTemplates/scripts/Test-Template.ps1
+++ b/src/ProjectTemplates/scripts/Test-Template.ps1
@@ -64,7 +64,9 @@ function Test-Template($templateName, $templateArgs, $templateNupkg, $isBlazorWa
         if ($isBlazorWasmHosted) {
             Push-Location Server
         }
-        dotnet.exe ef migrations add mvc
+        if ($templateArgs -match '-au') {
+            dotnet.exe ef migrations add mvc
+        }
         dotnet.exe publish --configuration Release
         Set-Location .\bin\Release\net6.0\publish
         if ($isBlazorWasm -eq $false) {
diff --git a/src/ProjectTemplates/test/BlazorServerTemplateTest.cs b/src/ProjectTemplates/test/BlazorServerTemplateTest.cs
index 432c85043bd7e2e9656718f80f9713f4442b985b..104f2304020d79a616ef1a11ea3ee3fd90f3e620 100644
--- a/src/ProjectTemplates/test/BlazorServerTemplateTest.cs
+++ b/src/ProjectTemplates/test/BlazorServerTemplateTest.cs
@@ -26,18 +26,26 @@ namespace Templates.Test
         [Fact]
         public Task BlazorServerTemplateWorks_NoAuth() => CreateBuildPublishAsync("blazorservernoauth");
 
+        [Fact]
+        public Task BlazorServerTemplateWorks_ProgamMainNoAuth() => CreateBuildPublishAsync("blazorservernoauth", args: new [] { "--use-program-main" });
+
         [Theory]
-        [InlineData(true)]
-        [InlineData(false)]
+        [InlineData(true, null)]
+        [InlineData(true, new string[] { "--use-program-main" })]
+        [InlineData(false, null)]
+        [InlineData(false, new string[] { "--use-program-main" })]
         [SkipOnHelix("https://github.com/dotnet/aspnetcore/issues/30825", Queues = "All.OSX")]
-        public Task BlazorServerTemplateWorks_IndividualAuth(bool useLocalDB) => CreateBuildPublishAsync("blazorserverindividual" + (useLocalDB ? "uld" : ""));
+        public Task BlazorServerTemplateWorks_IndividualAuth(bool useLocalDB, string[] args) => CreateBuildPublishAsync("blazorserverindividual" + (useLocalDB ? "uld" : "", args: args));
 
         [Theory]
         [InlineData("IndividualB2C", null)]
         [InlineData("IndividualB2C", new string[] { "--called-api-url \"https://graph.microsoft.com\"", "--called-api-scopes user.readwrite" })]
+        [InlineData("IndividualB2C", new string[] { "--use-program-main", "--called-api-url \"https://graph.microsoft.com\"", "--called-api-scopes user.readwrite" })]
         [InlineData("SingleOrg", null)]
         [InlineData("SingleOrg", new string[] { "--called-api-url \"https://graph.microsoft.com\"", "--called-api-scopes user.readwrite" })]
+        [InlineData("SingleOrg", new string[] { "--use-program-main --called-api-url \"https://graph.microsoft.com\"", "--called-api-scopes user.readwrite" })]
         [InlineData("SingleOrg", new string[] { "--calls-graph" })]
+        [InlineData("SingleOrg", new string[] { "--use-program-main --calls-graph" })]
         public Task BlazorServerTemplate_IdentityWeb_BuildAndPublish(string auth, string[] args)
             => CreateBuildPublishAsync("blazorserveridweb" + Guid.NewGuid().ToString().Substring(0, 10).ToLowerInvariant(), auth, args);
 
diff --git a/src/ProjectTemplates/test/BlazorWasmTemplateTest.cs b/src/ProjectTemplates/test/BlazorWasmTemplateTest.cs
index 97a580dddd8b31584b719316b3c09a55f0781988..dae6148d213a85a640d4ff73b58921d60dce7f31 100644
--- a/src/ProjectTemplates/test/BlazorWasmTemplateTest.cs
+++ b/src/ProjectTemplates/test/BlazorWasmTemplateTest.cs
@@ -37,6 +37,9 @@ namespace Templates.Test
         [Fact]
         public Task BlazorWasmHostedTemplateCanCreateBuildPublish() => CreateBuildPublishAsync("blazorhosted", args: new[] { "--hosted" }, serverProject: true);
 
+        [Fact]
+        public Task BlazorWasmHostedTemplateWithProgamMainCanCreateBuildPublish() => CreateBuildPublishAsync("blazorhosted", args: new[] { "--use-program-main", "--hosted" }, serverProject: true);
+
         [Fact]
         public Task BlazorWasmStandalonePwaTemplateCanCreateBuildPublish() => CreateBuildPublishAsync("blazorstandalonepwa", args: new[] { "--pwa" });
 
diff --git a/src/ProjectTemplates/test/EmptyWebTemplateTest.cs b/src/ProjectTemplates/test/EmptyWebTemplateTest.cs
index e90ccbf5b94c305f1d50743f21e20d219bb7ac99..7468a587b41ed93b8c87cb0328c0961749f850a5 100644
--- a/src/ProjectTemplates/test/EmptyWebTemplateTest.cs
+++ b/src/ProjectTemplates/test/EmptyWebTemplateTest.cs
@@ -38,17 +38,24 @@ namespace Templates.Test
             await EmtpyTemplateCore(languageOverride: null);
         }
 
+        [ConditionalFact]
+        [SkipOnHelix("Cert failure, https://github.com/dotnet/aspnetcore/issues/28090", Queues = "All.OSX;" + HelixConstants.Windows10Arm64 + HelixConstants.DebianArm64)]
+        public async Task EmptyWebTemplateProgramMainCSharp()
+        {
+            await EmtpyTemplateCore(languageOverride: null, args: new [] { "--use-program-main" });
+        }
+
         [Fact]
         public async Task EmptyWebTemplateFSharp()
         {
             await EmtpyTemplateCore("F#");
         }
 
-        private async Task EmtpyTemplateCore(string languageOverride)
+        private async Task EmtpyTemplateCore(string languageOverride, string[] args = null)
         {
             var project = await ProjectFactory.GetOrCreateProject("empty" + (languageOverride == "F#" ? "fsharp" : "csharp"), Output);
 
-            var createResult = await project.RunDotNetNewAsync("web", language: languageOverride);
+            var createResult = await project.RunDotNetNewAsync("web", args: args, language: languageOverride);
             Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create/restore", project, createResult));
 
             // Avoid the F# compiler. See https://github.com/dotnet/aspnetcore/issues/14022
diff --git a/src/ProjectTemplates/test/GrpcTemplateTest.cs b/src/ProjectTemplates/test/GrpcTemplateTest.cs
index 585ac0bfb457b2f0a894953fd10d856fe147ef70..d26d0f8623a67c74648a360f299c523353dea6a0 100644
--- a/src/ProjectTemplates/test/GrpcTemplateTest.cs
+++ b/src/ProjectTemplates/test/GrpcTemplateTest.cs
@@ -34,14 +34,17 @@ namespace Templates.Test
             }
         }
 
-        [ConditionalFact]
+        [ConditionalTheory]
         [SkipOnHelix("Not supported queues", Queues = "All.OSX;" + HelixConstants.Windows10Arm64 + HelixConstants.DebianArm64)]
         [SkipOnAlpine("https://github.com/grpc/grpc/issues/18338")]
-        public async Task GrpcTemplate()
+        [InlineData(true)]
+        [InlineData(false)]
+        public async Task GrpcTemplate(bool useProgramMain)
         {
             var project = await ProjectFactory.GetOrCreateProject("grpc", Output);
 
-            var createResult = await project.RunDotNetNewAsync("grpc");
+            var args = useProgramMain ? new [] { "--use-program-main" } : null;
+            var createResult = await project.RunDotNetNewAsync("grpc", args: args);
             Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create/restore", project, createResult));
 
             var publishResult = await project.RunDotNetPublishAsync();
diff --git a/src/ProjectTemplates/test/MvcTemplateTest.cs b/src/ProjectTemplates/test/MvcTemplateTest.cs
index 47045d6972aa212f8fa0653a000e6dec0b2d81ae..a5d6bec3806603848d6eebf6486aeb0c0c4c44ba 100644
--- a/src/ProjectTemplates/test/MvcTemplateTest.cs
+++ b/src/ProjectTemplates/test/MvcTemplateTest.cs
@@ -43,11 +43,15 @@ namespace Templates.Test
         [SkipOnHelix("Cert failure, https://github.com/dotnet/aspnetcore/issues/28090", Queues = "All.OSX;" + HelixConstants.Windows10Arm64 + HelixConstants.DebianArm64)]
         public async Task MvcTemplate_NoAuthCSharp() => await MvcTemplateCore(languageOverride: null);
 
-        private async Task MvcTemplateCore(string languageOverride)
+        [ConditionalFact]
+        [SkipOnHelix("Cert failure, https://github.com/dotnet/aspnetcore/issues/28090", Queues = "All.OSX;" + HelixConstants.Windows10Arm64 + HelixConstants.DebianArm64)]
+        public async Task MvcTemplate_ProgramMainNoAuthCSharp() => await MvcTemplateCore(languageOverride: null, new [] { "--use-program-main" });
+
+        private async Task MvcTemplateCore(string languageOverride, string[] args = null)
         {
             var project = await ProjectFactory.GetOrCreateProject("mvcnoauth" + (languageOverride == "F#" ? "fsharp" : "csharp"), Output);
 
-            var createResult = await project.RunDotNetNewAsync("mvc", language: languageOverride);
+            var createResult = await project.RunDotNetNewAsync("mvc", language: languageOverride, args: args);
             Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create/restore", project, createResult));
 
             var projectExtension = languageOverride == "F#" ? "fsproj" : "csproj";
@@ -75,10 +79,10 @@ namespace Templates.Test
             Assert.True(0 == buildResult.ExitCode, ErrorMessages.GetFailedProcessMessage("build", project, buildResult));
 
             IEnumerable<string> menuLinks = new List<string> {
-                PageUrls.HomeUrl,
-                PageUrls.HomeUrl,
-                PageUrls.PrivacyFullUrl
-            };
+                    PageUrls.HomeUrl,
+                    PageUrls.HomeUrl,
+                    PageUrls.PrivacyFullUrl
+                };
 
             var footerLinks = new string[] { PageUrls.PrivacyFullUrl };
 
@@ -116,14 +120,17 @@ namespace Templates.Test
         }
 
         [ConditionalTheory]
-        [InlineData(true)]
-        [InlineData(false)]
+        [InlineData(true, false)]
+        [InlineData(true, true)]
+        [InlineData(false, false)]
+        [InlineData(false, true)]
         [SkipOnHelix("Cert failure, https://github.com/dotnet/aspnetcore/issues/28090", Queues = "All.OSX;" + HelixConstants.Windows10Arm64 + HelixConstants.DebianArm64)]
-        public async Task MvcTemplate_IndividualAuth(bool useLocalDB)
+        public async Task MvcTemplate_IndividualAuth(bool useLocalDB, bool useProgramMain)
         {
             var project = await ProjectFactory.GetOrCreateProject("mvcindividual" + (useLocalDB ? "uld" : ""), Output);
 
-            var createResult = await project.RunDotNetNewAsync("mvc", auth: "Individual", useLocalDB: useLocalDB);
+            var args = useProgramMain ? new [] { "--use-program-main" } : null;
+            var createResult = await project.RunDotNetNewAsync("mvc", auth: "Individual", useLocalDB: useLocalDB, args: args);
             Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create/restore", project, createResult));
 
             var projectFileContents = project.ReadFile($"{project.ProjectName}.csproj");
@@ -148,72 +155,72 @@ namespace Templates.Test
 
             // Note: if any links are updated here, RazorPagesTemplateTest.cs should be updated as well
             var pages = new List<Page> {
-                new Page
-                {
-                    Url = PageUrls.ForgotPassword,
-                    Links = new string [] {
-                        PageUrls.HomeUrl,
-                        PageUrls.HomeUrl,
-                        PageUrls.PrivacyUrl,
-                        PageUrls.RegisterUrl,
-                        PageUrls.LoginUrl,
-                        PageUrls.PrivacyUrl
-                    }
-                },
-                new Page
-                {
-                    Url = PageUrls.HomeUrl,
-                    Links = new string[] {
-                        PageUrls.HomeUrl,
-                        PageUrls.HomeUrl,
-                        PageUrls.PrivacyUrl,
-                        PageUrls.RegisterUrl,
-                        PageUrls.LoginUrl,
-                        PageUrls.DocsUrl,
-                        PageUrls.PrivacyUrl
-                    }
-                },
-                new Page
-                {
-                    Url = PageUrls.PrivacyFullUrl,
-                    Links = new string[] {
-                        PageUrls.HomeUrl,
-                        PageUrls.HomeUrl,
-                        PageUrls.PrivacyUrl,
-                        PageUrls.RegisterUrl,
-                        PageUrls.LoginUrl,
-                        PageUrls.PrivacyUrl
-                    }
-                },
-                new Page
-                {
-                    Url = PageUrls.LoginUrl,
-                    Links = new string[] {
-                        PageUrls.HomeUrl,
-                        PageUrls.HomeUrl,
-                        PageUrls.PrivacyUrl,
-                        PageUrls.RegisterUrl,
-                        PageUrls.LoginUrl,
-                        PageUrls.ForgotPassword,
-                        PageUrls.RegisterUrl,
-                        PageUrls.ResendEmailConfirmation,
-                        PageUrls.ExternalArticle,
-                        PageUrls.PrivacyUrl }
-                },
-                new Page
-                {
-                    Url = PageUrls.RegisterUrl,
-                    Links = new string [] {
-                        PageUrls.HomeUrl,
-                        PageUrls.HomeUrl,
-                        PageUrls.PrivacyUrl,
-                        PageUrls.RegisterUrl,
-                        PageUrls.LoginUrl,
-                        PageUrls.ExternalArticle,
-                        PageUrls.PrivacyUrl
+                    new Page
+                    {
+                        Url = PageUrls.ForgotPassword,
+                        Links = new string [] {
+                            PageUrls.HomeUrl,
+                            PageUrls.HomeUrl,
+                            PageUrls.PrivacyUrl,
+                            PageUrls.RegisterUrl,
+                            PageUrls.LoginUrl,
+                            PageUrls.PrivacyUrl
+                        }
+                    },
+                    new Page
+                    {
+                        Url = PageUrls.HomeUrl,
+                        Links = new string[] {
+                            PageUrls.HomeUrl,
+                            PageUrls.HomeUrl,
+                            PageUrls.PrivacyUrl,
+                            PageUrls.RegisterUrl,
+                            PageUrls.LoginUrl,
+                            PageUrls.DocsUrl,
+                            PageUrls.PrivacyUrl
+                        }
+                    },
+                    new Page
+                    {
+                        Url = PageUrls.PrivacyFullUrl,
+                        Links = new string[] {
+                            PageUrls.HomeUrl,
+                            PageUrls.HomeUrl,
+                            PageUrls.PrivacyUrl,
+                            PageUrls.RegisterUrl,
+                            PageUrls.LoginUrl,
+                            PageUrls.PrivacyUrl
+                        }
+                    },
+                    new Page
+                    {
+                        Url = PageUrls.LoginUrl,
+                        Links = new string[] {
+                            PageUrls.HomeUrl,
+                            PageUrls.HomeUrl,
+                            PageUrls.PrivacyUrl,
+                            PageUrls.RegisterUrl,
+                            PageUrls.LoginUrl,
+                            PageUrls.ForgotPassword,
+                            PageUrls.RegisterUrl,
+                            PageUrls.ResendEmailConfirmation,
+                            PageUrls.ExternalArticle,
+                            PageUrls.PrivacyUrl }
+                    },
+                    new Page
+                    {
+                        Url = PageUrls.RegisterUrl,
+                        Links = new string [] {
+                            PageUrls.HomeUrl,
+                            PageUrls.HomeUrl,
+                            PageUrls.PrivacyUrl,
+                            PageUrls.RegisterUrl,
+                            PageUrls.LoginUrl,
+                            PageUrls.ExternalArticle,
+                            PageUrls.PrivacyUrl
+                        }
                     }
-                }
-            };
+                };
 
             using (var aspNetProcess = project.StartBuiltProjectAsync())
             {
@@ -234,67 +241,44 @@ namespace Templates.Test
             }
         }
 
-        [ConditionalFact(Skip = "https://github.com/dotnet/aspnetcore/issues/25103")]
-        [SkipOnHelix("cert failure", Queues = "All.OSX")]
+        [ConditionalFact]
+        [OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX)] // Running these requires the rid-specific runtime pack to be available which is not consistent in all our platform builds.
+        [SkipOnHelix("cert failure", Queues = "All.OSX;" + HelixConstants.Windows10Arm64)]
         public async Task MvcTemplate_SingleFileExe()
         {
             // This test verifies publishing an MVC app as a single file exe works. We'll limit testing
             // this to a few operating systems to make our lives easier.
-            string runtimeIdentifer;
-            if (OperatingSystem.IsWindows())
-            {
-                runtimeIdentifer = "win-x64";
-            }
-            else if (OperatingSystem.IsLinux())
-            {
-                runtimeIdentifer = "linux-x64";
-            }
-            else
-            {
-                return;
-            }
-
+            var runtimeIdentifer = "win-x64";
             var project = await ProjectFactory.GetOrCreateProject("mvcsinglefileexe", Output);
             project.RuntimeIdentifier = runtimeIdentifer;
 
-            var createResult = await project.RunDotNetNewAsync("mvc", auth: "Individual", useLocalDB: true);
+            var createResult = await project.RunDotNetNewAsync("mvc");
             Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create/restore", project, createResult));
 
             var publishResult = await project.RunDotNetPublishAsync(additionalArgs: $"/p:PublishSingleFile=true -r {runtimeIdentifer}", noRestore: false);
             Assert.True(0 == publishResult.ExitCode, ErrorMessages.GetFailedProcessMessage("publish", project, publishResult));
 
-            var pages = new[]
+            var menuLinks = new[]
+            {
+                PageUrls.HomeUrl,
+                PageUrls.HomeUrl,            
+                PageUrls.PrivacyFullUrl
+            };
+
+            var footerLinks = new[] { PageUrls.PrivacyFullUrl };
+
+            var pages = new List<Page>
             {
                 new Page
                 {
-                    // Verify a view from the app works
                     Url = PageUrls.HomeUrl,
-                    Links = new []
-                    {
-                        PageUrls.HomeUrl,
-                        PageUrls.RegisterUrl,
-                        PageUrls.LoginUrl,
-                        PageUrls.HomeUrl,
-                        PageUrls.PrivacyUrl,
-                        PageUrls.DocsUrl,
-                        PageUrls.PrivacyUrl
-                    }
+                    Links = menuLinks.Append(PageUrls.DocsUrl).Concat(footerLinks),
                 },
                 new Page
                 {
-                    // Verify a view from a RCL (in this case IdentityUI) works
-                    Url = PageUrls.RegisterUrl,
-                    Links = new []
-                    {
-                        PageUrls.HomeUrl,
-                        PageUrls.RegisterUrl,
-                        PageUrls.LoginUrl,
-                        PageUrls.HomeUrl,
-                        PageUrls.PrivacyUrl,
-                        PageUrls.ExternalArticle,
-                        PageUrls.PrivacyUrl
-                    }
-                },
+                    Url = PageUrls.PrivacyFullUrl,
+                    Links = menuLinks.Concat(footerLinks),
+                }
             };
 
             using var aspNetProcess = project.StartPublishedProjectAsync(usePublishedAppHost: true);
diff --git a/src/ProjectTemplates/test/RazorPagesTemplateTest.cs b/src/ProjectTemplates/test/RazorPagesTemplateTest.cs
index 1af0a68366ffc266a48504b1312268a08c49127d..3412233f5dd5ee56f1c576a07971771279f86019 100644
--- a/src/ProjectTemplates/test/RazorPagesTemplateTest.cs
+++ b/src/ProjectTemplates/test/RazorPagesTemplateTest.cs
@@ -34,13 +34,16 @@ namespace Templates.Test
             }
         }
 
-        [ConditionalFact]
+        [ConditionalTheory]
         [SkipOnHelix("Cert failure, https://github.com/dotnet/aspnetcore/issues/28090", Queues = "All.OSX;" + HelixConstants.Windows10Arm64 + HelixConstants.DebianArm64)]
-        public async Task RazorPagesTemplate_NoAuth()
+        [InlineData(true)]
+        [InlineData(false)]
+        public async Task RazorPagesTemplate_NoAuth(bool useProgramMain)
         {
             var project = await ProjectFactory.GetOrCreateProject("razorpagesnoauth", Output);
 
-            var createResult = await project.RunDotNetNewAsync("razor");
+            var args = useProgramMain ? new [] { "--use-program-main" } : null;
+            var createResult = await project.RunDotNetNewAsync("razor", args: args);
             Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("razor", project, createResult));
 
             var projectFileContents = ReadFile(project.TemplateOutputDir, $"{project.ProjectName}.csproj");
@@ -104,14 +107,17 @@ namespace Templates.Test
         }
 
         [ConditionalTheory]
-        [InlineData(false)]
-        [InlineData(true)]
+        [InlineData(false, false)]
+        [InlineData(false, true)]
+        [InlineData(true, false)]
+        [InlineData(true, true)]
         [SkipOnHelix("Cert failure, https://github.com/dotnet/aspnetcore/issues/28090", Queues = "All.OSX;" + HelixConstants.Windows10Arm64 + HelixConstants.DebianArm64)]
-        public async Task RazorPagesTemplate_IndividualAuth(bool useLocalDB)
+        public async Task RazorPagesTemplate_IndividualAuth(bool useLocalDB, bool useProgramMain)
         {
             var project = await ProjectFactory.GetOrCreateProject("razorpagesindividual" + (useLocalDB ? "uld" : ""), Output);
 
-            var createResult = await project.RunDotNetNewAsync("razor", auth: "Individual", useLocalDB: useLocalDB);
+            var args = useProgramMain ? new [] { "--use-program-main" } : null;
+            var createResult = await project.RunDotNetNewAsync("razor", auth: "Individual", useLocalDB: useLocalDB, args: args);
             Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create/restore", project, createResult));
 
             var projectFileContents = ReadFile(project.TemplateOutputDir, $"{project.ProjectName}.csproj");
@@ -226,12 +232,15 @@ namespace Templates.Test
         [SkipOnHelix("https://github.com/dotnet/aspnetcore/issues/28090", Queues = HelixConstants.Windows10Arm64 + HelixConstants.DebianArm64)]
         [InlineData("IndividualB2C", null)]
         [InlineData("IndividualB2C", new string[] { "--called-api-url \"https://graph.microsoft.com\"", "--called-api-scopes user.readwrite" })]
+        [InlineData("IndividualB2C", new string[] { "--use-program-main --called-api-url \"https://graph.microsoft.com\"", "--called-api-scopes user.readwrite" })]
         [InlineData("SingleOrg", null)]
         [InlineData("SingleOrg", new string[] { "--called-api-url \"https://graph.microsoft.com\"", "--called-api-scopes user.readwrite" })]
+        [InlineData("SingleOrg", new string[] { "--use-program-main --called-api-url \"https://graph.microsoft.com\"", "--called-api-scopes user.readwrite" })]
         public Task RazorPagesTemplate_IdentityWeb_BuildsAndPublishes(string auth, string[] args) => BuildAndPublishRazorPagesTemplate(auth: auth, args: args);
 
         [ConditionalTheory]
         [InlineData("SingleOrg", new string[] { "--calls-graph" })]
+        [InlineData("SingleOrg", new string[] { "--use-program-main --calls-graph" })]
         public Task RazorPagesTemplate_IdentityWeb_BuildsAndPublishes_WithSingleOrg(string auth, string[] args) => BuildAndPublishRazorPagesTemplate(auth: auth, args: args);
 
         private async Task<Project> BuildAndPublishRazorPagesTemplate(string auth, string[] args)
diff --git a/src/ProjectTemplates/test/WebApiTemplateTest.cs b/src/ProjectTemplates/test/WebApiTemplateTest.cs
index ddc6e185320e5a254c479d5d126fe760b51f3b8d..f727abcc92c0e830e040c7e0cffa6e0c804f5ed7 100644
--- a/src/ProjectTemplates/test/WebApiTemplateTest.cs
+++ b/src/ProjectTemplates/test/WebApiTemplateTest.cs
@@ -35,10 +35,15 @@ namespace Templates.Test
         [ConditionalTheory]
         [SkipOnHelix("https://github.com/dotnet/aspnetcore/issues/28090", Queues = HelixConstants.Windows10Arm64 + HelixConstants.DebianArm64)]
         [InlineData("IndividualB2C", null)]
+        [InlineData("IndividualB2C", new string[] { "--use-program-main" })]
         [InlineData("IndividualB2C", new string[] { "--called-api-url \"https://graph.microsoft.com\"", "--called-api-scopes user.readwrite" })]
+        [InlineData("IndividualB2C", new string[] { "--use-program-main --called-api-url \"https://graph.microsoft.com\"", "--called-api-scopes user.readwrite" })]
         [InlineData("SingleOrg", null)]
+        [InlineData("SingleOrg", new string[] { "--use-program-main" })]
         [InlineData("SingleOrg", new string[] { "--called-api-url \"https://graph.microsoft.com\"", "--called-api-scopes user.readwrite" })]
+        [InlineData("SingleOrg", new string[] { "--use-program-main --called-api-url \"https://graph.microsoft.com\"", "--called-api-scopes user.readwrite" })]
         [InlineData("SingleOrg", new string[] { "--calls-graph" })]
+        [InlineData("SingleOrg", new string[] { "--use-program-main --calls-graph" })]
         public Task WebApiTemplateCSharp_IdentityWeb_BuildsAndPublishes(string auth, string[] args) => PublishAndBuildWebApiTemplate(languageOverride: null, auth: auth, args: args);
 
         [Fact]
@@ -50,11 +55,18 @@ namespace Templates.Test
 
         [ConditionalFact]
         [SkipOnHelix("Cert failure, https://github.com/dotnet/aspnetcore/issues/28090", Queues = "All.OSX;" + HelixConstants.Windows10Arm64 + HelixConstants.DebianArm64)]
-        public async Task WebApiTemplateCSharp_WithoutOpenAPI()
+        public Task WebApiTemplateProgramMainCSharp() => WebApiTemplateCore(languageOverride: null, args: new [] { "--use-program-main" });
+
+        [ConditionalTheory]
+        [InlineData(false)]
+        [InlineData(true)]
+        [SkipOnHelix("Cert failure, https://github.com/dotnet/aspnetcore/issues/28090", Queues = "All.OSX;" + HelixConstants.Windows10Arm64 + HelixConstants.DebianArm64)]
+        public async Task WebApiTemplateCSharp_WithoutOpenAPI(bool useProgramMain)
         {
             var project = await FactoryFixture.GetOrCreateProject("webapinoopenapi", Output);
 
-            var createResult = await project.RunDotNetNewAsync("webapi", args: new[] { "--no-openapi" });
+            var args = useProgramMain ? new[] { "--use-program-main --no-openapi" } : new[] { "--no-openapi" };
+            var createResult = await project.RunDotNetNewAsync("webapi", args: args);
             Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create/restore", project, createResult));
 
             var buildResult = await project.RunDotNetBuildAsync();
@@ -68,7 +80,7 @@ namespace Templates.Test
             await aspNetProcess.AssertNotFound("swagger");
         }
 
-        private async Task<Project> PublishAndBuildWebApiTemplate(string languageOverride, string auth, string[] args)
+        private async Task<Project> PublishAndBuildWebApiTemplate(string languageOverride, string auth, string[] args = null)
         {
             var project = await FactoryFixture.GetOrCreateProject("webapi" + (languageOverride == "F#" ? "fsharp" : "csharp") + Guid.NewGuid().ToString().Substring(0, 10).ToLowerInvariant(), Output);
 
@@ -94,9 +106,9 @@ namespace Templates.Test
             return project;
         }
 
-        private async Task WebApiTemplateCore(string languageOverride)
+        private async Task WebApiTemplateCore(string languageOverride, string[] args = null)
         {
-            var project = await PublishAndBuildWebApiTemplate(languageOverride, null, null);
+            var project = await PublishAndBuildWebApiTemplate(languageOverride, null, args);
 
             // Avoid the F# compiler. See https://github.com/dotnet/aspnetcore/issues/14022
             if (languageOverride != null)
diff --git a/src/ProjectTemplates/test/WorkerTemplateTest.cs b/src/ProjectTemplates/test/WorkerTemplateTest.cs
index 80e67c18738ef989299851dccce831493a27445e..ba82b5073c0e9a89b9297814d4f033b8c344b4b7 100644
--- a/src/ProjectTemplates/test/WorkerTemplateTest.cs
+++ b/src/ProjectTemplates/test/WorkerTemplateTest.cs
@@ -32,16 +32,17 @@ namespace Templates.Test
 
         [ConditionalTheory]
         [OSSkipCondition(OperatingSystems.Linux, SkipReason = "https://github.com/dotnet/sdk/issues/12831")]
-        [InlineData("C#")]
-        [InlineData("F#")]
+        [InlineData("C#", null)]
+        [InlineData("C#", new string[] { "--use-program-main" })]
+        [InlineData("F#", null)]
         [QuarantinedTest("https://github.com/dotnet/aspnetcore/issues/25404")]
-        public async Task WorkerTemplateAsync(string language)
+        public async Task WorkerTemplateAsync(string language, string[] args)
         {
             var project = await ProjectFactory.GetOrCreateProject(
                 $"worker-{ language.ToLowerInvariant()[0] }sharp",
                 Output);
 
-            var createResult = await project.RunDotNetNewAsync("worker", language: language);
+            var createResult = await project.RunDotNetNewAsync("worker", language: language, args: args);
             Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create/restore", project, createResult));
 
             var publishResult = await project.RunDotNetPublishAsync();
diff --git a/src/submodules/spa-templates b/src/submodules/spa-templates
index 3d16ec44cf4bc171531cefb0a81ae72b8bf0c478..08a4e743ccec97c24aec8b7a719655f08e827d8e 160000
--- a/src/submodules/spa-templates
+++ b/src/submodules/spa-templates
@@ -1 +1 @@
-Subproject commit 3d16ec44cf4bc171531cefb0a81ae72b8bf0c478
+Subproject commit 08a4e743ccec97c24aec8b7a719655f08e827d8e