Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/dotnet/aspnetcore.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamian Edwards <damian@damianedwards.com>2022-03-28 21:13:57 +0300
committerDamian Edwards <damian@damianedwards.com>2022-03-30 02:55:43 +0300
commit73abf36fc06bcbe90960d20d63f97906adae22af (patch)
treedae9927cdf73ffa5e53a6115e5b45cab090dfbab
parent7eb15474ba995903ee9c8be0eb2b7a75b8813719 (diff)
Add option to project templates to use Program.Main instead of top-level statements (#40886)damianedwards/backport-UseProgramMain
Fixes #40944
-rw-r--r--.editorconfig6
-rw-r--r--src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/dotnetcli.host.json4
-rw-r--r--src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/ide.host.json6
-rw-r--r--src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/template.json22
-rw-r--r--src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/Program.Main.cs169
-rw-r--r--src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/dotnetcli.host.json4
-rw-r--r--src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/ide.host.json4
-rw-r--r--src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/template.json25
-rw-r--r--src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/Client/Program.Main.cs69
-rw-r--r--src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/Server/Program.Main.cs125
-rw-r--r--src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/dotnetcli.host.json4
-rw-r--r--src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/ide.host.json6
-rw-r--r--src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/template.json22
-rw-r--r--src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/Program.Main.cs14
-rw-r--r--src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/dotnetcli.host.json4
-rw-r--r--src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/ide.host.json8
-rw-r--r--src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/template.json22
-rw-r--r--src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/Program.Main.cs25
-rw-r--r--src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/dotnetcli.host.json4
-rw-r--r--src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/ide.host.json5
-rw-r--r--src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/template.json22
-rw-r--r--src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/Program.Main.cs155
-rw-r--r--src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/dotnetcli.host.json4
-rw-r--r--src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/ide.host.json5
-rw-r--r--src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/template.json22
-rw-r--r--src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/Program.Main.cs159
-rw-r--r--src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/dotnetcli.host.json4
-rw-r--r--src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/ide.host.json4
-rw-r--r--src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/template.json22
-rw-r--r--src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/Program.Main.cs95
-rw-r--r--src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/dotnetcli.host.json4
-rw-r--r--src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/ide.host.json6
-rw-r--r--src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/template.json22
-rw-r--r--src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/Program.Main.cs18
-rw-r--r--src/ProjectTemplates/scripts/Run-AngularProgramMain-Locally.ps112
-rw-r--r--src/ProjectTemplates/scripts/Run-BlazorProgramMain-Locally.ps113
-rw-r--r--src/ProjectTemplates/scripts/Run-BlazorWasmProgramMain-Locally.ps113
-rw-r--r--src/ProjectTemplates/scripts/Run-EmptyWebProgramMain-Locally.ps112
-rw-r--r--src/ProjectTemplates/scripts/Run-RazorProgramMain-Locally.ps19
-rw-r--r--src/ProjectTemplates/scripts/Run-ReactProgramMain-Locally.ps112
-rw-r--r--src/ProjectTemplates/scripts/Run-StarterwebProgramMain-Locally.ps112
-rw-r--r--src/ProjectTemplates/scripts/Run-WebApiProgamMain-Locally.ps112
-rw-r--r--src/ProjectTemplates/scripts/Run-WorkerProgramMain-Locally.ps112
-rw-r--r--src/ProjectTemplates/scripts/Test-Template.ps14
-rw-r--r--src/ProjectTemplates/test/BlazorServerTemplateTest.cs14
-rw-r--r--src/ProjectTemplates/test/BlazorWasmTemplateTest.cs3
-rw-r--r--src/ProjectTemplates/test/EmptyWebTemplateTest.cs11
-rw-r--r--src/ProjectTemplates/test/GrpcTemplateTest.cs9
-rw-r--r--src/ProjectTemplates/test/MvcTemplateTest.cs218
-rw-r--r--src/ProjectTemplates/test/RazorPagesTemplateTest.cs23
-rw-r--r--src/ProjectTemplates/test/WebApiTemplateTest.cs22
-rw-r--r--src/ProjectTemplates/test/WorkerTemplateTest.cs9
m---------src/submodules/googletest0
m---------src/submodules/spa-templates0
54 files changed, 1364 insertions, 146 deletions
diff --git a/.editorconfig b/.editorconfig
index d7ec0b83de..8583569cfc 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 3c34f96f85..02abad32e7 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 e891e5f2df..947fd0caa5 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 254598a9cf..4b203fdd52 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
@@ -35,6 +35,21 @@
],
"modifiers": [
{
+ "condition": "(!UseProgramMain)",
+ "exclude": [
+ "Program.Main.cs"
+ ]
+ },
+ {
+ "condition": "(UseProgramMain)",
+ "exclude": [
+ "Program.cs"
+ ],
+ "rename": {
+ "Program.Main.cs": "Program.cs"
+ }
+ },
+ {
"condition": "(!IndividualLocalAuth || UseLocalDB)",
"exclude": [
"app.db"
@@ -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 0000000000..92eb45d80a
--- /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 93b2c5a3bc..3d2007dc58 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 9005a4d171..2ed03203a4 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 cd44728a48..9b261b76d2 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
@@ -95,6 +95,24 @@
]
},
{
+ "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": [
"Server/app.db"
@@ -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 0000000000..8b870e5dc9
--- /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 0000000000..31835439cd
--- /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 d97858472b..6f4f4fb893 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 751a95c5b2..f30c4753e2 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 3b7edb411a..c85130f420 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 0000000000..6a10649982
--- /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 684bc1e734..ded3cbf35f 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 2cb4190951..5c3a869512 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 2fd14ec925..fc4288d873 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 0000000000..ec1af1a7e9
--- /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 6ce1fbe6eb..a00ae64f28 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 f176b8df2a..0dc542e09b 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 d7226586d3..989dbb8ab8 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 0000000000..3a1a1d68cc
--- /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 3c34f96f85..02abad32e7 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 12bb6ec5db..995a75bea9 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 b67fe4f719..558a4e818d 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 0000000000..5fda9092d0
--- /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 9b97a61820..79217f1680 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 c8fdd64b6a..19355a4eec 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 ee1f9c886b..5c9b53aedc 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
@@ -38,6 +38,21 @@
]
},
{
+ "condition": "(!UseProgramMain)",
+ "exclude": [
+ "Program.Main.cs"
+ ]
+ },
+ {
+ "condition": "(UseProgramMain && !UseMinimalAPIs)",
+ "exclude": [
+ "Program.cs"
+ ],
+ "rename": {
+ "Program.Main.cs": "Program.cs"
+ }
+ },
+ {
"condition": "(UseMinimalAPIs)",
"exclude": [
"Controllers/WeatherForecastController.cs",
@@ -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 0000000000..a0c9ad67e8
--- /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 b1cf98e39b..36493a3a4a 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 13a025d034..59f260a583 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 19358bf86a..d2789afed3 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 0000000000..d69747f38d
--- /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 0000000000..93127bb08b
--- /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 0000000000..3d9fdd64a7
--- /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 0000000000..7c8755a8bb
--- /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 0000000000..7453063baf
--- /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 0000000000..4224cf985d
--- /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 0000000000..df61a5a117
--- /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 0000000000..076106d3e8
--- /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 0000000000..41f794b7ea
--- /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 0000000000..9e0aa3d460
--- /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 349174ad3d..05cf0ef712 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 432c85043b..104f230402 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 97a580dddd..dae6148d21 100644
--- a/src/ProjectTemplates/test/BlazorWasmTemplateTest.cs
+++ b/src/ProjectTemplates/test/BlazorWasmTemplateTest.cs
@@ -38,6 +38,9 @@ namespace Templates.Test
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" });
[Fact]
diff --git a/src/ProjectTemplates/test/EmptyWebTemplateTest.cs b/src/ProjectTemplates/test/EmptyWebTemplateTest.cs
index e90ccbf5b9..7468a587b4 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 585ac0bfb4..d26d0f8623 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 47045d6972..a5d6bec380 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 1af0a68366..3412233f5d 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 ddc6e18532..f727abcc92 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 80e67c1873..ba82b5073c 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/googletest b/src/submodules/googletest
-Subproject c9461a9b55ba954df0489bab6420eb297bed846
+Subproject af29db7ec28d6df1c7f0f745186884091e602e0
diff --git a/src/submodules/spa-templates b/src/submodules/spa-templates
-Subproject 3d16ec44cf4bc171531cefb0a81ae72b8bf0c47
+Subproject 35fe7145d402a9519591e99edf20d6d3c7d091b