From 02299e43bbde87a8742e97db1e91e0253cf1808d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 14 Jul 2025 05:46:36 +0000 Subject: [PATCH 1/9] Initial plan From 23e48c6bcba1fd1b61da81b78d8d2b56bb905383 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 14 Jul 2025 05:55:53 +0000 Subject: [PATCH 2/9] Transform first 3 files from WebHostBuilder to HostBuilder pattern Co-authored-by: BrennanConroy <7574801+BrennanConroy@users.noreply.github.com> --- .../perf/benchmarkapps/BasicApi/Startup.cs | 21 ++++++++------ src/Mvc/samples/MvcSandbox/Startup.cs | 28 +++++++++++-------- src/Mvc/test/WebSites/BasicWebSite/Program.cs | 27 ++++++++++++------ .../test/WebSites/SimpleWebSite/Startup.cs | 19 ++++++++----- 4 files changed, 60 insertions(+), 35 deletions(-) diff --git a/src/Mvc/perf/benchmarkapps/BasicApi/Startup.cs b/src/Mvc/perf/benchmarkapps/BasicApi/Startup.cs index b1db2fa974fd..610267f8b813 100644 --- a/src/Mvc/perf/benchmarkapps/BasicApi/Startup.cs +++ b/src/Mvc/perf/benchmarkapps/BasicApi/Startup.cs @@ -11,6 +11,7 @@ using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Hosting; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; @@ -229,25 +230,29 @@ private void DropDatabaseTables(IServiceProvider services) public static void Main(string[] args) { - var host = CreateWebHostBuilder(args) + using var host = CreateHost(args) .Build(); host.Run(); } - public static IWebHostBuilder CreateWebHostBuilder(string[] args) + public static IHostBuilder CreateHost(string[] args) { var configuration = new ConfigurationBuilder() .AddEnvironmentVariables() .AddCommandLine(args) .Build(); - return new WebHostBuilder() - .UseKestrel() - .UseUrls("http://+:5000") - .UseConfiguration(configuration) - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseStartup(); + return new HostBuilder() + .ConfigureWebHost(webHostBuilder => + { + webHostBuilder + .UseKestrel() + .UseUrls("http://+:5000") + .UseConfiguration(configuration) + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseStartup(); + }); } } } diff --git a/src/Mvc/samples/MvcSandbox/Startup.cs b/src/Mvc/samples/MvcSandbox/Startup.cs index 2708a0c0b47c..c2deb5f84d4c 100644 --- a/src/Mvc/samples/MvcSandbox/Startup.cs +++ b/src/Mvc/samples/MvcSandbox/Startup.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using Microsoft.Extensions.Hosting; + namespace MvcSandbox; public class Startup @@ -42,22 +44,26 @@ static void ConfigureEndpoints(IEndpointRouteBuilder endpoints) public static void Main(string[] args) { - var host = CreateWebHostBuilder(args) + using var host = CreateHost(args) .Build(); host.Run(); } - public static IWebHostBuilder CreateWebHostBuilder(string[] args) => - new WebHostBuilder() - .UseContentRoot(Directory.GetCurrentDirectory()) - .ConfigureLogging(factory => + public static IHostBuilder CreateHost(string[] args) => + new HostBuilder() + .ConfigureWebHost(webHostBuilder => { - factory - .AddConsole() - .AddDebug(); - }) - .UseKestrel() - .UseStartup(); + webHostBuilder + .UseContentRoot(Directory.GetCurrentDirectory()) + .ConfigureLogging(factory => + { + factory + .AddConsole() + .AddDebug(); + }) + .UseKestrel() + .UseStartup(); + }); } diff --git a/src/Mvc/test/WebSites/BasicWebSite/Program.cs b/src/Mvc/test/WebSites/BasicWebSite/Program.cs index 2940ac16caec..3a577b7d6b0e 100644 --- a/src/Mvc/test/WebSites/BasicWebSite/Program.cs +++ b/src/Mvc/test/WebSites/BasicWebSite/Program.cs @@ -1,20 +1,29 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using Microsoft.Extensions.Hosting; + namespace BasicWebSite; public class Program { - public static void Main(string[] args) => CreateWebHostBuilder(args).Build().Run(); + public static void Main(string[] args) + { + using var host = CreateHost(args).Build(); + host.Run(); + } - // Do not change. This is the pattern our test infrastructure uses to initialize a IWebHostBuilder from - // a users app. - public static IWebHostBuilder CreateWebHostBuilder(string[] args) => - new WebHostBuilder() - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseStartup() - .UseKestrel() - .UseIISIntegration(); + // This method now returns IHostBuilder and uses the new pattern with HostBuilder and ConfigureWebHost + public static IHostBuilder CreateHost(string[] args) => + new HostBuilder() + .ConfigureWebHost(webHostBuilder => + { + webHostBuilder + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseStartup() + .UseKestrel() + .UseIISIntegration(); + }); } public class TestService diff --git a/src/Mvc/test/WebSites/SimpleWebSite/Startup.cs b/src/Mvc/test/WebSites/SimpleWebSite/Startup.cs index 5a87688449dd..dc5a7254680c 100644 --- a/src/Mvc/test/WebSites/SimpleWebSite/Startup.cs +++ b/src/Mvc/test/WebSites/SimpleWebSite/Startup.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using Microsoft.Extensions.Hosting; using Microsoft.Net.Http.Headers; using Newtonsoft.Json; @@ -29,17 +30,21 @@ public void Configure(IApplicationBuilder app) public static void Main(string[] args) { - var host = CreateWebHostBuilder(args) + using var host = CreateHost(args) .Build(); host.Run(); } - public static IWebHostBuilder CreateWebHostBuilder(string[] args) => - new WebHostBuilder() - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseStartup() - .UseKestrel() - .UseIISIntegration(); + public static IHostBuilder CreateHost(string[] args) => + new HostBuilder() + .ConfigureWebHost(webHostBuilder => + { + webHostBuilder + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseStartup() + .UseKestrel() + .UseIISIntegration(); + }); } From 531bb5f172d603778eb704524413681441d8d917 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 14 Jul 2025 05:59:46 +0000 Subject: [PATCH 3/9] Transform Program.cs files and benchmark apps from WebHostBuilder to HostBuilder Co-authored-by: BrennanConroy <7574801+BrennanConroy@users.noreply.github.com> --- .../perf/benchmarkapps/BasicViews/Startup.cs | 23 +++++++++++-------- .../benchmarkapps/RazorRendering/Startup.cs | 21 ++++++++++------- src/Mvc/test/WebSites/CorsWebSite/Program.cs | 20 ++++++++++------ src/Mvc/test/WebSites/FilesWebSite/Startup.cs | 20 ++++++++++------ .../test/WebSites/FormatterWebSite/Program.cs | 20 ++++++++++------ .../WebSites/RazorPagesWebSite/Program.cs | 20 ++++++++++------ src/Mvc/test/WebSites/RazorWebSite/Program.cs | 20 ++++++++++------ .../test/WebSites/RoutingWebSite/Program.cs | 20 ++++++++++------ .../test/WebSites/SecurityWebSite/Program.cs | 18 ++++++++++----- .../WebSites/VersioningWebSite/Program.cs | 20 ++++++++++------ 10 files changed, 130 insertions(+), 72 deletions(-) diff --git a/src/Mvc/perf/benchmarkapps/BasicViews/Startup.cs b/src/Mvc/perf/benchmarkapps/BasicViews/Startup.cs index cf4914be126c..131072630160 100644 --- a/src/Mvc/perf/benchmarkapps/BasicViews/Startup.cs +++ b/src/Mvc/perf/benchmarkapps/BasicViews/Startup.cs @@ -8,6 +8,7 @@ #endif using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Hosting; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; @@ -191,26 +192,30 @@ private void DropDatabaseTables(IServiceProvider services) public static void Main(string[] args) { - var host = CreateWebHostBuilder(args) + using var host = CreateHost(args) .Build(); host.Run(); } - public static IWebHostBuilder CreateWebHostBuilder(string[] args) + public static IHostBuilder CreateHost(string[] args) { var configuration = new ConfigurationBuilder() .AddEnvironmentVariables() .AddCommandLine(args) .Build(); - return new WebHostBuilder() - .UseKestrel() - .UseUrls("http://+:5000") - .UseConfiguration(configuration) - .UseIISIntegration() - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseStartup(); + return new HostBuilder() + .ConfigureWebHost(webHostBuilder => + { + webHostBuilder + .UseKestrel() + .UseUrls("http://+:5000") + .UseConfiguration(configuration) + .UseIISIntegration() + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseStartup(); + }); } } } diff --git a/src/Mvc/perf/benchmarkapps/RazorRendering/Startup.cs b/src/Mvc/perf/benchmarkapps/RazorRendering/Startup.cs index c332e9f2a8be..cc36aeaf08bb 100644 --- a/src/Mvc/perf/benchmarkapps/RazorRendering/Startup.cs +++ b/src/Mvc/perf/benchmarkapps/RazorRendering/Startup.cs @@ -4,6 +4,7 @@ using Data; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Hosting; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.DependencyInjection; using Microsoft.AspNetCore.Html; @@ -60,24 +61,28 @@ private static List GenerateDataB() public static void Main(string[] args) { - var host = CreateWebHostBuilder(args) + using var host = CreateHost(args) .Build(); host.Run(); } - public static IWebHostBuilder CreateWebHostBuilder(string[] args) + public static IHostBuilder CreateHost(string[] args) { var configuration = new ConfigurationBuilder() .AddEnvironmentVariables() .AddCommandLine(args) .Build(); - return new WebHostBuilder() - .UseKestrel() - .UseUrls("http://+:5000") - .UseConfiguration(configuration) - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseStartup(); + return new HostBuilder() + .ConfigureWebHost(webHostBuilder => + { + webHostBuilder + .UseKestrel() + .UseUrls("http://+:5000") + .UseConfiguration(configuration) + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseStartup(); + }); } } diff --git a/src/Mvc/test/WebSites/CorsWebSite/Program.cs b/src/Mvc/test/WebSites/CorsWebSite/Program.cs index d6bef8cec94e..1df67b56bf27 100644 --- a/src/Mvc/test/WebSites/CorsWebSite/Program.cs +++ b/src/Mvc/test/WebSites/CorsWebSite/Program.cs @@ -1,22 +1,28 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using Microsoft.Extensions.Hosting; + namespace CorsWebSite; public class Program { public static void Main(string[] args) { - var host = CreateWebHostBuilder(args) + using var host = CreateHost(args) .Build(); host.Run(); } - public static IWebHostBuilder CreateWebHostBuilder(string[] args) => - new WebHostBuilder() - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseStartup() - .UseKestrel() - .UseIISIntegration(); + public static IHostBuilder CreateHost(string[] args) => + new HostBuilder() + .ConfigureWebHost(webHostBuilder => + { + webHostBuilder + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseStartup() + .UseKestrel() + .UseIISIntegration(); + }); } diff --git a/src/Mvc/test/WebSites/FilesWebSite/Startup.cs b/src/Mvc/test/WebSites/FilesWebSite/Startup.cs index b2028da6904b..f75494beec23 100644 --- a/src/Mvc/test/WebSites/FilesWebSite/Startup.cs +++ b/src/Mvc/test/WebSites/FilesWebSite/Startup.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using Microsoft.Extensions.Hosting; + namespace FilesWebSite; public class Startup @@ -23,16 +25,20 @@ public void Configure(IApplicationBuilder app) public static void Main(string[] args) { - var host = CreateWebHostBuilder(args) + using var host = CreateHost(args) .Build(); host.Run(); } - public static IWebHostBuilder CreateWebHostBuilder(string[] args) => - new WebHostBuilder() - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseStartup() - .UseKestrel() - .UseIISIntegration(); + public static IHostBuilder CreateHost(string[] args) => + new HostBuilder() + .ConfigureWebHost(webHostBuilder => + { + webHostBuilder + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseStartup() + .UseKestrel() + .UseIISIntegration(); + }); } diff --git a/src/Mvc/test/WebSites/FormatterWebSite/Program.cs b/src/Mvc/test/WebSites/FormatterWebSite/Program.cs index 6235f2d3214f..a01042092c8c 100644 --- a/src/Mvc/test/WebSites/FormatterWebSite/Program.cs +++ b/src/Mvc/test/WebSites/FormatterWebSite/Program.cs @@ -1,22 +1,28 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using Microsoft.Extensions.Hosting; + namespace FormatterWebSite; public class Program { public static void Main(string[] args) { - var host = CreateWebHostBuilder(args) + using var host = CreateHost(args) .Build(); host.Run(); } - public static IWebHostBuilder CreateWebHostBuilder(string[] args) => - new WebHostBuilder() - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseStartup() - .UseKestrel() - .UseIISIntegration(); + public static IHostBuilder CreateHost(string[] args) => + new HostBuilder() + .ConfigureWebHost(webHostBuilder => + { + webHostBuilder + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseStartup() + .UseKestrel() + .UseIISIntegration(); + }); } diff --git a/src/Mvc/test/WebSites/RazorPagesWebSite/Program.cs b/src/Mvc/test/WebSites/RazorPagesWebSite/Program.cs index 8440222b2671..03ab394d37c2 100644 --- a/src/Mvc/test/WebSites/RazorPagesWebSite/Program.cs +++ b/src/Mvc/test/WebSites/RazorPagesWebSite/Program.cs @@ -1,22 +1,28 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using Microsoft.Extensions.Hosting; + namespace RazorPagesWebSite; public class Program { public static void Main(string[] args) { - var host = CreateWebHostBuilder(args) + using var host = CreateHost(args) .Build(); host.Run(); } - public static IWebHostBuilder CreateWebHostBuilder(string[] args) => - new WebHostBuilder() - .UseKestrel() - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseIISIntegration() - .UseStartup(); + public static IHostBuilder CreateHost(string[] args) => + new HostBuilder() + .ConfigureWebHost(webHostBuilder => + { + webHostBuilder + .UseKestrel() + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseIISIntegration() + .UseStartup(); + }); } diff --git a/src/Mvc/test/WebSites/RazorWebSite/Program.cs b/src/Mvc/test/WebSites/RazorWebSite/Program.cs index 63f000d9e68c..7bb070105754 100644 --- a/src/Mvc/test/WebSites/RazorWebSite/Program.cs +++ b/src/Mvc/test/WebSites/RazorWebSite/Program.cs @@ -1,22 +1,28 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using Microsoft.Extensions.Hosting; + namespace RazorWebSite; public class Program { public static void Main(string[] args) { - var host = CreateWebHostBuilder(args) + using var host = CreateHost(args) .Build(); host.Run(); } - public static IWebHostBuilder CreateWebHostBuilder(string[] args) => - new WebHostBuilder() - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseStartup() - .UseKestrel() - .UseIISIntegration(); + public static IHostBuilder CreateHost(string[] args) => + new HostBuilder() + .ConfigureWebHost(webHostBuilder => + { + webHostBuilder + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseStartup() + .UseKestrel() + .UseIISIntegration(); + }); } diff --git a/src/Mvc/test/WebSites/RoutingWebSite/Program.cs b/src/Mvc/test/WebSites/RoutingWebSite/Program.cs index e87a93791ee6..a2b63cbe5b56 100644 --- a/src/Mvc/test/WebSites/RoutingWebSite/Program.cs +++ b/src/Mvc/test/WebSites/RoutingWebSite/Program.cs @@ -1,22 +1,28 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using Microsoft.Extensions.Hosting; + namespace RoutingWebSite; public class Program { public static void Main(string[] args) { - var host = CreateWebHostBuilder(args) + using var host = CreateHost(args) .Build(); host.Run(); } - public static IWebHostBuilder CreateWebHostBuilder(string[] args) => - new WebHostBuilder() - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseStartup() - .UseKestrel() - .UseIISIntegration(); + public static IHostBuilder CreateHost(string[] args) => + new HostBuilder() + .ConfigureWebHost(webHostBuilder => + { + webHostBuilder + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseStartup() + .UseKestrel() + .UseIISIntegration(); + }); } diff --git a/src/Mvc/test/WebSites/SecurityWebSite/Program.cs b/src/Mvc/test/WebSites/SecurityWebSite/Program.cs index 9aaddc6b3c38..7025096edf94 100644 --- a/src/Mvc/test/WebSites/SecurityWebSite/Program.cs +++ b/src/Mvc/test/WebSites/SecurityWebSite/Program.cs @@ -1,21 +1,27 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using Microsoft.Extensions.Hosting; + namespace SecurityWebSite; public class Program { public static void Main(string[] args) { - var host = CreateWebHostBuilder(args) + using var host = CreateHost(args) .Build(); host.Run(); } - public static IWebHostBuilder CreateWebHostBuilder(string[] args) => - new WebHostBuilder() - .UseKestrel() - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseStartup(); + public static IHostBuilder CreateHost(string[] args) => + new HostBuilder() + .ConfigureWebHost(webHostBuilder => + { + webHostBuilder + .UseKestrel() + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseStartup(); + }); } diff --git a/src/Mvc/test/WebSites/VersioningWebSite/Program.cs b/src/Mvc/test/WebSites/VersioningWebSite/Program.cs index bdb3e48f5746..7e9532d7cb40 100644 --- a/src/Mvc/test/WebSites/VersioningWebSite/Program.cs +++ b/src/Mvc/test/WebSites/VersioningWebSite/Program.cs @@ -1,22 +1,28 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using Microsoft.Extensions.Hosting; + namespace VersioningWebSite; public class Program { public static void Main(string[] args) { - var host = CreateWebHostBuilder(args) + using var host = CreateHost(args) .Build(); host.Run(); } - public static IWebHostBuilder CreateWebHostBuilder(string[] args) => - new WebHostBuilder() - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseStartup() - .UseKestrel() - .UseIISIntegration(); + public static IHostBuilder CreateHost(string[] args) => + new HostBuilder() + .ConfigureWebHost(webHostBuilder => + { + webHostBuilder + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseStartup() + .UseKestrel() + .UseIISIntegration(); + }); } From 749289e573d0a185e4432bf6f92beaee51424e42 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 14 Jul 2025 06:05:59 +0000 Subject: [PATCH 4/9] Complete transformation of all remaining Startup.cs files from WebHostBuilder to HostBuilder Co-authored-by: BrennanConroy <7574801+BrennanConroy@users.noreply.github.com> --- .../WebSites/ApiExplorerWebSite/Startup.cs | 19 ++++++++++------ .../ApplicationModelWebSite/Startup.cs | 20 +++++++++++------ .../ControllersFromServicesWebSite/Startup.cs | 19 ++++++++++------ .../ErrorPageMiddlewareWebSite/Startup.cs | 20 +++++++++++------ .../WebSites/HtmlGenerationWebSite/Startup.cs | 19 ++++++++++------ .../StartupWithCultureReplace.cs | 17 +++++++++----- .../WebSites/RazorBuildWebSite/Startup.cs | 18 ++++++++++----- .../StartupWithHostingStartup.cs | 17 +++++++++----- .../WebSites/TagHelpersWebSite/Startup.cs | 22 ++++++++++++------- .../WebSites/XmlFormattersWebSite/Startup.cs | 19 ++++++++++------ 10 files changed, 122 insertions(+), 68 deletions(-) diff --git a/src/Mvc/test/WebSites/ApiExplorerWebSite/Startup.cs b/src/Mvc/test/WebSites/ApiExplorerWebSite/Startup.cs index c2bfec25d45e..6f4fa1e1c5dc 100644 --- a/src/Mvc/test/WebSites/ApiExplorerWebSite/Startup.cs +++ b/src/Mvc/test/WebSites/ApiExplorerWebSite/Startup.cs @@ -4,6 +4,7 @@ using ApiExplorerWebSite.Controllers; using Microsoft.AspNetCore.Mvc.Formatters; using Microsoft.AspNetCore.Mvc.Infrastructure; +using Microsoft.Extensions.Hosting; namespace ApiExplorerWebSite; @@ -45,17 +46,21 @@ public void Configure(IApplicationBuilder app) public static void Main(string[] args) { - var host = CreateWebHostBuilder(args) + using var host = CreateHost(args) .Build(); host.Run(); } - public static IWebHostBuilder CreateWebHostBuilder(string[] args) => - new WebHostBuilder() - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseKestrel() - .UseIISIntegration() - .UseStartup(); + public static IHostBuilder CreateHost(string[] args) => + new HostBuilder() + .ConfigureWebHost(webHostBuilder => + { + webHostBuilder + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseKestrel() + .UseIISIntegration() + .UseStartup(); + }); } diff --git a/src/Mvc/test/WebSites/ApplicationModelWebSite/Startup.cs b/src/Mvc/test/WebSites/ApplicationModelWebSite/Startup.cs index ab31d94048cd..ec2af2ed2b03 100644 --- a/src/Mvc/test/WebSites/ApplicationModelWebSite/Startup.cs +++ b/src/Mvc/test/WebSites/ApplicationModelWebSite/Startup.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using Microsoft.Extensions.Hosting; + namespace ApplicationModelWebSite; public class Startup @@ -34,17 +36,21 @@ public void Configure(IApplicationBuilder app) public static void Main(string[] args) { - var host = CreateWebHostBuilder(args) + using var host = CreateHost(args) .Build(); host.Run(); } - public static IWebHostBuilder CreateWebHostBuilder(string[] args) => - new WebHostBuilder() - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseStartup() - .UseKestrel() - .UseIISIntegration(); + public static IHostBuilder CreateHost(string[] args) => + new HostBuilder() + .ConfigureWebHost(webHostBuilder => + { + webHostBuilder + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseStartup() + .UseKestrel() + .UseIISIntegration(); + }); } diff --git a/src/Mvc/test/WebSites/ControllersFromServicesWebSite/Startup.cs b/src/Mvc/test/WebSites/ControllersFromServicesWebSite/Startup.cs index 2e236143f638..abcd6a49f442 100644 --- a/src/Mvc/test/WebSites/ControllersFromServicesWebSite/Startup.cs +++ b/src/Mvc/test/WebSites/ControllersFromServicesWebSite/Startup.cs @@ -6,6 +6,7 @@ using ControllersFromServicesWebSite.Components; using ControllersFromServicesWebSite.TagHelpers; using Microsoft.AspNetCore.Mvc.ApplicationParts; +using Microsoft.Extensions.Hosting; namespace ControllersFromServicesWebSite; @@ -61,17 +62,21 @@ public void Configure(IApplicationBuilder app) public static void Main(string[] args) { - var host = CreateWebHostBuilder(args) + using var host = CreateHost(args) .Build(); host.Run(); } - public static IWebHostBuilder CreateWebHostBuilder(string[] args) => - new WebHostBuilder() - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseStartup() - .UseKestrel() - .UseIISIntegration(); + public static IHostBuilder CreateHost(string[] args) => + new HostBuilder() + .ConfigureWebHost(webHostBuilder => + { + webHostBuilder + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseStartup() + .UseKestrel() + .UseIISIntegration(); + }); } diff --git a/src/Mvc/test/WebSites/ErrorPageMiddlewareWebSite/Startup.cs b/src/Mvc/test/WebSites/ErrorPageMiddlewareWebSite/Startup.cs index d459fadc0c7a..3b7cc13f179c 100644 --- a/src/Mvc/test/WebSites/ErrorPageMiddlewareWebSite/Startup.cs +++ b/src/Mvc/test/WebSites/ErrorPageMiddlewareWebSite/Startup.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using Microsoft.Extensions.Hosting; + namespace ErrorPageMiddlewareWebSite; public class Startup @@ -24,17 +26,21 @@ public void Configure(IApplicationBuilder app) public static void Main(string[] args) { - var host = CreateWebHostBuilder(args) + using var host = CreateHost(args) .Build(); host.Run(); } - public static IWebHostBuilder CreateWebHostBuilder(string[] args) => - new WebHostBuilder() - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseStartup() - .UseKestrel() - .UseIISIntegration(); + public static IHostBuilder CreateHost(string[] args) => + new HostBuilder() + .ConfigureWebHost(webHostBuilder => + { + webHostBuilder + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseStartup() + .UseKestrel() + .UseIISIntegration(); + }); } diff --git a/src/Mvc/test/WebSites/HtmlGenerationWebSite/Startup.cs b/src/Mvc/test/WebSites/HtmlGenerationWebSite/Startup.cs index 4ac4a3edbdf6..743e590e0e45 100644 --- a/src/Mvc/test/WebSites/HtmlGenerationWebSite/Startup.cs +++ b/src/Mvc/test/WebSites/HtmlGenerationWebSite/Startup.cs @@ -4,6 +4,7 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.TagHelpers; using Microsoft.Extensions.Caching.Memory; +using Microsoft.Extensions.Hosting; namespace HtmlGenerationWebSite; @@ -48,18 +49,22 @@ public virtual void Configure(IApplicationBuilder app) public static void Main(string[] args) { - var host = CreateWebHostBuilder(args) + using var host = CreateHost(args) .Build(); host.Run(); } - public static IWebHostBuilder CreateWebHostBuilder(string[] args) => - new WebHostBuilder() - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseStartup() - .UseKestrel() - .UseIISIntegration(); + public static IHostBuilder CreateHost(string[] args) => + new HostBuilder() + .ConfigureWebHost(webHostBuilder => + { + webHostBuilder + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseStartup() + .UseKestrel() + .UseIISIntegration(); + }); protected virtual void ConfigureMvcOptions(MvcOptions options) { diff --git a/src/Mvc/test/WebSites/HtmlGenerationWebSite/StartupWithCultureReplace.cs b/src/Mvc/test/WebSites/HtmlGenerationWebSite/StartupWithCultureReplace.cs index da8475622054..3a3779aa5a0c 100644 --- a/src/Mvc/test/WebSites/HtmlGenerationWebSite/StartupWithCultureReplace.cs +++ b/src/Mvc/test/WebSites/HtmlGenerationWebSite/StartupWithCultureReplace.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Globalization; +using Microsoft.Extensions.Hosting; namespace HtmlGenerationWebSite; @@ -31,10 +32,14 @@ public void Configure(IApplicationBuilder app) Startup.Configure(app); } - public static IWebHostBuilder CreateWebHostBuilder(string[] args) => - new WebHostBuilder() - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseStartup() - .UseKestrel() - .UseIISIntegration(); + public static IHostBuilder CreateHost(string[] args) => + new HostBuilder() + .ConfigureWebHost(webHostBuilder => + { + webHostBuilder + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseStartup() + .UseKestrel() + .UseIISIntegration(); + }); } diff --git a/src/Mvc/test/WebSites/RazorBuildWebSite/Startup.cs b/src/Mvc/test/WebSites/RazorBuildWebSite/Startup.cs index 95325f20d4f2..5629b8a3a3c5 100644 --- a/src/Mvc/test/WebSites/RazorBuildWebSite/Startup.cs +++ b/src/Mvc/test/WebSites/RazorBuildWebSite/Startup.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using Microsoft.Extensions.Hosting; + namespace RazorBuildWebSite; public class Startup @@ -25,10 +27,14 @@ public void Configure(IApplicationBuilder app) }); } - public static IWebHostBuilder CreateWebHostBuilder(string[] args) => - new WebHostBuilder() - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseStartup() - .UseKestrel() - .UseIISIntegration(); + public static IHostBuilder CreateHost(string[] args) => + new HostBuilder() + .ConfigureWebHost(webHostBuilder => + { + webHostBuilder + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseStartup() + .UseKestrel() + .UseIISIntegration(); + }); } diff --git a/src/Mvc/test/WebSites/RazorBuildWebSite/StartupWithHostingStartup.cs b/src/Mvc/test/WebSites/RazorBuildWebSite/StartupWithHostingStartup.cs index 78c56e00ed5a..dd5547b34c44 100644 --- a/src/Mvc/test/WebSites/RazorBuildWebSite/StartupWithHostingStartup.cs +++ b/src/Mvc/test/WebSites/RazorBuildWebSite/StartupWithHostingStartup.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using Microsoft.AspNetCore.Mvc.ApplicationParts; +using Microsoft.Extensions.Hosting; namespace RazorBuildWebSite; @@ -34,17 +35,21 @@ public void Configure(IApplicationBuilder app) public static void Main(string[] args) { - var host = CreateWebHostBuilder(args) + using var host = CreateHost(args) .Build(); host.Run(); } - public static IWebHostBuilder CreateWebHostBuilder(string[] args) => - new WebHostBuilder() - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseStartup() - .UseKestrel(); + public static IHostBuilder CreateHost(string[] args) => + new HostBuilder() + .ConfigureWebHost(webHostBuilder => + { + webHostBuilder + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseStartup() + .UseKestrel(); + }); private class MockMvcBuilder : IMvcBuilder { diff --git a/src/Mvc/test/WebSites/TagHelpersWebSite/Startup.cs b/src/Mvc/test/WebSites/TagHelpersWebSite/Startup.cs index 67990ce51d8b..50c06675a654 100644 --- a/src/Mvc/test/WebSites/TagHelpersWebSite/Startup.cs +++ b/src/Mvc/test/WebSites/TagHelpersWebSite/Startup.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using Microsoft.Extensions.Hosting; + namespace TagHelpersWebSite; public class Startup @@ -23,18 +25,22 @@ public void Configure(IApplicationBuilder app) public static void Main(string[] args) { - var host = CreateWebHostBuilder(args) + using var host = CreateHost(args) .Build(); host.Run(); } - public static IWebHostBuilder CreateWebHostBuilder(string[] args) => - new WebHostBuilder() - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseStaticWebAssets() - .UseStartup() - .UseKestrel() - .UseIISIntegration(); + public static IHostBuilder CreateHost(string[] args) => + new HostBuilder() + .ConfigureWebHost(webHostBuilder => + { + webHostBuilder + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseStaticWebAssets() + .UseStartup() + .UseKestrel() + .UseIISIntegration(); + }); } diff --git a/src/Mvc/test/WebSites/XmlFormattersWebSite/Startup.cs b/src/Mvc/test/WebSites/XmlFormattersWebSite/Startup.cs index 956fd0f33233..9d1a71695ee3 100644 --- a/src/Mvc/test/WebSites/XmlFormattersWebSite/Startup.cs +++ b/src/Mvc/test/WebSites/XmlFormattersWebSite/Startup.cs @@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Formatters; +using Microsoft.Extensions.Hosting; using Microsoft.Net.Http.Headers; namespace XmlFormattersWebSite; @@ -109,17 +110,21 @@ public void Configure(IApplicationBuilder app) public static void Main(string[] args) { - var host = CreateWebHostBuilder(args) + using var host = CreateHost(args) .Build(); host.Run(); } - public static IWebHostBuilder CreateWebHostBuilder(string[] args) => - new WebHostBuilder() - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseStartup() - .UseKestrel() - .UseIISIntegration(); + public static IHostBuilder CreateHost(string[] args) => + new HostBuilder() + .ConfigureWebHost(webHostBuilder => + { + webHostBuilder + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseStartup() + .UseKestrel() + .UseIISIntegration(); + }); } From 71f4919631a7faaac40f450efcdac44b009fbf5b Mon Sep 17 00:00:00 2001 From: Brennan Date: Mon, 14 Jul 2025 13:10:34 -0700 Subject: [PATCH 5/9] fixup --- .../src/GenericHost/GenericWebHostBuilder.cs | 22 +++++++++++-------- src/Mvc/samples/MvcSandbox/Startup.cs | 4 ++-- .../WebSites/ApiExplorerWebSite/Startup.cs | 4 ++-- .../ApplicationModelWebSite/Startup.cs | 4 ++-- src/Mvc/test/WebSites/BasicWebSite/Program.cs | 6 ++--- .../ControllersFromServicesWebSite/Startup.cs | 4 ++-- src/Mvc/test/WebSites/CorsWebSite/Program.cs | 6 ++--- .../ErrorPageMiddlewareWebSite/Startup.cs | 4 ++-- src/Mvc/test/WebSites/FilesWebSite/Startup.cs | 4 ++-- .../test/WebSites/FormatterWebSite/Program.cs | 6 ++--- .../WebSites/HtmlGenerationWebSite/Startup.cs | 4 ++-- .../StartupWithCultureReplace.cs | 2 +- .../WebSites/RazorBuildWebSite/Startup.cs | 2 +- .../StartupWithHostingStartup.cs | 4 ++-- .../WebSites/RazorPagesWebSite/Program.cs | 6 ++--- src/Mvc/test/WebSites/RazorWebSite/Program.cs | 6 ++--- .../test/WebSites/RoutingWebSite/Program.cs | 4 ++-- .../test/WebSites/SecurityWebSite/Program.cs | 6 ++--- .../test/WebSites/SimpleWebSite/Startup.cs | 4 ++-- .../WebSites/TagHelpersWebSite/Startup.cs | 4 ++-- .../WebSites/VersioningWebSite/Program.cs | 6 ++--- .../WebSites/XmlFormattersWebSite/Startup.cs | 4 ++-- 22 files changed, 60 insertions(+), 56 deletions(-) diff --git a/src/Hosting/Hosting/src/GenericHost/GenericWebHostBuilder.cs b/src/Hosting/Hosting/src/GenericHost/GenericWebHostBuilder.cs index 5cc17d57e2ec..d50666bc369c 100644 --- a/src/Hosting/Hosting/src/GenericHost/GenericWebHostBuilder.cs +++ b/src/Hosting/Hosting/src/GenericHost/GenericWebHostBuilder.cs @@ -20,7 +20,7 @@ namespace Microsoft.AspNetCore.Hosting; internal sealed class GenericWebHostBuilder : WebHostBuilderBase, ISupportsStartup { - private object? _startupObject; + private const string _startupConfigName = "__UseStartup.StartupType"; private readonly object _startupKey = new object(); private AggregateException? _hostingStartupErrors; @@ -170,12 +170,13 @@ public IWebHostBuilder UseStartup([DynamicallyAccessedMembers(StartupLinkerOptio UseSetting(WebHostDefaults.ApplicationKey, startupAssemblyName); // UseStartup can be called multiple times. Only run the last one. - _startupObject = startupType; + _builder.Properties[_startupConfigName] = startupType; _builder.ConfigureServices((context, services) => { // Run this delegate if the startup type matches - if (object.ReferenceEquals(_startupObject, startupType)) + if (_builder.Properties.TryGetValue(_startupConfigName, out var startupObject) && + object.ReferenceEquals(startupObject, startupType)) { UseStartup(startupType, context, services); } @@ -193,7 +194,7 @@ public IWebHostBuilder UseStartup([DynamicallyAccessedMembers(StartupLinkerOptio UseSetting(WebHostDefaults.ApplicationKey, startupAssemblyName); // Clear the startup type - _startupObject = startupFactory; + _builder.Properties[_startupConfigName] = startupFactory; _builder.ConfigureServices(ConfigureStartup); @@ -201,7 +202,8 @@ public IWebHostBuilder UseStartup([DynamicallyAccessedMembers(StartupLinkerOptio void ConfigureStartup(HostBuilderContext context, IServiceCollection services) { // UseStartup can be called multiple times. Only run the last one. - if (object.ReferenceEquals(_startupObject, startupFactory)) + if (_builder.Properties.TryGetValue(_startupConfigName, out var startupObject) && + object.ReferenceEquals(startupObject, startupFactory)) { var webHostBuilderContext = GetWebHostBuilderContext(context); var instance = startupFactory(webHostBuilderContext) ?? throw new InvalidOperationException("The specified factory returned null startup instance."); @@ -316,11 +318,12 @@ public IWebHostBuilder Configure(Action configure) UseSetting(WebHostDefaults.ApplicationKey, startupAssemblyName); // Clear the startup type - _startupObject = configure; + _builder.Properties[_startupConfigName] = configure; _builder.ConfigureServices((context, services) => { - if (object.ReferenceEquals(_startupObject, configure)) + if (_builder.Properties.TryGetValue(_startupConfigName, out var startupObject) && + object.ReferenceEquals(startupObject, configure)) { services.Configure(options => { @@ -339,11 +342,12 @@ public IWebHostBuilder Configure(Action { - if (object.ReferenceEquals(_startupObject, configure)) + if (_builder.Properties.TryGetValue(_startupConfigName, out var startupObject) && + object.ReferenceEquals(startupObject, configure)) { services.Configure(options => { diff --git a/src/Mvc/samples/MvcSandbox/Startup.cs b/src/Mvc/samples/MvcSandbox/Startup.cs index c2deb5f84d4c..95b307f30108 100644 --- a/src/Mvc/samples/MvcSandbox/Startup.cs +++ b/src/Mvc/samples/MvcSandbox/Startup.cs @@ -44,13 +44,13 @@ static void ConfigureEndpoints(IEndpointRouteBuilder endpoints) public static void Main(string[] args) { - using var host = CreateHost(args) + using var host = CreateHostBuilder(args) .Build(); host.Run(); } - public static IHostBuilder CreateHost(string[] args) => + public static IHostBuilder CreateHostBuilder(string[] args) => new HostBuilder() .ConfigureWebHost(webHostBuilder => { diff --git a/src/Mvc/test/WebSites/ApiExplorerWebSite/Startup.cs b/src/Mvc/test/WebSites/ApiExplorerWebSite/Startup.cs index 6f4fa1e1c5dc..22ab7f53d20a 100644 --- a/src/Mvc/test/WebSites/ApiExplorerWebSite/Startup.cs +++ b/src/Mvc/test/WebSites/ApiExplorerWebSite/Startup.cs @@ -46,13 +46,13 @@ public void Configure(IApplicationBuilder app) public static void Main(string[] args) { - using var host = CreateHost(args) + using var host = CreateHostBuilder(args) .Build(); host.Run(); } - public static IHostBuilder CreateHost(string[] args) => + public static IHostBuilder CreateHostBuilder(string[] args) => new HostBuilder() .ConfigureWebHost(webHostBuilder => { diff --git a/src/Mvc/test/WebSites/ApplicationModelWebSite/Startup.cs b/src/Mvc/test/WebSites/ApplicationModelWebSite/Startup.cs index ec2af2ed2b03..20962f53c44b 100644 --- a/src/Mvc/test/WebSites/ApplicationModelWebSite/Startup.cs +++ b/src/Mvc/test/WebSites/ApplicationModelWebSite/Startup.cs @@ -36,13 +36,13 @@ public void Configure(IApplicationBuilder app) public static void Main(string[] args) { - using var host = CreateHost(args) + using var host = CreateHostBuilder(args) .Build(); host.Run(); } - public static IHostBuilder CreateHost(string[] args) => + public static IHostBuilder CreateHostBuilder(string[] args) => new HostBuilder() .ConfigureWebHost(webHostBuilder => { diff --git a/src/Mvc/test/WebSites/BasicWebSite/Program.cs b/src/Mvc/test/WebSites/BasicWebSite/Program.cs index 3a577b7d6b0e..a73dd5d7b4b4 100644 --- a/src/Mvc/test/WebSites/BasicWebSite/Program.cs +++ b/src/Mvc/test/WebSites/BasicWebSite/Program.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using Microsoft.Extensions.Hosting; @@ -9,12 +9,12 @@ public class Program { public static void Main(string[] args) { - using var host = CreateHost(args).Build(); + using var host = CreateHostBuilder(args).Build(); host.Run(); } // This method now returns IHostBuilder and uses the new pattern with HostBuilder and ConfigureWebHost - public static IHostBuilder CreateHost(string[] args) => + public static IHostBuilder CreateHostBuilder(string[] args) => new HostBuilder() .ConfigureWebHost(webHostBuilder => { diff --git a/src/Mvc/test/WebSites/ControllersFromServicesWebSite/Startup.cs b/src/Mvc/test/WebSites/ControllersFromServicesWebSite/Startup.cs index abcd6a49f442..ca1fe86ab6da 100644 --- a/src/Mvc/test/WebSites/ControllersFromServicesWebSite/Startup.cs +++ b/src/Mvc/test/WebSites/ControllersFromServicesWebSite/Startup.cs @@ -62,13 +62,13 @@ public void Configure(IApplicationBuilder app) public static void Main(string[] args) { - using var host = CreateHost(args) + using var host = CreateHostBuilder(args) .Build(); host.Run(); } - public static IHostBuilder CreateHost(string[] args) => + public static IHostBuilder CreateHostBuilder(string[] args) => new HostBuilder() .ConfigureWebHost(webHostBuilder => { diff --git a/src/Mvc/test/WebSites/CorsWebSite/Program.cs b/src/Mvc/test/WebSites/CorsWebSite/Program.cs index 1df67b56bf27..fffa0760a8dc 100644 --- a/src/Mvc/test/WebSites/CorsWebSite/Program.cs +++ b/src/Mvc/test/WebSites/CorsWebSite/Program.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using Microsoft.Extensions.Hosting; @@ -9,13 +9,13 @@ public class Program { public static void Main(string[] args) { - using var host = CreateHost(args) + using var host = CreateHostBuilder(args) .Build(); host.Run(); } - public static IHostBuilder CreateHost(string[] args) => + public static IHostBuilder CreateHostBuilder(string[] args) => new HostBuilder() .ConfigureWebHost(webHostBuilder => { diff --git a/src/Mvc/test/WebSites/ErrorPageMiddlewareWebSite/Startup.cs b/src/Mvc/test/WebSites/ErrorPageMiddlewareWebSite/Startup.cs index 3b7cc13f179c..a3aae2df48ce 100644 --- a/src/Mvc/test/WebSites/ErrorPageMiddlewareWebSite/Startup.cs +++ b/src/Mvc/test/WebSites/ErrorPageMiddlewareWebSite/Startup.cs @@ -26,13 +26,13 @@ public void Configure(IApplicationBuilder app) public static void Main(string[] args) { - using var host = CreateHost(args) + using var host = CreateHostBuilder(args) .Build(); host.Run(); } - public static IHostBuilder CreateHost(string[] args) => + public static IHostBuilder CreateHostBuilder(string[] args) => new HostBuilder() .ConfigureWebHost(webHostBuilder => { diff --git a/src/Mvc/test/WebSites/FilesWebSite/Startup.cs b/src/Mvc/test/WebSites/FilesWebSite/Startup.cs index f75494beec23..bdee1296991f 100644 --- a/src/Mvc/test/WebSites/FilesWebSite/Startup.cs +++ b/src/Mvc/test/WebSites/FilesWebSite/Startup.cs @@ -25,13 +25,13 @@ public void Configure(IApplicationBuilder app) public static void Main(string[] args) { - using var host = CreateHost(args) + using var host = CreateHostBuilder(args) .Build(); host.Run(); } - public static IHostBuilder CreateHost(string[] args) => + public static IHostBuilder CreateHostBuilder(string[] args) => new HostBuilder() .ConfigureWebHost(webHostBuilder => { diff --git a/src/Mvc/test/WebSites/FormatterWebSite/Program.cs b/src/Mvc/test/WebSites/FormatterWebSite/Program.cs index a01042092c8c..55d6b0c04c25 100644 --- a/src/Mvc/test/WebSites/FormatterWebSite/Program.cs +++ b/src/Mvc/test/WebSites/FormatterWebSite/Program.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using Microsoft.Extensions.Hosting; @@ -9,13 +9,13 @@ public class Program { public static void Main(string[] args) { - using var host = CreateHost(args) + using var host = CreateHostBuilder(args) .Build(); host.Run(); } - public static IHostBuilder CreateHost(string[] args) => + public static IHostBuilder CreateHostBuilder(string[] args) => new HostBuilder() .ConfigureWebHost(webHostBuilder => { diff --git a/src/Mvc/test/WebSites/HtmlGenerationWebSite/Startup.cs b/src/Mvc/test/WebSites/HtmlGenerationWebSite/Startup.cs index 743e590e0e45..baab04ea7b8b 100644 --- a/src/Mvc/test/WebSites/HtmlGenerationWebSite/Startup.cs +++ b/src/Mvc/test/WebSites/HtmlGenerationWebSite/Startup.cs @@ -49,13 +49,13 @@ public virtual void Configure(IApplicationBuilder app) public static void Main(string[] args) { - using var host = CreateHost(args) + using var host = CreateHostBuilder(args) .Build(); host.Run(); } - public static IHostBuilder CreateHost(string[] args) => + public static IHostBuilder CreateHostBuilder(string[] args) => new HostBuilder() .ConfigureWebHost(webHostBuilder => { diff --git a/src/Mvc/test/WebSites/HtmlGenerationWebSite/StartupWithCultureReplace.cs b/src/Mvc/test/WebSites/HtmlGenerationWebSite/StartupWithCultureReplace.cs index 3a3779aa5a0c..1f8da4281eb3 100644 --- a/src/Mvc/test/WebSites/HtmlGenerationWebSite/StartupWithCultureReplace.cs +++ b/src/Mvc/test/WebSites/HtmlGenerationWebSite/StartupWithCultureReplace.cs @@ -32,7 +32,7 @@ public void Configure(IApplicationBuilder app) Startup.Configure(app); } - public static IHostBuilder CreateHost(string[] args) => + public static IHostBuilder CreateHostBuilder(string[] args) => new HostBuilder() .ConfigureWebHost(webHostBuilder => { diff --git a/src/Mvc/test/WebSites/RazorBuildWebSite/Startup.cs b/src/Mvc/test/WebSites/RazorBuildWebSite/Startup.cs index 5629b8a3a3c5..82da4815dba1 100644 --- a/src/Mvc/test/WebSites/RazorBuildWebSite/Startup.cs +++ b/src/Mvc/test/WebSites/RazorBuildWebSite/Startup.cs @@ -27,7 +27,7 @@ public void Configure(IApplicationBuilder app) }); } - public static IHostBuilder CreateHost(string[] args) => + public static IHostBuilder CreateHostBuilder(string[] args) => new HostBuilder() .ConfigureWebHost(webHostBuilder => { diff --git a/src/Mvc/test/WebSites/RazorBuildWebSite/StartupWithHostingStartup.cs b/src/Mvc/test/WebSites/RazorBuildWebSite/StartupWithHostingStartup.cs index dd5547b34c44..8fde980c5abf 100644 --- a/src/Mvc/test/WebSites/RazorBuildWebSite/StartupWithHostingStartup.cs +++ b/src/Mvc/test/WebSites/RazorBuildWebSite/StartupWithHostingStartup.cs @@ -35,13 +35,13 @@ public void Configure(IApplicationBuilder app) public static void Main(string[] args) { - using var host = CreateHost(args) + using var host = CreateHostBuilder(args) .Build(); host.Run(); } - public static IHostBuilder CreateHost(string[] args) => + public static IHostBuilder CreateHostBuilder(string[] args) => new HostBuilder() .ConfigureWebHost(webHostBuilder => { diff --git a/src/Mvc/test/WebSites/RazorPagesWebSite/Program.cs b/src/Mvc/test/WebSites/RazorPagesWebSite/Program.cs index 03ab394d37c2..39720535fdbb 100644 --- a/src/Mvc/test/WebSites/RazorPagesWebSite/Program.cs +++ b/src/Mvc/test/WebSites/RazorPagesWebSite/Program.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using Microsoft.Extensions.Hosting; @@ -9,13 +9,13 @@ public class Program { public static void Main(string[] args) { - using var host = CreateHost(args) + using var host = CreateHostBuilder(args) .Build(); host.Run(); } - public static IHostBuilder CreateHost(string[] args) => + public static IHostBuilder CreateHostBuilder(string[] args) => new HostBuilder() .ConfigureWebHost(webHostBuilder => { diff --git a/src/Mvc/test/WebSites/RazorWebSite/Program.cs b/src/Mvc/test/WebSites/RazorWebSite/Program.cs index 7bb070105754..df37aa1be8d9 100644 --- a/src/Mvc/test/WebSites/RazorWebSite/Program.cs +++ b/src/Mvc/test/WebSites/RazorWebSite/Program.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using Microsoft.Extensions.Hosting; @@ -9,13 +9,13 @@ public class Program { public static void Main(string[] args) { - using var host = CreateHost(args) + using var host = CreateHostBuilder(args) .Build(); host.Run(); } - public static IHostBuilder CreateHost(string[] args) => + public static IHostBuilder CreateHostBuilder(string[] args) => new HostBuilder() .ConfigureWebHost(webHostBuilder => { diff --git a/src/Mvc/test/WebSites/RoutingWebSite/Program.cs b/src/Mvc/test/WebSites/RoutingWebSite/Program.cs index a2b63cbe5b56..d872250cf5bd 100644 --- a/src/Mvc/test/WebSites/RoutingWebSite/Program.cs +++ b/src/Mvc/test/WebSites/RoutingWebSite/Program.cs @@ -9,13 +9,13 @@ public class Program { public static void Main(string[] args) { - using var host = CreateHost(args) + using var host = CreateHostBuilder(args) .Build(); host.Run(); } - public static IHostBuilder CreateHost(string[] args) => + public static IHostBuilder CreateHostBuilder(string[] args) => new HostBuilder() .ConfigureWebHost(webHostBuilder => { diff --git a/src/Mvc/test/WebSites/SecurityWebSite/Program.cs b/src/Mvc/test/WebSites/SecurityWebSite/Program.cs index 7025096edf94..440a2774ebaa 100644 --- a/src/Mvc/test/WebSites/SecurityWebSite/Program.cs +++ b/src/Mvc/test/WebSites/SecurityWebSite/Program.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using Microsoft.Extensions.Hosting; @@ -9,13 +9,13 @@ public class Program { public static void Main(string[] args) { - using var host = CreateHost(args) + using var host = CreateHostBuilder(args) .Build(); host.Run(); } - public static IHostBuilder CreateHost(string[] args) => + public static IHostBuilder CreateHostBuilder(string[] args) => new HostBuilder() .ConfigureWebHost(webHostBuilder => { diff --git a/src/Mvc/test/WebSites/SimpleWebSite/Startup.cs b/src/Mvc/test/WebSites/SimpleWebSite/Startup.cs index dc5a7254680c..e5faf5d06d32 100644 --- a/src/Mvc/test/WebSites/SimpleWebSite/Startup.cs +++ b/src/Mvc/test/WebSites/SimpleWebSite/Startup.cs @@ -30,13 +30,13 @@ public void Configure(IApplicationBuilder app) public static void Main(string[] args) { - using var host = CreateHost(args) + using var host = CreateHostBuilder(args) .Build(); host.Run(); } - public static IHostBuilder CreateHost(string[] args) => + public static IHostBuilder CreateHostBuilder(string[] args) => new HostBuilder() .ConfigureWebHost(webHostBuilder => { diff --git a/src/Mvc/test/WebSites/TagHelpersWebSite/Startup.cs b/src/Mvc/test/WebSites/TagHelpersWebSite/Startup.cs index 50c06675a654..71a933ba44ab 100644 --- a/src/Mvc/test/WebSites/TagHelpersWebSite/Startup.cs +++ b/src/Mvc/test/WebSites/TagHelpersWebSite/Startup.cs @@ -25,13 +25,13 @@ public void Configure(IApplicationBuilder app) public static void Main(string[] args) { - using var host = CreateHost(args) + using var host = CreateHostBuilder(args) .Build(); host.Run(); } - public static IHostBuilder CreateHost(string[] args) => + public static IHostBuilder CreateHostBuilder(string[] args) => new HostBuilder() .ConfigureWebHost(webHostBuilder => { diff --git a/src/Mvc/test/WebSites/VersioningWebSite/Program.cs b/src/Mvc/test/WebSites/VersioningWebSite/Program.cs index 7e9532d7cb40..8f535ad23228 100644 --- a/src/Mvc/test/WebSites/VersioningWebSite/Program.cs +++ b/src/Mvc/test/WebSites/VersioningWebSite/Program.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using Microsoft.Extensions.Hosting; @@ -9,13 +9,13 @@ public class Program { public static void Main(string[] args) { - using var host = CreateHost(args) + using var host = CreateHostBuilder(args) .Build(); host.Run(); } - public static IHostBuilder CreateHost(string[] args) => + public static IHostBuilder CreateHostBuilder(string[] args) => new HostBuilder() .ConfigureWebHost(webHostBuilder => { diff --git a/src/Mvc/test/WebSites/XmlFormattersWebSite/Startup.cs b/src/Mvc/test/WebSites/XmlFormattersWebSite/Startup.cs index 9d1a71695ee3..b747c6b08438 100644 --- a/src/Mvc/test/WebSites/XmlFormattersWebSite/Startup.cs +++ b/src/Mvc/test/WebSites/XmlFormattersWebSite/Startup.cs @@ -110,13 +110,13 @@ public void Configure(IApplicationBuilder app) public static void Main(string[] args) { - using var host = CreateHost(args) + using var host = CreateHostBuilder(args) .Build(); host.Run(); } - public static IHostBuilder CreateHost(string[] args) => + public static IHostBuilder CreateHostBuilder(string[] args) => new HostBuilder() .ConfigureWebHost(webHostBuilder => { From c5f4ac02ca50a5871851830b9c0a2cfbc03ce2a3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 14 Jul 2025 21:05:21 +0000 Subject: [PATCH 6/9] Add test for multiple ConfigureWebHost calls with UseStartup Co-authored-by: BrennanConroy <7574801+BrennanConroy@users.noreply.github.com> --- .../test/GenericWebHostBuilderTests.cs | 81 ++++++++++++++++++- 1 file changed, 79 insertions(+), 2 deletions(-) diff --git a/src/Hosting/Hosting/test/GenericWebHostBuilderTests.cs b/src/Hosting/Hosting/test/GenericWebHostBuilderTests.cs index d517e6e0fe6b..5d6eba178b74 100644 --- a/src/Hosting/Hosting/test/GenericWebHostBuilderTests.cs +++ b/src/Hosting/Hosting/test/GenericWebHostBuilderTests.cs @@ -2,8 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Linq; +using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting.Server; using Microsoft.AspNetCore.Hosting.Server.Features; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Features; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; @@ -128,6 +130,59 @@ public void ReadsUrlsOrPorts(string urls, string httpPorts, string httpsPorts, s Assert.Equal(expected, string.Join(';', server.Addresses)); } + [Fact] + public async Task MultipleConfigureWebHostCallsWithUseStartupLastWins() + { + var server = new TestServer(); + + using var host = new HostBuilder() + .ConfigureWebHost(webHostBuilder => + { + webHostBuilder + .UseServer(server) + .UseStartup(); + }) + .ConfigureWebHost(webHostBuilder => + { + webHostBuilder + .UseStartup(); + }) + .Build(); + + await host.StartAsync(); + await AssertResponseContains(server.RequestDelegate, "SecondStartup"); + } + + private async Task AssertResponseContains(RequestDelegate app, string expectedText) + { + var httpContext = new DefaultHttpContext(); + httpContext.Response.Body = new MemoryStream(); + await app(httpContext); + httpContext.Response.Body.Seek(0, SeekOrigin.Begin); + var bodyText = new StreamReader(httpContext.Response.Body).ReadToEnd(); + Assert.Contains(expectedText, bodyText); + } + + private class FirstStartup + { + public void ConfigureServices(IServiceCollection services) { } + + public void Configure(IApplicationBuilder app) + { + app.Run(context => context.Response.WriteAsync("FirstStartup")); + } + } + + private class SecondStartup + { + public void ConfigureServices(IServiceCollection services) { } + + public void Configure(IApplicationBuilder app) + { + app.Run(context => context.Response.WriteAsync("SecondStartup")); + } + } + private class TestServer : IServer, IServerAddressesFeature { public TestServer() @@ -139,9 +194,31 @@ public TestServer() public ICollection Addresses { get; } = new List(); public bool PreferHostingUrls { get; set; } + public RequestDelegate RequestDelegate { get; private set; } - public Task StartAsync(IHttpApplication application, CancellationToken cancellationToken) => Task.CompletedTask; - public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask; public void Dispose() { } + + public Task StartAsync(IHttpApplication application, CancellationToken cancellationToken) + { + // For testing that uses RequestDelegate + RequestDelegate = async ctx => + { + var httpContext = application.CreateContext(ctx.Features); + try + { + await application.ProcessRequestAsync(httpContext); + } + catch (Exception ex) + { + application.DisposeContext(httpContext, ex); + throw; + } + application.DisposeContext(httpContext, null); + }; + + return Task.CompletedTask; + } + + public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask; } } From 802ef7eaf5bdb68595f20d64fff8fc65a5f3da38 Mon Sep 17 00:00:00 2001 From: Brennan Date: Tue, 15 Jul 2025 09:57:20 -0700 Subject: [PATCH 7/9] fixup --- .../test/GenericWebHostBuilderTests.cs | 12 ++++++---- .../Hosting/test/WebHostBuilderTests.cs | 4 ++-- .../Mvc.Testing/src/PublicAPI.Unshipped.txt | 1 + .../Mvc.Testing/src/WebApplicationFactory.cs | 23 +++++++++++++++++-- .../MvcEncodedTestFixtureOfT.cs | 9 ++++---- .../Mvc.FunctionalTests/RazorBuildTest.cs | 1 - .../TestingInfrastructureInheritanceTests.cs | 12 +++++++--- 7 files changed, 45 insertions(+), 17 deletions(-) diff --git a/src/Hosting/Hosting/test/GenericWebHostBuilderTests.cs b/src/Hosting/Hosting/test/GenericWebHostBuilderTests.cs index 5d6eba178b74..4041503fb1d5 100644 --- a/src/Hosting/Hosting/test/GenericWebHostBuilderTests.cs +++ b/src/Hosting/Hosting/test/GenericWebHostBuilderTests.cs @@ -165,20 +165,24 @@ private async Task AssertResponseContains(RequestDelegate app, string expectedTe private class FirstStartup { - public void ConfigureServices(IServiceCollection services) { } - + public void ConfigureServices(IServiceCollection services) { services.AddSingleton(); } + public void Configure(IApplicationBuilder app) { + Assert.NotNull(app.ApplicationServices.GetService()); + Assert.Null(app.ApplicationServices.GetService()); app.Run(context => context.Response.WriteAsync("FirstStartup")); } } private class SecondStartup { - public void ConfigureServices(IServiceCollection services) { } - + public void ConfigureServices(IServiceCollection services) { services.AddSingleton(); } + public void Configure(IApplicationBuilder app) { + Assert.Null(app.ApplicationServices.GetService()); + Assert.NotNull(app.ApplicationServices.GetService()); app.Run(context => context.Response.WriteAsync("SecondStartup")); } } diff --git a/src/Hosting/Hosting/test/WebHostBuilderTests.cs b/src/Hosting/Hosting/test/WebHostBuilderTests.cs index 0bd72551ec1e..af7026409880 100644 --- a/src/Hosting/Hosting/test/WebHostBuilderTests.cs +++ b/src/Hosting/Hosting/test/WebHostBuilderTests.cs @@ -1681,11 +1681,11 @@ public void Configure(IWebHostBuilder builder) // This check is required because MVC still uses the // IWebHostEnvironment instance before the container is baked #pragma warning disable CS0618 // Type or member is obsolete - var heDescriptor = services.SingleOrDefault(s => s.ServiceType == typeof(IHostingEnvironment)); + var heDescriptor = services.FirstOrDefault(s => s.ServiceType == typeof(IHostingEnvironment)); Assert.NotNull(heDescriptor); Assert.NotNull(heDescriptor.ImplementationInstance); #pragma warning restore CS0618 // Type or member is obsolete - var wheDescriptor = services.SingleOrDefault(s => s.ServiceType == typeof(IWebHostEnvironment)); + var wheDescriptor = services.FirstOrDefault(s => s.ServiceType == typeof(IWebHostEnvironment)); Assert.NotNull(wheDescriptor); Assert.NotNull(wheDescriptor.ImplementationInstance); }) diff --git a/src/Mvc/Mvc.Testing/src/PublicAPI.Unshipped.txt b/src/Mvc/Mvc.Testing/src/PublicAPI.Unshipped.txt index e9587b50c032..f1ba5d5f2e0e 100644 --- a/src/Mvc/Mvc.Testing/src/PublicAPI.Unshipped.txt +++ b/src/Mvc/Mvc.Testing/src/PublicAPI.Unshipped.txt @@ -3,3 +3,4 @@ Microsoft.AspNetCore.Mvc.Testing.WebApplicationFactory.StartServer( Microsoft.AspNetCore.Mvc.Testing.WebApplicationFactory.UseKestrel() -> void Microsoft.AspNetCore.Mvc.Testing.WebApplicationFactory.UseKestrel(int port) -> void Microsoft.AspNetCore.Mvc.Testing.WebApplicationFactory.UseKestrel(System.Action! configureKestrelOptions) -> void +virtual Microsoft.AspNetCore.Mvc.Testing.WebApplicationFactory.CreateServer(System.IServiceProvider! serviceProvider) -> Microsoft.AspNetCore.TestHost.TestServer! diff --git a/src/Mvc/Mvc.Testing/src/WebApplicationFactory.cs b/src/Mvc/Mvc.Testing/src/WebApplicationFactory.cs index 5e028ac82230..926ab9bcf9b5 100644 --- a/src/Mvc/Mvc.Testing/src/WebApplicationFactory.cs +++ b/src/Mvc/Mvc.Testing/src/WebApplicationFactory.cs @@ -143,6 +143,7 @@ internal virtual WebApplicationFactory WithWebHostBuilderCore(Actio var factory = new DelegatedWebApplicationFactory( ClientOptions, CreateServer, + CreateServer, CreateHost, CreateWebHostBuilder, CreateHostBuilder, @@ -337,7 +338,10 @@ private void ConfigureHostBuilder(IHostBuilder hostBuilder) } else { - webHostBuilder.UseTestServer(); + webHostBuilder.ConfigureServices(services => + { + services.AddSingleton(CreateServer); + }); } }); _host = CreateHost(hostBuilder); @@ -565,10 +569,19 @@ private static void EnsureDepsFile() /// The with the bootstrapped application. protected virtual TestServer CreateServer(IWebHostBuilder builder) => new(builder); + /// + /// Creates the with the from the bootstrapped application. + /// This is only called for applications using . Applications based on + /// will use instead. + /// + /// The from the bootstrapped application. + /// + protected virtual TestServer CreateServer(IServiceProvider serviceProvider) => new(serviceProvider); + /// /// Creates the with the bootstrapped application in . /// This is only called for applications using . Applications based on - /// will use instead. + /// will use instead. /// /// The used to create the host. /// The with the bootstrapped application. @@ -801,6 +814,7 @@ public virtual async ValueTask DisposeAsync() private sealed class DelegatedWebApplicationFactory : WebApplicationFactory { private readonly Func _createServer; + private readonly Func _createServerFromServiceProvider; private readonly Func _createHost; private readonly Func _createWebHostBuilder; private readonly Func _createHostBuilder; @@ -810,6 +824,7 @@ private sealed class DelegatedWebApplicationFactory : WebApplicationFactory createServer, + Func createServerFromServiceProvider, Func createHost, Func createWebHostBuilder, Func createHostBuilder, @@ -819,6 +834,7 @@ public DelegatedWebApplicationFactory( { ClientOptions = new WebApplicationFactoryClientOptions(options); _createServer = createServer; + _createServerFromServiceProvider = createServerFromServiceProvider; _createHost = createHost; _createWebHostBuilder = createWebHostBuilder; _createHostBuilder = createHostBuilder; @@ -829,6 +845,8 @@ public DelegatedWebApplicationFactory( protected override TestServer CreateServer(IWebHostBuilder builder) => _createServer(builder); + protected override TestServer CreateServer(IServiceProvider serviceProvider) => _createServerFromServiceProvider(serviceProvider); + protected override IHost CreateHost(IHostBuilder builder) => _createHost(builder); protected override IWebHostBuilder? CreateWebHostBuilder() => _createWebHostBuilder(); @@ -846,6 +864,7 @@ internal override WebApplicationFactory WithWebHostBuilderCore(Acti return new DelegatedWebApplicationFactory( ClientOptions, _createServer, + _createServerFromServiceProvider, _createHost, _createWebHostBuilder, _createHostBuilder, diff --git a/src/Mvc/test/Mvc.FunctionalTests/Infrastructure/MvcEncodedTestFixtureOfT.cs b/src/Mvc/test/Mvc.FunctionalTests/Infrastructure/MvcEncodedTestFixtureOfT.cs index 5f9a0054bf4e..2c575743e210 100644 --- a/src/Mvc/test/Mvc.FunctionalTests/Infrastructure/MvcEncodedTestFixtureOfT.cs +++ b/src/Mvc/test/Mvc.FunctionalTests/Infrastructure/MvcEncodedTestFixtureOfT.cs @@ -3,10 +3,9 @@ using System.Text.Encodings.Web; using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.WebEncoders.Testing; -using Xunit.Abstractions; namespace Microsoft.AspNetCore.Mvc.FunctionalTests; @@ -20,9 +19,9 @@ protected override void ConfigureWebHost(IWebHostBuilder builder) base.ConfigureWebHost(builder); builder.ConfigureServices(services => { - services.TryAddTransient(); - services.TryAddTransient(); - services.TryAddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); }); } } diff --git a/src/Mvc/test/Mvc.FunctionalTests/RazorBuildTest.cs b/src/Mvc/test/Mvc.FunctionalTests/RazorBuildTest.cs index e3a7bfdb7fe5..482b45fbd744 100644 --- a/src/Mvc/test/Mvc.FunctionalTests/RazorBuildTest.cs +++ b/src/Mvc/test/Mvc.FunctionalTests/RazorBuildTest.cs @@ -25,7 +25,6 @@ protected override void Initialize(TestContext context, MethodInfo methodInfo, o { base.Initialize(context, methodInfo, testMethodArguments, testOutputHelper); Factory = new MvcTestFixture(LoggerFactory) - .WithWebHostBuilder(b => b.UseStartup()) .WithWebHostBuilder(b => b.ConfigureTestServices(serviceCollection => serviceCollection.Configure(ConfigureRuntimeCompilationOptions))); static void ConfigureRuntimeCompilationOptions(MvcRazorRuntimeCompilationOptions options) diff --git a/src/Mvc/test/Mvc.FunctionalTests/TestingInfrastructureInheritanceTests.cs b/src/Mvc/test/Mvc.FunctionalTests/TestingInfrastructureInheritanceTests.cs index 9f4162734292..b50e3be4a43c 100644 --- a/src/Mvc/test/Mvc.FunctionalTests/TestingInfrastructureInheritanceTests.cs +++ b/src/Mvc/test/Mvc.FunctionalTests/TestingInfrastructureInheritanceTests.cs @@ -26,11 +26,11 @@ public void TestingInfrastructure_WebHost_WithWebHostBuilderRespectsCustomizatio // Assert Assert.Equal(new[] { "ConfigureWebHost", "Customization", "FurtherCustomization" }, factory.ConfigureWebHostCalled.ToArray()); Assert.True(factory.CreateServerCalled); - Assert.True(factory.CreateWebHostBuilderCalled); + Assert.False(factory.CreateWebHostBuilderCalled); // GetTestAssemblies is not called when reading content roots from MvcAppManifest Assert.False(factory.GetTestAssembliesCalled); Assert.True(factory.CreateHostBuilderCalled); - Assert.False(factory.CreateHostCalled); + Assert.True(factory.CreateHostCalled); } [Fact] @@ -48,7 +48,7 @@ public void TestingInfrastructure_GenericHost_WithWithHostBuilderRespectsCustomi Assert.False(factory.GetTestAssembliesCalled); Assert.True(factory.CreateHostBuilderCalled); Assert.True(factory.CreateHostCalled); - Assert.False(factory.CreateServerCalled); + Assert.True(factory.CreateServerCalled); Assert.False(factory.CreateWebHostBuilderCalled); } @@ -147,6 +147,12 @@ protected override TestServer CreateServer(IWebHostBuilder builder) return base.CreateServer(builder); } + protected override TestServer CreateServer(IServiceProvider serviceProvider) + { + CreateServerCalled = true; + return base.CreateServer(serviceProvider); + } + protected override IHost CreateHost(IHostBuilder builder) { CreateHostCalled = true; From e2a1342c3fc0031db6902cd7d60385cfee003c77 Mon Sep 17 00:00:00 2001 From: Brennan Date: Tue, 15 Jul 2025 13:57:22 -0700 Subject: [PATCH 8/9] cleanup --- src/Hosting/Hosting/src/GenericHost/GenericWebHostBuilder.cs | 2 +- src/Hosting/Hosting/test/WebHostBuilderTests.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Hosting/Hosting/src/GenericHost/GenericWebHostBuilder.cs b/src/Hosting/Hosting/src/GenericHost/GenericWebHostBuilder.cs index d50666bc369c..9d6f6c7e1d93 100644 --- a/src/Hosting/Hosting/src/GenericHost/GenericWebHostBuilder.cs +++ b/src/Hosting/Hosting/src/GenericHost/GenericWebHostBuilder.cs @@ -20,7 +20,7 @@ namespace Microsoft.AspNetCore.Hosting; internal sealed class GenericWebHostBuilder : WebHostBuilderBase, ISupportsStartup { - private const string _startupConfigName = "__UseStartup.StartupType"; + private const string _startupConfigName = "__UseStartup.StartupObject"; private readonly object _startupKey = new object(); private AggregateException? _hostingStartupErrors; diff --git a/src/Hosting/Hosting/test/WebHostBuilderTests.cs b/src/Hosting/Hosting/test/WebHostBuilderTests.cs index af7026409880..caf6d2a6958f 100644 --- a/src/Hosting/Hosting/test/WebHostBuilderTests.cs +++ b/src/Hosting/Hosting/test/WebHostBuilderTests.cs @@ -1681,11 +1681,11 @@ public void Configure(IWebHostBuilder builder) // This check is required because MVC still uses the // IWebHostEnvironment instance before the container is baked #pragma warning disable CS0618 // Type or member is obsolete - var heDescriptor = services.FirstOrDefault(s => s.ServiceType == typeof(IHostingEnvironment)); + var heDescriptor = services.LastOrDefault(s => s.ServiceType == typeof(IHostingEnvironment)); Assert.NotNull(heDescriptor); Assert.NotNull(heDescriptor.ImplementationInstance); #pragma warning restore CS0618 // Type or member is obsolete - var wheDescriptor = services.FirstOrDefault(s => s.ServiceType == typeof(IWebHostEnvironment)); + var wheDescriptor = services.LastOrDefault(s => s.ServiceType == typeof(IWebHostEnvironment)); Assert.NotNull(wheDescriptor); Assert.NotNull(wheDescriptor.ImplementationInstance); }) From d15eabdd3f09b8b250f6c1ddefbc3afa6fc4fbe3 Mon Sep 17 00:00:00 2001 From: Brennan Date: Wed, 16 Jul 2025 14:26:10 -0700 Subject: [PATCH 9/9] fix multiple of same startup --- .../src/GenericHost/GenericWebHostBuilder.cs | 4 ++++ .../test/GenericWebHostBuilderTests.cs | 23 +++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/src/Hosting/Hosting/src/GenericHost/GenericWebHostBuilder.cs b/src/Hosting/Hosting/src/GenericHost/GenericWebHostBuilder.cs index 9d6f6c7e1d93..83f416fa0089 100644 --- a/src/Hosting/Hosting/src/GenericHost/GenericWebHostBuilder.cs +++ b/src/Hosting/Hosting/src/GenericHost/GenericWebHostBuilder.cs @@ -178,6 +178,7 @@ public IWebHostBuilder UseStartup([DynamicallyAccessedMembers(StartupLinkerOptio if (_builder.Properties.TryGetValue(_startupConfigName, out var startupObject) && object.ReferenceEquals(startupObject, startupType)) { + _builder.Properties.Remove(_startupConfigName); UseStartup(startupType, context, services); } }); @@ -205,6 +206,7 @@ void ConfigureStartup(HostBuilderContext context, IServiceCollection services) if (_builder.Properties.TryGetValue(_startupConfigName, out var startupObject) && object.ReferenceEquals(startupObject, startupFactory)) { + _builder.Properties.Remove(_startupConfigName); var webHostBuilderContext = GetWebHostBuilderContext(context); var instance = startupFactory(webHostBuilderContext) ?? throw new InvalidOperationException("The specified factory returned null startup instance."); UseStartup(instance.GetType(), context, services, instance); @@ -325,6 +327,7 @@ public IWebHostBuilder Configure(Action configure) if (_builder.Properties.TryGetValue(_startupConfigName, out var startupObject) && object.ReferenceEquals(startupObject, configure)) { + _builder.Properties.Remove(_startupConfigName); services.Configure(options => { options.ConfigureApplication = configure; @@ -349,6 +352,7 @@ public IWebHostBuilder Configure(Action(options => { var webhostBuilderContext = GetWebHostBuilderContext(context); diff --git a/src/Hosting/Hosting/test/GenericWebHostBuilderTests.cs b/src/Hosting/Hosting/test/GenericWebHostBuilderTests.cs index 4041503fb1d5..5d940a63c8dc 100644 --- a/src/Hosting/Hosting/test/GenericWebHostBuilderTests.cs +++ b/src/Hosting/Hosting/test/GenericWebHostBuilderTests.cs @@ -153,6 +153,29 @@ public async Task MultipleConfigureWebHostCallsWithUseStartupLastWins() await AssertResponseContains(server.RequestDelegate, "SecondStartup"); } + [Fact] + public async Task MultipleConfigureWebHostCallsWithSameUseStartupOnlyRunsOne() + { + var server = new TestServer(); + + using var host = new HostBuilder() + .ConfigureWebHost(webHostBuilder => + { + webHostBuilder + .UseServer(server) + .UseStartup(); + }) + .ConfigureWebHost(webHostBuilder => + { + webHostBuilder + .UseStartup(); + }) + .Build(); + + await host.StartAsync(); + Assert.Single(host.Services.GetRequiredService>()); + } + private async Task AssertResponseContains(RequestDelegate app, string expectedText) { var httpContext = new DefaultHttpContext();