From 59678c1ef36f0ceb019a053cbffee26977dc6d1a Mon Sep 17 00:00:00 2001 From: DamianEdwards Date: Tue, 31 Aug 2021 18:32:07 -0700 Subject: [PATCH 1/6] Add minimal option to webapi template - Add "minimal" option to webapi project template - Factor Program.cs into multiple files and update template manifest to exclude/rename dependent on selected options - Updated controller and minimal versions to set endpoint/route name when EnableOpenAPI is true - Configure webapi template minimal option for VS display as "Use controllers" --- .../.template.config/dotnetcli.host.json | 4 + .../.template.config/ide.host.json | 9 ++ .../.template.config/template.json | 43 +++++ .../Controllers/WeatherForecastController.cs | 16 +- ...gram.MinimalAPIs.OrgOrIndividualB2CAuth.cs | 150 ++++++++++++++++++ .../Program.MinimalAPIs.WindowsOrNoAuth.cs | 57 +++++++ src/ProjectTemplates/scripts/.gitignore | 2 + .../scripts/Run-WebApiMinimal-Locally.ps1 | 12 ++ 8 files changed, 291 insertions(+), 2 deletions(-) create mode 100644 src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/Program.MinimalAPIs.OrgOrIndividualB2CAuth.cs create mode 100644 src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/Program.MinimalAPIs.WindowsOrNoAuth.cs create mode 100644 src/ProjectTemplates/scripts/Run-WebApiMinimal-Locally.ps1 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 382180645c81..9b97a6182066 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 @@ -4,6 +4,10 @@ "UseLocalDB": { "longName": "use-local-db" }, + "UseMinimalAPIs": { + "longName": "use-minimal-apis", + "shortName": "minimal" + }, "AADInstance": { "longName": "aad-instance", "shortName": "" 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 68310fc667ad..2b3113af4e3b 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 @@ -43,6 +43,15 @@ "invertBoolean": true, "isVisible": true, "defaultValue": true + }, + { + "id": "UseMinimalAPIs", + "name": { + "text": "Use controllers (uncheck to use minimal APIs)" + }, + "invertBoolean": true, + "isVisible": true, + "defaultValue": 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 ab893945383c..17c1aac54e5c 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 @@ -36,6 +36,39 @@ "exclude": [ "Properties/launchSettings.json" ] + }, + { + "condition": "(UseMinimalAPIs)", + "exclude": [ + "Controllers/WeatherForecastController.cs", + "Program.cs", + "WeatherForecast.cs" + ] + }, + { + "condition": "(UseMinimalAPIs && (NoAuth || WindowsAuth))", + "rename": { + "Program.MinimalAPIs.WindowsOrNoAuth.cs": "Program.cs" + }, + "exclude": [ + "Program.MinimalAPIs.OrgOrIndividualB2CAuth.cs" + ] + }, + { + "condition": "(UseMinimalAPIs && (IndividualAuth || OrganizationalAuth))", + "rename": { + "Program.MinimalAPIs.OrgOrIndividualB2CAuth.cs": "Program.cs" + }, + "exclude": [ + "Program.MinimalAPIs.WindowsOrNoAuth.cs" + ] + }, + { + "condition": "(UseControllers)", + "exclude": [ + "Program.MinimalAPIs.WindowsOrNoAuth.cs", + "Program.MinimalAPIs.OrgOrIndividualB2CAuth.cs" + ] } ] } @@ -254,6 +287,12 @@ "defaultValue": "false", "description": "Whether to use LocalDB instead of SQLite. This option only applies if --auth Individual or --auth IndividualB2C is specified." }, + "UseMinimalAPIs": { + "type": "parameter", + "datatype": "bool", + "defaultValue": "false", + "description": "Whether to use mininmal APIs instead of Controllers." + }, "Framework": { "type": "parameter", "description": "The target framework for the project.", @@ -321,6 +360,10 @@ "EnableOpenAPI": { "type": "computed", "value": "(!DisableOpenAPI)" + }, + "UseControllers": { + "type": "computed", + "value": "(!UseMinimalAPIs)" } }, "primaryOutputs": [ diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/Controllers/WeatherForecastController.cs b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/Controllers/WeatherForecastController.cs index da9c0b0e8eb7..545e1ba9365c 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/Controllers/WeatherForecastController.cs +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/Controllers/WeatherForecastController.cs @@ -40,11 +40,15 @@ public class WeatherForecastController : ControllerBase public WeatherForecastController(ILogger logger, IDownstreamWebApi downstreamWebApi) { - _logger = logger; + _logger = logger; _downstreamWebApi = downstreamWebApi; } +#if (EnableOpenAPI) + [HttpGet(Name = "GetWeatherForecast")] +#else [HttpGet] +#endif public async Task> Get() { using var response = await _downstreamWebApi.CallWebApiForUserAsync("DownstreamApi").ConfigureAwait(false); @@ -74,11 +78,15 @@ public async Task> Get() public WeatherForecastController(ILogger logger, GraphServiceClient graphServiceClient) { - _logger = logger; + _logger = logger; _graphServiceClient = graphServiceClient; } +#if (EnableOpenAPI) + [HttpGet(Name = "GetWeatherForecast")] +#else [HttpGet] +#endif public async Task> Get() { var user = await _graphServiceClient.Me.Request().GetAsync(); @@ -97,7 +105,11 @@ public WeatherForecastController(ILogger logger) _logger = logger; } +#if (EnableOpenAPI) + [HttpGet(Name = "GetWeatherForecast")] +#else [HttpGet] +#endif public IEnumerable Get() { return Enumerable.Range(1, 5).Select(index => new WeatherForecast diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/Program.MinimalAPIs.OrgOrIndividualB2CAuth.cs b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/Program.MinimalAPIs.OrgOrIndividualB2CAuth.cs new file mode 100644 index 000000000000..69aec233da02 --- /dev/null +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/Program.MinimalAPIs.OrgOrIndividualB2CAuth.cs @@ -0,0 +1,150 @@ +#if (GenerateApi) +using System.Net.Http; +#endif +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Authentication.JwtBearer; +#if (GenerateGraph) +using Graph = Microsoft.Graph; +#endif +using Microsoft.Identity.Web; +using Microsoft.Identity.Web.Resource; + +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.AddAuthorization(); + +#if (EnableOpenAPI) +builder.Services.AddEndpointsApiExplorer(); +builder.Services.AddSwaggerGen(); +#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 + +app.UseAuthentication(); +app.UseAuthorization(); + +var scopeRequiredByApi = app.Configuration["AzureAd:Scopes"]; +var summaries = new[] +{ + "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" +}; + +#if (GenerateApi) +app.MapGet("/weatherforecast", (HttpContext httpContext, IDownstreamWebApi downstreamWebApi) => +{ + httpContext.VerifyUserHasAnyAcceptedScope(scopeRequiredByApi); + + using var response = await downstreamWebApi.CallWebApiForUserAsync("DownstreamApi").ConfigureAwait(false); + if (response.StatusCode == System.Net.HttpStatusCode.OK) + { + var apiResult = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + // Do something + } + else + { + var error = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new HttpRequestException($"Invalid status code in the HttpResponseMessage: {response.StatusCode}: {error}"); + } + + var forecast = Enumerable.Range(1, 5).Select(index => new WeatherForecast + { + Date = DateTime.Now.AddDays(index), + TemperatureC = Random.Shared.Next(-20, 55), + Summary = summaries[Random.Shared.Next(summaries.Length)] + }) + .ToArray(); + + return forecast; +}) +#elseif (GenerateGraph) +app.MapGet("/weahterforecast", (HttpContext httpContext, GraphServiceClient graphServiceClient) => +{ + httpContext.VerifyUserHasAnyAcceptedScope(scopeRequiredByApi); + + var user = await _graphServiceClient.Me.Request().GetAsync(); + + var forecast = Enumerable.Range(1, 5).Select(index => new WeatherForecast + { + Date = DateTime.Now.AddDays(index), + TemperatureC = Random.Shared.Next(-20, 55), + Summary = summaries[Random.Shared.Next(summaries.Length)] + }) + .ToArray(); + + return forecast; +}) +#else +app.MapGet("/weatherforecast", (HttpContext httpContext) => +{ + httpContext.VerifyUserHasAnyAcceptedScope(scopeRequiredByApi); + + var forecast = Enumerable.Range(1, 5).Select(index => new WeatherForecast + { + Date = DateTime.Now.AddDays(index), + TemperatureC = Random.Shared.Next(-20, 55), + Summary = summaries[Random.Shared.Next(summaries.Length)] + }) + .ToArray(); + return forecast; +#endif +#if (EnableOpenAPI) +}) +.WithName("GetWeatherForecast") +.RequireAuthorization(); +#else +}) +.RequireAuthorization(); +#endif + +app.Run(); + +class WeatherForecast +{ + public DateTime Date { get; set; } + + public int TemperatureC { get; set; } + + public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); + + public string? Summary { get; set; } +} \ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/Program.MinimalAPIs.WindowsOrNoAuth.cs b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/Program.MinimalAPIs.WindowsOrNoAuth.cs new file mode 100644 index 000000000000..1b0ebfc92c46 --- /dev/null +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/Program.MinimalAPIs.WindowsOrNoAuth.cs @@ -0,0 +1,57 @@ +var builder = WebApplication.CreateBuilder(args); + +// Add services to the container. +#if (EnableOpenAPI) +builder.Services.AddEndpointsApiExplorer(); +builder.Services.AddSwaggerGen(); +#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 + +var summaries = new[] +{ + "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" +}; + +app.MapGet("/weatherforecast", () => +{ + var forecast = Enumerable.Range(1, 5).Select(index => new WeatherForecast + { + Date = DateTime.Now.AddDays(index), + TemperatureC = Random.Shared.Next(-20, 55), + Summary = summaries[Random.Shared.Next(summaries.Length)] + }) + .ToArray(); + return forecast; +#if (EnableOpenAPI) +}) +.WithName("GetWeatherForecast"); +#else +}); +#endif + +app.Run(); + +class WeatherForecast +{ + public DateTime Date { get; set; } + + public int TemperatureC { get; set; } + + public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); + + public string? Summary { get; set; } +} \ No newline at end of file diff --git a/src/ProjectTemplates/scripts/.gitignore b/src/ProjectTemplates/scripts/.gitignore index ceb08c3caee9..60f1c8f0fd54 100644 --- a/src/ProjectTemplates/scripts/.gitignore +++ b/src/ProjectTemplates/scripts/.gitignore @@ -5,11 +5,13 @@ angular/ blazorserver/ blazorwasm/ mvc/ +mvcorgauth/ razor/ react/ reactredux/ web/ webapp/ webapi/ +webapimin/ worker/ grpc/ \ No newline at end of file diff --git a/src/ProjectTemplates/scripts/Run-WebApiMinimal-Locally.ps1 b/src/ProjectTemplates/scripts/Run-WebApiMinimal-Locally.ps1 new file mode 100644 index 000000000000..19325a7c7eca --- /dev/null +++ b/src/ProjectTemplates/scripts/Run-WebApiMinimal-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 "webapimin" "webapi -minimal" "Microsoft.DotNet.Web.ProjectTemplates.6.0.6.0.0-dev.nupkg" $false From c83a507a00969464a3e9b9b15a6b30b47cb02d0b Mon Sep 17 00:00:00 2001 From: DamianEdwards Date: Wed, 1 Sep 2021 17:23:42 -0700 Subject: [PATCH 2/6] Update template baselines & fix casing of option description --- .../.template.config/template.json | 2 +- .../test/template-baselines.json | 44 +++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) 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 17c1aac54e5c..a4970ed06183 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 @@ -291,7 +291,7 @@ "type": "parameter", "datatype": "bool", "defaultValue": "false", - "description": "Whether to use mininmal APIs instead of Controllers." + "description": "Whether to use mininmal APIs instead of controllers." }, "Framework": { "type": "parameter", diff --git a/src/ProjectTemplates/test/template-baselines.json b/src/ProjectTemplates/test/template-baselines.json index 55a6d5731494..306b85f40227 100644 --- a/src/ProjectTemplates/test/template-baselines.json +++ b/src/ProjectTemplates/test/template-baselines.json @@ -567,6 +567,39 @@ ], "AuthOption": "None" }, + "MinimalIndividualB2C": { + "Template": "webapi", + "Arguments": "new webapi -au IndividualB2C --aad-b2c-instance https://login.microsoftonline.com/tfp/ --domain fake-b2c-domain.onmicrosoft.com --client-id 64f31f76-2750-49e4-aab9-f5de105b5172 -ssp B2C_1_SiUpIn -minimal", + "Files": [ + "appsettings.Development.json", + "appsettings.json", + "Program.cs", + "Properties/launchSettings.json" + ], + "AuthOption": "IndividualB2C" + }, + "MinimalSingleOrg": { + "Template": "webapi", + "Arguments": "new webapi -au SingleOrg --aad-instance https://login.microsoftonline.com/ --domain fake-aad-domain.onmicrosoft.com --client-id db33c356-12cc-4953-9167-00ad56c2e8b2 --tenant-id 7e511586-66ec-4108-bc9c-a68dee0dc2aa -minimal", + "Files": [ + "appsettings.Development.json", + "appsettings.json", + "Program.cs", + "Properties/launchSettings.json" + ], + "AuthOption": "SingleOrg" + }, + "Minimal": { + "Template": "webapi", + "Arguments": "new webapi -au None -minimal", + "Files": [ + "appsettings.Development.json", + "appsettings.json", + "Program.cs", + "Properties/launchSettings.json" + ], + "AuthOption": "None" + }, "Windows": { "Template": "webapi", "Arguments": "new webapi -au Windows", @@ -580,6 +613,17 @@ ], "AuthOption": "Windows" }, + "MinimalWindows": { + "Template": "webapi", + "Arguments": "new webapi -minimal -au Windows", + "Files": [ + "appsettings.Development.json", + "appsettings.json", + "Program.cs", + "Properties/launchSettings.json" + ], + "AuthOption": "Windows" + }, "FSharp": { "Template": "webapi", "Arguments": "new webapi --language F#", From e0690aee386088a5e0db53b7a5117289c386becf Mon Sep 17 00:00:00 2001 From: DamianEdwards Date: Thu, 2 Sep 2021 12:27:06 -0700 Subject: [PATCH 3/6] Fix template baseline tests issue --- .../Shared/TemplatePackageInstaller.cs | 2 ++ src/ProjectTemplates/test/BaselineTest.cs | 11 ++++++++--- src/ProjectTemplates/test/template-baselines.json | 6 +++--- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/ProjectTemplates/Shared/TemplatePackageInstaller.cs b/src/ProjectTemplates/Shared/TemplatePackageInstaller.cs index 20a2a00a8619..1a5db4033bfc 100644 --- a/src/ProjectTemplates/Shared/TemplatePackageInstaller.cs +++ b/src/ProjectTemplates/Shared/TemplatePackageInstaller.cs @@ -109,6 +109,7 @@ private static async Task InstallTemplatePackages(ITestOutputHelper output) await VerifyCannotFindTemplateAsync(output, "web"); await VerifyCannotFindTemplateAsync(output, "webapp"); + await VerifyCannotFindTemplateAsync(output, "webapi"); await VerifyCannotFindTemplateAsync(output, "mvc"); await VerifyCannotFindTemplateAsync(output, "react"); await VerifyCannotFindTemplateAsync(output, "reactredux"); @@ -123,6 +124,7 @@ private static async Task InstallTemplatePackages(ITestOutputHelper output) await VerifyCanFindTemplate(output, "webapp"); await VerifyCanFindTemplate(output, "web"); + await VerifyCanFindTemplate(output, "webapi"); await VerifyCanFindTemplate(output, "react"); } diff --git a/src/ProjectTemplates/test/BaselineTest.cs b/src/ProjectTemplates/test/BaselineTest.cs index 801b9b78582c..95cc01c142f3 100644 --- a/src/ProjectTemplates/test/BaselineTest.cs +++ b/src/ProjectTemplates/test/BaselineTest.cs @@ -51,11 +51,11 @@ public static TheoryData TemplateBaselines var data = new TheoryData(); foreach (var template in baseline) { - foreach (var authOption in (JObject)template.Value) + foreach (var scenarioName in (JObject)template.Value) { data.Add( - (string)authOption.Value["Arguments"], - ((JArray)authOption.Value["Files"]).Select(s => (string)s).ToArray()); + (string)scenarioName.Value["Arguments"], + ((JArray)scenarioName.Value["Files"]).Select(s => (string)s).ToArray()); } } @@ -144,6 +144,11 @@ private string SanitizeArgs(string arguments) text += "pwa"; } + if (arguments.Contains("-minimal")) + { + text += "Minimal"; + } + return text; } diff --git a/src/ProjectTemplates/test/template-baselines.json b/src/ProjectTemplates/test/template-baselines.json index 306b85f40227..f45c38609f61 100644 --- a/src/ProjectTemplates/test/template-baselines.json +++ b/src/ProjectTemplates/test/template-baselines.json @@ -569,7 +569,7 @@ }, "MinimalIndividualB2C": { "Template": "webapi", - "Arguments": "new webapi -au IndividualB2C --aad-b2c-instance https://login.microsoftonline.com/tfp/ --domain fake-b2c-domain.onmicrosoft.com --client-id 64f31f76-2750-49e4-aab9-f5de105b5172 -ssp B2C_1_SiUpIn -minimal", + "Arguments": "new webapi -minimal -au IndividualB2C --aad-b2c-instance https://login.microsoftonline.com/tfp/ --domain fake-b2c-domain.onmicrosoft.com --client-id 64f31f76-2750-49e4-aab9-f5de105b5172 -ssp B2C_1_SiUpIn", "Files": [ "appsettings.Development.json", "appsettings.json", @@ -580,7 +580,7 @@ }, "MinimalSingleOrg": { "Template": "webapi", - "Arguments": "new webapi -au SingleOrg --aad-instance https://login.microsoftonline.com/ --domain fake-aad-domain.onmicrosoft.com --client-id db33c356-12cc-4953-9167-00ad56c2e8b2 --tenant-id 7e511586-66ec-4108-bc9c-a68dee0dc2aa -minimal", + "Arguments": "new webapi -minimal -au SingleOrg --aad-instance https://login.microsoftonline.com/ --domain fake-aad-domain.onmicrosoft.com --client-id db33c356-12cc-4953-9167-00ad56c2e8b2 --tenant-id 7e511586-66ec-4108-bc9c-a68dee0dc2aa", "Files": [ "appsettings.Development.json", "appsettings.json", @@ -591,7 +591,7 @@ }, "Minimal": { "Template": "webapi", - "Arguments": "new webapi -au None -minimal", + "Arguments": "new webapi -minimal -au None", "Files": [ "appsettings.Development.json", "appsettings.json", From 585b02e68fd7784b2c4eeae8d08cfeeffd54b5ab Mon Sep 17 00:00:00 2001 From: DamianEdwards Date: Thu, 2 Sep 2021 13:34:46 -0700 Subject: [PATCH 4/6] Update template baseline test to be more resilient Made the template baseline test more resilient by ensuring that all template arg options without values are added to the project key rather than a specific few. Args that have a value are still not added to the key. Keys are all tracked now to ensure uniqueness & an exception is thrown if they aren't. Renamed a few things for better clarity and easy of debugging too. --- src/ProjectTemplates/test/BaselineTest.cs | 86 +++++++++++++---------- 1 file changed, 47 insertions(+), 39 deletions(-) diff --git a/src/ProjectTemplates/test/BaselineTest.cs b/src/ProjectTemplates/test/BaselineTest.cs index 95cc01c142f3..9aa402950423 100644 --- a/src/ProjectTemplates/test/BaselineTest.cs +++ b/src/ProjectTemplates/test/BaselineTest.cs @@ -2,9 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Collections.Concurrent; using System.IO; using System.Linq; -using System.Text.RegularExpressions; using System.Threading.Tasks; using Microsoft.AspNetCore.Testing; using Newtonsoft.Json; @@ -17,20 +17,7 @@ namespace Templates.Test { public class BaselineTest : LoggedTest { - private static readonly Regex TemplateNameRegex = new Regex( - "new (?