question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

WebApplicationFactory does not work from when CreateHostBuilder is from another class + assembly, instead of the entry point assembly.

See original GitHub issue

Related

This issue is related to #8210 and (archived) Hosting #1517


Problem

The WebApplicationFactory doesn’t work right when the “entry point assembly” references another assembly which contains the CreateHostBuilder logic. Current code (I think) requires a method called CreateHostBuilder to exist in the entry point assembly, only.


Repo

A full repo of this problem can be found here in GitHub.


Description

I have a pretty standard ASP.NET Core 3.1 web api application and i’m trying to use the WebAppFactory to test my web application.

For my program.cs file, instead of adding my custom code in there (e.g. wire up Serilog, etc), I actually have a nuget package which I then re-use everywhere. So if I change my program.cs logic, I can just update various webapi applications with the latest nuget, instead of having to change the copy/paste code in each webapi program.cs class. Works really well.

Given this type of setup, the WebApplicationFactory fails to ResolveHostBuilderFactory because the entry point assembly doesn’t contain the CreateHostBuilder<T> method. And therefore stuff isn’t working 100% right.

For example.

this is my program.cs

public class Program
{
    public static Task Main()
    {
        var options = new MainOptions
        {
            FirstLoggingInformationMessage = "~~~ Starting FooBar Web Api  ~~~"
        };

        return Homely.AspNetCore.Hosting.CoreApp.Program.Main<Startup>(options);
    }
}

That’s it. Notice how it’s very different to the default template on first glance. So my program.cs class literally says: -> call some other assembly’s Main method and do stuff. It’s this other Main<T>(..) method that contains the typical template logic.

(That Main method logic is literally -> setup Serilog, do the normal program.cs templated stuff … then flush the Serilog on exit. So just logging plumbing wrapped around the default program.cs Main logic).

Okay - so my entry point assembly just calls some other assembly. Nothing crazy.

Except … it doesn’t work in this case because the WebApplicationFactory.CreateHostBuilder() code does this

protected virtual IHostBuilder CreateHostBuilder()
{
    var hostBuilder = HostFactoryResolver.ResolveHostBuilderFactory<IHostBuilder>(typeof(TEntryPoint).Assembly)?.Invoke(Array.Empty<string>());
    
<snip>
}

and that RHBF method then does this

        public static Func<string[], THostBuilder> ResolveHostBuilderFactory<THostBuilder>(Assembly assembly)
        {
            return ResolveFactory<THostBuilder>(assembly, CreateHostBuilder);
        }

        private static Func<string[], T> ResolveFactory<T>(Assembly assembly, string name)
        {
            var programType = assembly?.EntryPoint?.DeclaringType;
            if (programType == null)
            {
                return null;
            }

           <snip>
        }

and the assembly?.EntryPoint?.DeclaringType ends up returning null. Sadness 😦

So … I’m not sure what can be done here, for this scenario. It’s like I wish the code could ‘see’ that the entry point assembly is not the right place to check, but another assembly which I tell it, is what should be checked.

Secondly, I also tried this:

public class WebAppFactory : WebApplicationFactory<Homely.AspNetCore.Hosting.CoreApp.Program>

but that errored with: System.InvalidOperationException : The provided Type 'Program' does not belong to an assembly with an entry point. A common cause for this error is providing a Type from a class library. That’s exactly what I’m trying to do, though 😛

So - would love some help, please?


$ dotnet --info
.NET Core SDK (reflecting any global.json):
 Version:   3.1.100
 Commit:    cd82f021f4

Runtime Environment:
 OS Name:     Windows
 OS Version:  10.0.18362
 OS Platform: Windows
 RID:         win10-x64
 Base Path:   C:\Program Files\dotnet\sdk\3.1.100\

Host (useful for support):
  Version: 3.1.0
  Commit:  65f04fb6db

Issue Analytics

  • State:open
  • Created 4 years ago
  • Reactions:11
  • Comments:10 (8 by maintainers)

github_iconTop GitHub Comments

6reactions
msftbot[bot]commented, Oct 9, 2020

We’ve moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process.

3reactions
davidfowlcommented, Aug 10, 2021

.NET 6

Read more comments on GitHub >

github_iconTop Results From Across the Web

Supporting integration tests with WebApplicationFactory in ...
The generic parameter TEntryPoint is conventionally set to Startup , but it just needs to be a type inside the entry assembly, so...
Read more >
WebApplicationFactory throws error that contentRootPath ...
My solution for this problem is define WebApplicationFactory with Application Startup but setup WebHostBuilder with TestStartup.
Read more >
WebApplicationFactory<TEntryPoint> Class
The WebApplicationFactory<TEntryPoint> will find the entry point class of TEntryPoint assembly and initialize the application by calling IWebHostBuilder ...
Read more >
Integration tests in ASP.NET Core
WebApplicationFactory <TEntryPoint> is used to create a TestServer for the integration tests. TEntryPoint is the entry point class of the SUT ...
Read more >
Using custom startup class with ASP.NET Core integration ...
Using this custom web application factory doesn't come for free. We have to solve some issues when switching over to fake startup class:....
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found