diff --git a/src/Mvc/Mvc.Testing/src/DeferredHostBuilder.cs b/src/Mvc/Mvc.Testing/src/DeferredHostBuilder.cs index 9449c1f78416..ea58bf4faade 100644 --- a/src/Mvc/Mvc.Testing/src/DeferredHostBuilder.cs +++ b/src/Mvc/Mvc.Testing/src/DeferredHostBuilder.cs @@ -19,6 +19,8 @@ internal class DeferredHostBuilder : IHostBuilder private Action _configure; private Func? _hostFactory; + private readonly ConfigurationManager _hostConfiguration = new(); + // This task represents a call to IHost.Start, we create it here preemptively in case the application // exits due to an exception or because it didn't wait for the shutdown signal private readonly TaskCompletionSource _hostStartTcs = new(TaskCreationOptions.RunContinuationsAsynchronously); @@ -38,8 +40,18 @@ public DeferredHostBuilder() public IHost Build() { + // Hosting configuration is being provided by args so that + // we can impact WebApplicationBuilder based applications. + var args = new List(); + + // Transform the host configuration into command line arguments + foreach (var (key, value) in _hostConfiguration.AsEnumerable()) + { + args.Add($"--{key}={value}"); + } + // This will never be null if the case where Build is being called - var host = (IHost)_hostFactory!(Array.Empty()); + var host = (IHost)_hostFactory!(args.ToArray()); // We can't return the host directly since we need to defer the call to StartAsync return new DeferredHost(host, _hostStartTcs); @@ -59,7 +71,10 @@ public IHostBuilder ConfigureContainer(Action configureDelegate) { - _configure += b => b.ConfigureHostConfiguration(configureDelegate); + // Run this immediately so that we can capture the host configuration + // before we pass it to the application. We can do this for app configuration + // as well if it becomes necessary. + configureDelegate(_hostConfiguration); return this; } diff --git a/src/Mvc/Mvc.Testing/src/WebApplicationFactory.cs b/src/Mvc/Mvc.Testing/src/WebApplicationFactory.cs index a0f306e5e743..b5a2164391b4 100644 --- a/src/Mvc/Mvc.Testing/src/WebApplicationFactory.cs +++ b/src/Mvc/Mvc.Testing/src/WebApplicationFactory.cs @@ -159,6 +159,7 @@ private void EnsureServer() if (builder is null) { var deferredHostBuilder = new DeferredHostBuilder(); + deferredHostBuilder.UseEnvironment(Environments.Development); // This helper call does the hard work to determine if we can fallback to diagnostic source events to get the host instance var factory = HostFactoryResolver.ResolveHostFactory( typeof(TEntryPoint).Assembly, diff --git a/src/Mvc/test/Mvc.FunctionalTests/SimpleWithWebApplicationBuilderTests.cs b/src/Mvc/test/Mvc.FunctionalTests/SimpleWithWebApplicationBuilderTests.cs index 1af1563cfb3e..3c852c5de8ea 100644 --- a/src/Mvc/test/Mvc.FunctionalTests/SimpleWithWebApplicationBuilderTests.cs +++ b/src/Mvc/test/Mvc.FunctionalTests/SimpleWithWebApplicationBuilderTests.cs @@ -1,30 +1,37 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Collections.Generic; using System.Net; using System.Net.Http; using System.Threading.Tasks; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Mvc.Testing; +using Microsoft.AspNetCore.Testing; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Hosting; using Xunit; namespace Microsoft.AspNetCore.Mvc.FunctionalTests { public class SimpleWithWebApplicationBuilderTests : IClassFixture> { + private readonly MvcTestFixture _fixture; + public SimpleWithWebApplicationBuilderTests(MvcTestFixture fixture) { - Client = fixture.CreateDefaultClient(); + _fixture = fixture; } - public HttpClient Client { get; } - [Fact] public async Task HelloWorld() { // Arrange var expected = "Hello World"; + using var client = _fixture.CreateDefaultClient(); // Act - var content = await Client.GetStringAsync("http://localhost/"); + var content = await client.GetStringAsync("http://localhost/"); // Assert Assert.Equal(expected, content); @@ -35,9 +42,10 @@ public async Task JsonResult_Works() { // Arrange var expected = "{\"name\":\"John\",\"age\":42}"; + using var client = _fixture.CreateDefaultClient(); // Act - var response = await Client.GetAsync("/json"); + var response = await client.GetAsync("/json"); // Assert await response.AssertStatusCodeAsync(HttpStatusCode.OK); @@ -50,9 +58,10 @@ public async Task OkObjectResult_Works() { // Arrange var expected = "{\"name\":\"John\",\"age\":42}"; + using var client = _fixture.CreateDefaultClient(); // Act - var response = await Client.GetAsync("/ok-object"); + var response = await client.GetAsync("/ok-object"); // Assert await response.AssertStatusCodeAsync(HttpStatusCode.OK); @@ -65,9 +74,10 @@ public async Task AcceptedObjectResult_Works() { // Arrange var expected = "{\"name\":\"John\",\"age\":42}"; + using var client = _fixture.CreateDefaultClient(); // Act - var response = await Client.GetAsync("/accepted-object"); + var response = await client.GetAsync("/accepted-object"); // Assert await response.AssertStatusCodeAsync(HttpStatusCode.Accepted); @@ -79,8 +89,11 @@ public async Task AcceptedObjectResult_Works() [Fact] public async Task ActionReturningMoreThanOneResult_NotFound() { + // Arrange + using var client = _fixture.CreateDefaultClient(); + // Act - var response = await Client.GetAsync("/many-results?id=-1"); + var response = await client.GetAsync("/many-results?id=-1"); // Assert await response.AssertStatusCodeAsync(HttpStatusCode.NotFound); @@ -89,8 +102,11 @@ public async Task ActionReturningMoreThanOneResult_NotFound() [Fact] public async Task ActionReturningMoreThanOneResult_Found() { + // Arrange + using var client = _fixture.CreateDefaultClient(); + // Act - var response = await Client.GetAsync("/many-results?id=7"); + var response = await client.GetAsync("/many-results?id=7"); // Assert await response.AssertStatusCodeAsync(HttpStatusCode.MovedPermanently); @@ -98,14 +114,63 @@ public async Task ActionReturningMoreThanOneResult_Found() } [Fact] - public async Task ActionReturningProblemDetails_ConfiguresContentType() + public async Task DefaultEnvironment_Is_Development() + { + // Arrange + var expected = "Development"; + using var client = new WebApplicationFactory().CreateClient(); + + // Act + var content = await client.GetStringAsync("http://localhost/environment"); + + // Assert + Assert.Equal(expected, content); + } + + [Fact] + public async Task Configuration_Can_Be_Overridden() { + // Arrange + var fixture = _fixture.WithWebHostBuilder(builder => + { + builder.ConfigureAppConfiguration(builder => + { + var config = new[] + { + KeyValuePair.Create("Greeting", "Bonjour tout le monde"), + }; + + builder.AddInMemoryCollection(config); + }); + }); + + var expected = "Bonjour tout le monde"; + using var client = fixture.CreateDefaultClient(); + // Act - var response = await Client.GetAsync("/problem"); + var content = await client.GetStringAsync("http://localhost/greeting"); // Assert - await response.AssertStatusCodeAsync(HttpStatusCode.InternalServerError); - Assert.Equal("application/problem+json", response.Content.Headers.ContentType.ToString()); + Assert.Equal(expected, content); + } + + [Fact] + public async Task Environment_Can_Be_Overridden() + { + // Arrange + var fixture = _fixture.WithWebHostBuilder(builder => + { + builder.UseEnvironment(Environments.Staging); + }); + + var expected = "Staging"; + using var client = fixture.CreateDefaultClient(); + + // Act + var content = await client.GetStringAsync("http://localhost/environment"); + + // Assert + Assert.Equal(expected, content); } } } diff --git a/src/Mvc/test/WebSites/SimpleWebSiteWithWebApplicationBuilder/Program.cs b/src/Mvc/test/WebSites/SimpleWebSiteWithWebApplicationBuilder/Program.cs index 51aabd0a31f3..8c9fad1b937d 100644 --- a/src/Mvc/test/WebSites/SimpleWebSiteWithWebApplicationBuilder/Program.cs +++ b/src/Mvc/test/WebSites/SimpleWebSiteWithWebApplicationBuilder/Program.cs @@ -25,6 +25,10 @@ app.MapGet("/problem", () => Results.Problem("Some problem")); +app.MapGet("/environment", (IHostEnvironment environment) => environment.EnvironmentName); + +app.MapGet("/greeting", (IConfiguration config) => config["Greeting"]); + app.Run(); record Person(string Name, int Age);