AspNetCore.Docs icon indicating copy to clipboard operation
AspNetCore.Docs copied to clipboard

Sample code returns 404

Open ghost opened this issue 2 years ago • 7 comments

Issue: the test suite returns 404 using the sample code. Note: I can hit them with Swagger UI.

Request: document the process model in order for developers to diagnose 404 responses quicker:

  • What URL/port does the test framework run?
  • The documentation hints that the SUT is hosted at http://localhost:80 from the suggestion to add BaseAddress = "https://localhost" to avoid HTTPS redirects. However that doesn't make sense since ports < 1024 are blocked by Windows for non-privileges processes.

My code:

public partial class Program { // Made the class partial as suggested in the docs but I don't know why this is necessary. Maybe clarify why?
  public static void Main(string[] args)
  {
    var builder = WebApplication.CreateBuilder(webApplicationOptions);
    var app = builder.Build();
    //Service configuration code omitted
    //Note: I call builder.Configuration.AddAzureAppConfiguration() to retrieve config values from Azure Cloud
    app.Run();
  }
}

public class MyWebApplicationFactory<TProgram> : WebApplicationFactory<TProgram> where TProgram : class
{
  protected override void ConfigureWebHost(IWebHostBuilder builder) {
    builder.UseEnvironment("Development");
  }
}

public class HomeControllerTests : IClassFixture<MyWebApplicationFactory<Program>> {
  [Fact]
  public void Get_Index_ReturnOk() {
    var a = (await _client.GetAsync("/home")).StatusCode; // Returns 404 not 200
    var b = (await _client.GetAsync("/")).StatusCode; // Returns 404 not 200
  }
}

Update:

Looks like removing the ApplicationName assignment in var builder = WebApplication.CreateBuilder(new WebApplicationOptions { ApplicationName = Assembly.GetEntryAssembly().GetName().Name }); solves the 404 issues.

Request:

  • Add document to forbid developers from modifying ApplicationName in CreateBuilder().

Related: https://stackoverflow.com/a/75306984


Document Details

Do not edit this section. It is required for learn.microsoft.com ➟ GitHub issue linking.

ghost avatar Oct 04 '23 19:10 ghost

@jvandertil @martincostello please review.

Rick-Anderson avatar Oct 05 '23 00:10 Rick-Anderson

Seems reasonable to me to not set ApplicationName - it's not something I've ever done in all my usage of the MVC testing library.

martincostello avatar Oct 05 '23 09:10 martincostello

Seems reasonable to me to not set ApplicationName - it's not something I've ever done in all my usage of the MVC testing library.

Suggestions:

  1. Remove ApplicationName from the arguments class so as to prevent the developer from silently breaking their testing projects (and who knows what else). As you've stated it is rarely ever set. Note: I believe my team set it to include a shorter descriptor of the app's process name in the logging.
  2. Patch the testing library to allow for ApplicationName to be changed.
  3. Leave as-is. Issue: hard to debug due to opaqueness of the testing library's process model but thank God I found a Stackoverflow solution! Thus it would be beneficial to add a "WARNING: do not touch ApplicationName in the docs!"

ghost avatar Oct 05 '23 13:10 ghost

Removing ApplicationName would be a breaking change, and while I've not used it myself, I'm sure it has its uses independent of the MVC testing library - otherwise why would it even be there?

I think the only sensible solution is 2, i.e. diagnose why it breaks things, and then if possible update the testing library to support that scenario.

Changing the testing-related docs to not use something they don't need to demonstrate which actively breaks the demo is just part of a larger end-to-end resolution.

martincostello avatar Oct 05 '23 13:10 martincostello

@3pillardeveloper

Looks like removing the ApplicationName assignment in var builder = WebApplication.CreateBuilder(new WebApplicationOptions { ApplicationName = Assembly.GetEntryAssembly().GetName().Name }); solves the 404 issues.

Where is that set?

Rick-Anderson avatar Oct 17 '23 02:10 Rick-Anderson

@3pillardeveloper

Looks like removing the ApplicationName assignment in var builder = WebApplication.CreateBuilder(new WebApplicationOptions { ApplicationName = Assembly.GetEntryAssembly().GetName().Name }); solves the 404 issues.

Where is that set?

The builder variable is set in our class Program.

ghost avatar Oct 17 '23 12:10 ghost

@Rick-Anderson I tried some things and these are my findings. For this I modified the RazorPagesProject we have in the Samples repository for integration testing (https://github.com/dotnet/AspNetCore.Docs.Samples/blob/5aac3b4b9774277bbeebf7a1fdfc05aba8aa9675/test/integration-tests/IntegrationTestsSample/src/RazorPagesProject/Program.cs#L13).

Works means all tests are green. Does not work means endpoints return 404 and all tests fail.

What we have currently, works:

var appBuilder = WebApplication.CreateBuilder(args);

Passing empty options, does not work:

var appBuilder = WebApplication.CreateBuilder(new WebApplicationOptions
{
});

Passing options with args, works:

var appBuilder = WebApplication.CreateBuilder(new WebApplicationOptions
{
    Args = args,
});

Using the empty overload, does not work:

var appBuilder = WebApplication.CreateBuilder();

The example shared in this issue, does not work:

var appBuilder = WebApplication.CreateBuilder(new WebApplicationOptions
{
    ApplicationName = Assembly.GetEntryAssembly().GetName().Name,
});

NOTE: The assembly returned from Assembly.GetEntryAssembly() is testhost.dll

Passing args does not make a difference, this also does not work:

var appBuilder = WebApplication.CreateBuilder(new WebApplicationOptions
{
    ApplicationName = Assembly.GetEntryAssembly().GetName().Name,
    Args = args,
});

This does work:

var appBuilder = WebApplication.CreateBuilder(new WebApplicationOptions
{
    ApplicationName = typeof(Program).Assembly.GetName().Name,
});

Looking at the code the ApplicationName is used as the ApplicationKey (haven't looked what that is used for yet), and the WebApplicationFactory tries to set it basically typeof(Program).Assembly.GetName().Name through the TEntryPoint generic.

Not sure what we should document around this behavior.

jvandertil avatar Jan 29 '24 18:01 jvandertil