Browse Source

Update "empty" web project templates to use minimal hostinng and routing (#32003)

* Minimize EmptyWeb-CSharp project template

* Add UseDeveloperExceptionPage() back

* Minimize EmptyWeb-FSharp project template

* Add MinimalSampleFSharp

* upcast

* Fix tests

* Show WebApplicationBuilder

* _

* Update SDK to 6.0.100-preview.4.21222.6

* Fixes #32028: Investigate Template Baseline tests errors

Latest `dotnet new` doesn't work with relative path for `--debug:custom-hive`... Hence make it absolute
Also switched to using `--debug:disable-sdk-templates` to avoid potential conflict between SDK and tests installed templates.

Co-authored-by: David Karlaš <[email protected]>
Stephen Halter 4 years ago
parent
commit
90137b0336

+ 15 - 0
AspNetCore.sln

@@ -1626,6 +1626,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.SpaSer
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MinimalSample", "src\Http\samples\MinimalSample\MinimalSample.csproj", "{9647D8B7-4616-4E05-B258-BAD5CAEEDD38}"
 EndProject
+Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "MinimalSampleFSharp", "src\Http\samples\MinimalSampleFSharp\MinimalSampleFSharp.fsproj", "{11BE4471-6C3D-4758-881A-97B6A16F21F6}"
+EndProject
 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "HttpLogging", "HttpLogging", "{022B4B80-E813-4256-8034-11A68146F4EF}"
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.HttpLogging", "src\Middleware\HttpLogging\src\Microsoft.AspNetCore.HttpLogging.csproj", "{FF413F1C-A998-4FA2-823F-52AC0916B35C}"
@@ -7717,6 +7719,18 @@ Global
 		{9647D8B7-4616-4E05-B258-BAD5CAEEDD38}.Release|x64.Build.0 = Release|Any CPU
 		{9647D8B7-4616-4E05-B258-BAD5CAEEDD38}.Release|x86.ActiveCfg = Release|Any CPU
 		{9647D8B7-4616-4E05-B258-BAD5CAEEDD38}.Release|x86.Build.0 = Release|Any CPU
+		{11BE4471-6C3D-4758-881A-97B6A16F21F6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{11BE4471-6C3D-4758-881A-97B6A16F21F6}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{11BE4471-6C3D-4758-881A-97B6A16F21F6}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{11BE4471-6C3D-4758-881A-97B6A16F21F6}.Debug|x64.Build.0 = Debug|Any CPU
+		{11BE4471-6C3D-4758-881A-97B6A16F21F6}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{11BE4471-6C3D-4758-881A-97B6A16F21F6}.Debug|x86.Build.0 = Debug|Any CPU
+		{11BE4471-6C3D-4758-881A-97B6A16F21F6}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{11BE4471-6C3D-4758-881A-97B6A16F21F6}.Release|Any CPU.Build.0 = Release|Any CPU
+		{11BE4471-6C3D-4758-881A-97B6A16F21F6}.Release|x64.ActiveCfg = Release|Any CPU
+		{11BE4471-6C3D-4758-881A-97B6A16F21F6}.Release|x64.Build.0 = Release|Any CPU
+		{11BE4471-6C3D-4758-881A-97B6A16F21F6}.Release|x86.ActiveCfg = Release|Any CPU
+		{11BE4471-6C3D-4758-881A-97B6A16F21F6}.Release|x86.Build.0 = Release|Any CPU
 		{FF413F1C-A998-4FA2-823F-52AC0916B35C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{FF413F1C-A998-4FA2-823F-52AC0916B35C}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{FF413F1C-A998-4FA2-823F-52AC0916B35C}.Debug|x64.ActiveCfg = Debug|Any CPU
@@ -8558,6 +8572,7 @@ Global
 		{DF4637DA-5F07-4903-8461-4E2DAB235F3C} = {7F99E967-3DC1-4198-9D55-47CD9471D0B6}
 		{AAB50C64-39AA-4AED-8E9C-50D68E7751AD} = {7F99E967-3DC1-4198-9D55-47CD9471D0B6}
 		{9647D8B7-4616-4E05-B258-BAD5CAEEDD38} = {EB5E294B-9ED5-43BF-AFA9-1CD2327F3DC1}
+		{11BE4471-6C3D-4758-881A-97B6A16F21F6} = {EB5E294B-9ED5-43BF-AFA9-1CD2327F3DC1}
 		{022B4B80-E813-4256-8034-11A68146F4EF} = {E5963C9F-20A6-4385-B364-814D2581FADF}
 		{FF413F1C-A998-4FA2-823F-52AC0916B35C} = {022B4B80-E813-4256-8034-11A68146F4EF}
 		{3A1EC883-EF9C-43E8-95E5-6B527428867B} = {022B4B80-E813-4256-8034-11A68146F4EF}

+ 2 - 2
global.json

@@ -1,9 +1,9 @@
 {
   "sdk": {
-    "version": "6.0.100-preview.4.21216.8"
+    "version": "6.0.100-preview.4.21222.6"
   },
   "tools": {
-    "dotnet": "6.0.100-preview.4.21216.8",
+    "dotnet": "6.0.100-preview.4.21222.6",
     "runtimes": {
       "dotnet/x64": [
         "2.1.25",

+ 1 - 0
src/Http/HttpAbstractions.slnf

@@ -36,6 +36,7 @@
       "src\\Http\\WebUtilities\\perf\\Microbenchmarks\\Microsoft.AspNetCore.WebUtilities.Microbenchmarks.csproj",
       "src\\Http\\WebUtilities\\src\\Microsoft.AspNetCore.WebUtilities.csproj",
       "src\\Http\\WebUtilities\\test\\Microsoft.AspNetCore.WebUtilities.Tests.csproj",
+      "src\\Http\\samples\\MinimalSampleFSharp\\MinimalSampleFSharp.fsproj",
       "src\\Http\\samples\\MinimalSample\\MinimalSample.csproj",
       "src\\Http\\samples\\SampleApp\\HttpAbstractions.SampleApp.csproj",
       "src\\Middleware\\CORS\\src\\Microsoft.AspNetCore.Cors.csproj",

+ 7 - 6
src/Http/samples/MinimalSample/Program.cs

@@ -1,10 +1,13 @@
 using System;
 using Microsoft.AspNetCore.Builder;
+using Microsoft.Extensions.Hosting;
 
-await using var app = WebApplication.Create();
+await using var app = WebApplication.Create(args);
 
-Todo EchoTodo(Todo todo) => todo;
-app.MapPost("/EchoTodo", (Func<Todo, Todo>)EchoTodo);
+if (app.Environment.IsDevelopment())
+{
+    app.UseDeveloperExceptionPage();
+}
 
 string Plaintext() => "Hello, World!";
 app.MapGet("/plaintext", (Func<string>)Plaintext);
@@ -12,9 +15,7 @@ app.MapGet("/plaintext", (Func<string>)Plaintext);
 object Json() => new { message = "Hello, World!" };
 app.MapGet("/json", (Func<object>)Json);
 
-string SayHello(string name) => $"Hello {name}";
+string SayHello(string name) => $"Hello, {name}!";
 app.MapGet("/hello/{name}", (Func<string, string>)SayHello);
 
 await app.RunAsync();
-
-record Todo(int Id, string Name, bool IsComplete);

+ 20 - 0
src/Http/samples/MinimalSampleFSharp/MinimalSampleFSharp.fsproj

@@ -0,0 +1,20 @@
+<Project Sdk="Microsoft.NET.Sdk.Web">
+
+  <PropertyGroup>
+    <TargetFramework>net6.0</TargetFramework>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <Compile Include="Program.fs" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <Reference Include="Microsoft.AspNetCore" />
+    <Reference Include="Microsoft.AspNetCore.Diagnostics" />
+    <Reference Include="Microsoft.AspNetCore.Hosting" />
+    <!-- Mvc.Core is referenced only for its attributes -->
+    <Reference Include="Microsoft.AspNetCore.Mvc.Core" />
+    <Reference Include="Microsoft.AspNetCore.Server.Kestrel" />
+  </ItemGroup>
+
+</Project>

+ 18 - 0
src/Http/samples/MinimalSampleFSharp/Program.fs

@@ -0,0 +1,18 @@
+open System
+open Microsoft.AspNetCore.Builder
+open Microsoft.Extensions.Hosting
+
+[<EntryPoint>]
+let main args =
+    use app = WebApplication.Create(args)
+
+    if app.Environment.IsDevelopment() then
+        app.UseDeveloperExceptionPage() |> ignore
+
+    app.MapGet("/plaintext", Func<string>(fun () -> "Hello, World!")) |> ignore
+    app.MapGet("/json", Func<_>(fun () -> {| message = "Hello, World!" |})) |> ignore
+    app.MapGet("/hello/{name}", Func<string, string>(fun name -> $"Hello, {name}!")) |> ignore
+
+    app.Run()
+
+    0 // Exit code

+ 13 - 0
src/Http/samples/MinimalSampleFSharp/Properties/launchSettings.json

@@ -0,0 +1,13 @@
+{
+  "profiles": {
+    "MinimalSampleFSharp": {
+      "commandName": "Project",
+      "dotnetRunMessages": "true",
+      "launchBrowser": true,
+      "applicationUrl": "https://localhost:5001;http://localhost:5000",
+      "environmentVariables": {
+        "ASPNETCORE_ENVIRONMENT": "Development"
+      }
+    }
+  }
+}

+ 9 - 0
src/Http/samples/MinimalSampleFSharp/appsettings.Development.json

@@ -0,0 +1,9 @@
+{
+  "Logging": {
+    "LogLevel": {
+      "Default": "Information",
+      "Microsoft": "Warning",
+      "Microsoft.Hosting.Lifetime": "Information"
+    }
+  }
+}

+ 10 - 0
src/Http/samples/MinimalSampleFSharp/appsettings.json

@@ -0,0 +1,10 @@
+{
+  "Logging": {
+    "LogLevel": {
+      "Default": "Information",
+      "Microsoft": "Warning",
+      "Microsoft.Hosting.Lifetime": "Information"
+    }
+  },
+  "AllowedHosts": "*"
+}

+ 2 - 2
src/ProjectTemplates/Shared/Project.cs

@@ -58,7 +58,7 @@ namespace Templates.Test.Helpers
             // Used to set special options in MSBuild
             IDictionary<string, string> environmentVariables = null)
         {
-            var hiveArg = $"--debug:custom-hive \"{TemplatePackageInstaller.CustomHivePath}\"";
+            var hiveArg = $" --debug:disable-sdk-templates --debug:custom-hive \"{TemplatePackageInstaller.CustomHivePath}\"";
             var argString = $"new {templateName} {hiveArg}";
             environmentVariables ??= new Dictionary<string, string>();
             if (!string.IsNullOrEmpty(auth))
@@ -323,7 +323,7 @@ namespace Templates.Test.Helpers
                     AppContext.BaseDirectory,
                     DotNetMuxer.MuxerPathOrDefault(),
                     arguments +
-                        $" --debug:custom-hive \"{TemplatePackageInstaller.CustomHivePath}\"" +
+                        $" --debug:disable-sdk-templates --debug:custom-hive \"{TemplatePackageInstaller.CustomHivePath}\"" +
                         $" -o {TemplateOutputDir}");
                 await result.Exited;
                 return result;

+ 11 - 49
src/ProjectTemplates/Shared/TemplatePackageInstaller.cs

@@ -43,11 +43,11 @@ namespace Templates.Test.Helpers
             "Microsoft.AspNetCore.Blazor.Templates",
         };
 
-        public static string CustomHivePath { get; } = (string.IsNullOrEmpty(Environment.GetEnvironmentVariable("helix")))
+        public static string CustomHivePath { get; } = Path.GetFullPath((string.IsNullOrEmpty(Environment.GetEnvironmentVariable("helix")))
                      ? typeof(TemplatePackageInstaller)
                          .Assembly.GetCustomAttributes<AssemblyMetadataAttribute>()
                          .Single(s => s.Key == "CustomTemplateHivePath").Value
-                     : Path.Combine("Hives", ".templateEngine");
+                     : Path.Combine("Hives", ".templateEngine"));
 
         public static async Task EnsureTemplatingEngineInitializedAsync(ITestOutputHelper output)
         {
@@ -78,7 +78,9 @@ namespace Templates.Test.Helpers
                 output,
                 AppContext.BaseDirectory,
                 DotNetMuxer.MuxerPathOrDefault(),
-                $"new {arguments} --debug:custom-hive \"{CustomHivePath}\"");
+                //--debug:disable-sdk-templates means, don't include C:\Program Files\dotnet\templates, aka. what comes with SDK, so we don't need to uninstall
+                //--debug:custom-hive means, don't install templates on CI/developer machine, instead create new temporary instance
+                $"new {arguments} --debug:disable-sdk-templates --debug:custom-hive \"{CustomHivePath}\"");
 
             await proc.Exited;
 
@@ -105,23 +107,12 @@ namespace Templates.Test.Helpers
 
             Assert.Equal(4, builtPackages.Length);
 
-            /*
-             * The templates are indexed by path, for example:
-              &USERPROFILE%\.templateengine\dotnetcli\v5.0.100-alpha1-013788\packages\nunit3.dotnetnew.template.1.6.1.nupkg
-                Templates:
-                    NUnit 3 Test Project (nunit) C#
-                    NUnit 3 Test Item (nunit-test) C#
-                    NUnit 3 Test Project (nunit) F#
-                    NUnit 3 Test Item (nunit-test) F#
-                    NUnit 3 Test Project (nunit) VB
-                    NUnit 3 Test Item (nunit-test) VB
-                Uninstall Command:
-                    dotnet new -u &USERPROFILE%\.templateengine\dotnetcli\v5.0.100-alpha1-013788\packages\nunit3.dotnetnew.template.1.6.1.nupkg
-
-             * We don't want to construct this path so we'll rely on dotnet new --uninstall --help to construct the uninstall command.
-             */
-            // Workaround for https://github.com/dotnet/sdk/issues/16906
-            // await UninstallExistingTemplatesAsync(output);
+            await VerifyCannotFindTemplateAsync(output, "web");
+            await VerifyCannotFindTemplateAsync(output, "webapp");
+            await VerifyCannotFindTemplateAsync(output, "mvc");
+            await VerifyCannotFindTemplateAsync(output, "react");
+            await VerifyCannotFindTemplateAsync(output, "reactredux");
+            await VerifyCannotFindTemplateAsync(output, "angular");
 
             foreach (var packagePath in builtPackages)
             {
@@ -135,35 +126,6 @@ namespace Templates.Test.Helpers
             await VerifyCanFindTemplate(output, "react");
         }
 
-        private static async Task UninstallExistingTemplatesAsync(ITestOutputHelper output)
-        {
-            var proc = await RunDotNetNew(output, "--uninstall --help");
-            var lines = proc.Output.Split(Environment.NewLine);
-
-            // Remove any previous or prebundled version of the template packages
-            foreach (var packageName in _templatePackages)
-            {
-                // Depending on the ordering, there may be multiple matches:
-                // Microsoft.DotNet.Web.Spa.ProjectTemplates.3.0.3.0.0-preview7.*.nupkg
-                // Microsoft.DotNet.Web.Spa.ProjectTemplates.3.0.0-preview7.*.nupkg
-                // Error on the side of caution and uninstall all of them
-                foreach (var command in lines.Where(l => l.Contains("dotnet new") && l.Contains(packageName, StringComparison.OrdinalIgnoreCase)))
-                {
-                    var uninstallCommand = command.TrimStart();
-                    Debug.Assert(uninstallCommand.StartsWith("dotnet new", StringComparison.Ordinal));
-                    uninstallCommand = uninstallCommand.Substring("dotnet new".Length);
-                    await RunDotNetNew(output, uninstallCommand);
-                }
-            }
-
-            await VerifyCannotFindTemplateAsync(output, "web");
-            await VerifyCannotFindTemplateAsync(output, "webapp");
-            await VerifyCannotFindTemplateAsync(output, "mvc");
-            await VerifyCannotFindTemplateAsync(output, "react");
-            await VerifyCannotFindTemplateAsync(output, "reactredux");
-            await VerifyCannotFindTemplateAsync(output, "angular");
-        }
-
         private static async Task VerifyCanFindTemplate(ITestOutputHelper output, string templateName)
         {
             var proc = await RunDotNetNew(output, $"");

+ 1 - 2
src/ProjectTemplates/Web.ProjectTemplates/EmptyWeb-FSharp.fsproj.in

@@ -1,4 +1,4 @@
-<Project Sdk="Microsoft.NET.Sdk.Web">
+<Project Sdk="Microsoft.NET.Sdk.Web">
 
   <PropertyGroup>
     <TargetFramework>${DefaultNetCoreTargetFramework}</TargetFramework>
@@ -7,7 +7,6 @@
   </PropertyGroup>
 
   <ItemGroup>
-    <Compile Include="Startup.fs" />
     <Compile Include="Program.fs" />
   </ItemGroup>
 

+ 10 - 21
src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/Program.cs

@@ -1,26 +1,15 @@
 using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
-using Microsoft.AspNetCore.Hosting;
-using Microsoft.Extensions.Configuration;
+using Microsoft.AspNetCore.Builder;
 using Microsoft.Extensions.Hosting;
-using Microsoft.Extensions.Logging;
 
-namespace Company.WebApplication1
-{
-    public class Program
-    {
-        public static void Main(string[] args)
-        {
-            CreateHostBuilder(args).Build().Run();
-        }
+var builder = WebApplication.CreateBuilder(args);
+await using var app = builder.Build();
 
-        public static IHostBuilder CreateHostBuilder(string[] args) =>
-            Host.CreateDefaultBuilder(args)
-                .ConfigureWebHostDefaults(webBuilder =>
-                {
-                    webBuilder.UseStartup<Startup>();
-                });
-    }
+if (app.Environment.IsDevelopment())
+{
+    app.UseDeveloperExceptionPage();
 }
+
+app.MapGet("/", (Func<string>)(() => "Hello World!"));
+
+await app.RunAsync();

+ 0 - 40
src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/Startup.cs

@@ -1,40 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
-using Microsoft.AspNetCore.Builder;
-using Microsoft.AspNetCore.Hosting;
-using Microsoft.AspNetCore.Http;
-using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.Hosting;
-
-namespace Company.WebApplication1
-{
-    public class Startup
-    {
-        // This method gets called by the runtime. Use this method to add services to the container.
-        // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
-        public void ConfigureServices(IServiceCollection services)
-        {
-        }
-
-        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
-        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
-        {
-            if (env.IsDevelopment())
-            {
-                app.UseDeveloperExceptionPage();
-            }
-
-            app.UseRouting();
-
-            app.UseEndpoints(endpoints =>
-            {
-                endpoints.MapGet("/", async context =>
-                {
-                    await context.Response.WriteAsync("Hello World!");
-                });
-            });
-        }
-    }
-}

+ 13 - 20
src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-FSharp/Program.fs

@@ -1,25 +1,18 @@
-namespace Company.WebApplication1
-
 open System
-open System.Collections.Generic
-open System.IO
-open System.Linq
-open System.Threading.Tasks
-open Microsoft.AspNetCore
-open Microsoft.AspNetCore.Hosting
-open Microsoft.Extensions.Configuration
+open Microsoft.AspNetCore.Builder
 open Microsoft.Extensions.Hosting
-open Microsoft.Extensions.Logging
 
-module Program =
-    let createHostBuilder args =
-        Host.CreateDefaultBuilder(args)
-            .ConfigureWebHostDefaults(fun webBuilder ->
-                webBuilder.UseStartup<Startup>() |> ignore
-            )
+[<EntryPoint>]
+let main args =
+    let builder = WebApplication.CreateBuilder(args)
+    use app = builder.Build()
+
+    if app.Environment.IsDevelopment() then
+        app.UseDeveloperExceptionPage() |> ignore
+
+    app.MapGet("/", Func<string>(fun () -> "Hello World!")) |> ignore
+
+    app.Run()
 
-    [<EntryPoint>]
-    let main args =
-        createHostBuilder(args).Build().Run()
+    0 // Exit code
 
-        0 // Exit code

+ 0 - 26
src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-FSharp/Startup.fs

@@ -1,26 +0,0 @@
-namespace Company.WebApplication1
-
-open System
-open Microsoft.AspNetCore.Builder
-open Microsoft.AspNetCore.Hosting
-open Microsoft.AspNetCore.Http
-open Microsoft.Extensions.DependencyInjection
-open Microsoft.Extensions.Hosting
-
-type Startup() =
-
-    // This method gets called by the runtime. Use this method to add services to the container.
-    // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
-    member _.ConfigureServices(services: IServiceCollection) =
-        ()
-
-    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
-    member _.Configure(app: IApplicationBuilder, env: IWebHostEnvironment) =
-        if env.IsDevelopment() then
-            app.UseDeveloperExceptionPage() |> ignore
-
-        app.UseRouting()
-           .UseEndpoints(fun endpoints ->
-                endpoints.MapGet("/", fun context ->
-                    context.Response.WriteAsync("Hello World!")) |> ignore
-            ) |> ignore

+ 0 - 2
src/ProjectTemplates/test/template-baselines.json

@@ -371,7 +371,6 @@
         "appsettings.Development.json",
         "appsettings.json",
         "Program.cs",
-        "Startup.cs",
         "Properties/launchSettings.json"
       ],
       "AuthOption": "None"
@@ -383,7 +382,6 @@
         "appsettings.Development.json",
         "appsettings.json",
         "Program.fs",
-        "Startup.fs",
         "Properties/launchSettings.json"
       ],
       "AuthOption": "None"