Aspnetcore: ConfigureTestContainer not working with GenericHost

Created on 11 Oct 2019  路  54Comments  路  Source: dotnet/aspnetcore

Describe the bug

When using GenericHost, in tests ConfigureTestContainer is not executed.

To Reproduce

I've added a test in https://github.com/alefranz/AspNetCore/commit/282c153cfd343498928636780558031f0ab940b2#diff-589b0cebe9e796b47e521f0318393df2R194-R208 to reproduce

Expected behavior

The delegate provided with ConfigureTestContainer should be executed

Additional context

This happen in 3.x

I'm looking at providing a fix for this but I would probably need some hint on the right place to address this.
Could you also confirm the behavior is not intentional?

@Tratcher I've seen you have worked to add support to ConfigureTestServices with GenericHost in https://github.com/aspnet/AspNetCore/pull/6585/files#diff-48af505b9d348e7e52da534c4590aef1R36 - Do you think it would need a similar logic to address this as well?

Thank you,
Alessio

affected-medium area-hosting bug severity-major

Most helpful comment

OK waking up and re-reading this issue. IT does seem like a bug that should be fixed and potentially patched though it is risky (maybe it'll need to be quirked). I will follow up with some people.

All 54 comments

There were reasons... I don't think ConfigureTestContainer was compatible. @javiercn might remember.

@alefranz thanks for contacting us.

In previous versions the reason we had ConfigureTest(Services|Container) was due to the fact that the Configure(Services|Container) in Startup ran after all the ConfigureTest(Services|Container) methods applied to the host builder and we needed a way to run a Configure(Services|Container) callback after that happened to ensure services could be overriden for testing purposes.

When we moved to generic host, we changed that behavior and now the callbacks are queued in the order in which you register them, so when you do UseStartup the callback gets immediately queued. For that reason, if you are using generic host you shouldn't need the ConfigureTestContainer overload, you can simply call hostBuilder.ConfigureContainer after the call to UseStartup to tweak the container configuration.

I don't know what work @Tratcher did to make it work for ConfigureTestServices. I think the main reason we didn't do it is because we might have thought it was a much less common use case.

If ConfigureTestServices is supported on generic host, @Tratcher is ok with it, and it's not a big change, I'm supportive of a PR to make ConfigureTestContainer work too, if you want to give it a try.

I don't think we will fix ourselves as it's not a common scenario and there is an alternative way to achieve the same thing as described above, so this only helps you in migration scenarios.

Otherwise, I simply recommend closing the issue.

Hope this helps.

I will investigate the scope of a change to make it work.
If this is too big of a change, what do you think about throwing an exception that clearly indicates that it is not supported in this scenario and what to use instead?
With the current behavior there is a risk to spend time in trying to understand why you don't have the expected services in the container (talking from experience 馃槄).

@javiercn I'm having a similar issue and have tried to make the updates that you suggested above. However, I'm having an issue because my Startup.ConfigureContainer method is always being called after my call to IHostBuilder.ConfigureContainer. It doesn't seem to matter what order I set them up with.

@javiercn I did confirm that if I remove Startup.ConfigureContainer and instead put that code into a call to IHostBuilder.ConfigureContainer then it does appear to all get executed in the right order.

@roend83 It's impossible for us to diagnose what's going on in your case without a minimal repro project. How DI works with the new container is explained a bit better here:
https://github.com/aspnet/AspNetCore.Docs/issues/14973

AspNetCoreConfigurationIssue.zip
@javiercn Here's a minimal repro of what I'm seeing.

@roend83 Thanks for the repro.

@Tratcher I took a quick look at the repro and @roend83 seems legit. Can you take a look?

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .UseServiceProviderFactory(new AutofacServiceProviderFactory())
                .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); })
                .ConfigureContainer<ContainerBuilder>(builder =>
                {
                    if (!Startup.IsContainerConfigured)
                    {
                        throw new Exception("Startup.ConfigureContainer hasn't been called yet'");
                    }
                });

My understanding is that that should never throw as Startup.ConfigureContainer should run before the ConfigureContainer after it, isn't that the case?

This gets hit first:

>   AspNetCoreConfigurationIssue.dll!AspNetCoreConfigurationIssue.Program.CreateHostBuilder.AnonymousMethod__1_1(Autofac.ContainerBuilder builder) Line 27  C#
    Microsoft.Extensions.Hosting.dll!Microsoft.Extensions.Hosting.HostingHostBuilderExtensions.ConfigureContainer.AnonymousMethod__0(Microsoft.Extensions.Hosting.HostBuilderContext context, System.__Canon builder)   Unknown
    Microsoft.Extensions.Hosting.dll!Microsoft.Extensions.Hosting.Internal.ConfigureContainerAdapter<Autofac.ContainerBuilder>.ConfigureContainer(Microsoft.Extensions.Hosting.HostBuilderContext hostContext, object containerBuilder) Unknown
    Microsoft.Extensions.Hosting.dll!Microsoft.Extensions.Hosting.HostBuilder.CreateServiceProvider()   Unknown
    Microsoft.Extensions.Hosting.dll!Microsoft.Extensions.Hosting.HostBuilder.Build()   Unknown
    AspNetCoreConfigurationIssue.dll!AspNetCoreConfigurationIssue.Program.Main(string[] args) Line 18   C#

And this second:

>   AspNetCoreConfigurationIssue.dll!AspNetCoreConfigurationIssue.Startup.ConfigureContainer(Autofac.ContainerBuilder builder) Line 56  C#
    [Native to Managed Transition]  
    [Managed to Native Transition]  
    Microsoft.AspNetCore.Hosting.dll!Microsoft.AspNetCore.Hosting.ConfigureContainerBuilder.InvokeCore(object instance, object container)   Unknown
    Microsoft.AspNetCore.Hosting.dll!Microsoft.AspNetCore.Hosting.ConfigureContainerBuilder.Invoke.__StartupConfigureContainer|0(object containerBuilder)   Unknown
    Microsoft.AspNetCore.Hosting.dll!Microsoft.AspNetCore.Hosting.ConfigureContainerBuilder.Invoke(object instance, object container)   Unknown
    Microsoft.AspNetCore.Hosting.dll!Microsoft.AspNetCore.Hosting.ConfigureContainerBuilder.Build.AnonymousMethod__0(object container)  Unknown
    Microsoft.AspNetCore.Hosting.dll!Microsoft.AspNetCore.Hosting.GenericWebHostBuilder.ConfigureContainer<System.__Canon>(Microsoft.Extensions.Hosting.HostBuilderContext context, System.__Canon container)   Unknown
    Microsoft.Extensions.Hosting.dll!Microsoft.Extensions.Hosting.Internal.ConfigureContainerAdapter<Autofac.ContainerBuilder>.ConfigureContainer(Microsoft.Extensions.Hosting.HostBuilderContext hostContext, object containerBuilder) Unknown
    Microsoft.Extensions.Hosting.dll!Microsoft.Extensions.Hosting.HostBuilder.CreateServiceProvider()   Unknown
    Microsoft.Extensions.Hosting.dll!Microsoft.Extensions.Hosting.HostBuilder.Build()   Unknown
    AspNetCoreConfigurationIssue.dll!AspNetCoreConfigurationIssue.Program.Main(string[] args) Line 18   C#

ConfigureContainer actions are called in the order registered:
https://github.com/aspnet/Extensions/blob/b3a158ac055f1f8f76ed4a1a1c6ef860068cf63e/src/Hosting/Hosting/src/HostBuilder.cs#L228-L231
This is where generic web host finds and calls ConfigureContainer:
https://github.com/aspnet/AspNetCore/blob/c7972d45f83aab461d23616a9c17fe5fe3ad2226/src/Hosting/Hosting/src/GenericHost/GenericWebHostBuilder.cs#L260-L263
Which is called inline...

>   AspNetCoreConfigurationIssue.dll!AspNetCoreConfigurationIssue.Program.CreateHostBuilder.AnonymousMethod__1_0(Microsoft.AspNetCore.Hosting.IWebHostBuilder webBuilder) Line 24   C#
    Microsoft.AspNetCore.dll!Microsoft.Extensions.Hosting.GenericHostBuilderExtensions.ConfigureWebHostDefaults.AnonymousMethod__0(Microsoft.AspNetCore.Hosting.IWebHostBuilder webHostBuilder) Unknown
    Microsoft.AspNetCore.Hosting.dll!Microsoft.Extensions.Hosting.GenericHostWebHostBuilderExtensions.ConfigureWebHost(Microsoft.Extensions.Hosting.IHostBuilder builder, System.Action<Microsoft.AspNetCore.Hosting.IWebHostBuilder> configure)    Unknown
    Microsoft.AspNetCore.dll!Microsoft.Extensions.Hosting.GenericHostBuilderExtensions.ConfigureWebHostDefaults(Microsoft.Extensions.Hosting.IHostBuilder builder, System.Action<Microsoft.AspNetCore.Hosting.IWebHostBuilder> configure)   Unknown
    AspNetCoreConfigurationIssue.dll!AspNetCoreConfigurationIssue.Program.CreateHostBuilder(string[] args) Line 22  C#
    AspNetCoreConfigurationIssue.dll!AspNetCoreConfigurationIssue.Program.Main(string[] args) Line 18   C#

Ah, but UseStartup is delayed until ConfigureServices runs.
https://github.com/aspnet/AspNetCore/blob/c7972d45f83aab461d23616a9c17fe5fe3ad2226/src/Hosting/Hosting/src/GenericHost/GenericWebHostBuilder.cs#L203-L209
That explains the order inversion. Here's how it works out:

  • Program: ConfigureWebHostDefaults, UseStartup
  • Program: ConfigureContainer (register callback)
  • Build, CreateServiceProvider
  • ConfigureServices

    • UseStartup registers Startup.ConfigureContainer callback

  • ConfigureContainer

    • Program ConfigureContainer callback

    • Startup ConfigureContainer callback

Trying to fix this would likely require moving the delayed call to UseStartup out of ConfigureServices. Not sure what other consequences that would have.

I have the exact same issue. Is there a workaround that would allow us to bypass this issue?

@GODBS I ended up going the super-hacky route, for now. I hope this is fixed in 3.1.

c# internal static Action<ContainerBuilder> IntegTestOverrides = null; public void ConfigureContainer(ContainerBuilder cb) { cb.RegisterModule(new ApiRootModule()); cb.RegisterType<StartupHttpPipeline>().As<IStartupHTTPPipeline>(); IntegTestOverrides?.Invoke(cb); }

@cdibbs no changes are planned for 3.1.

Will a fix come with a later patch to 3.1? Requiring hacks to override dependencies in your tests seems like a pretty undesirable thing to enter LTS with.

Unlikely. Patching is risky and anything with a viable workaround is unlikely to be patched.

Take a look at this article for more information about AspNet Core 3.0 integration tests
https://andrewlock.net/converting-integration-tests-to-net-core-3/

As @roend83 mentioned it works when adding third party DI registrations at the time the IHostBuilder is bein set up.
Take a look here for an example

https://github.com/seesharper/heatkeeper/blob/master/src/HeatKeeper.Server.Host/Program.cs

And the customization of the container during test is here

https://github.com/seesharper/heatkeeper/blob/master/src/HeatKeeper.Server.WebApi.Tests/TestBase.cs

The resolution I am using is below.

          public class TestApplicationFactory : WebApplicationFactory<Startup>
        {
            protected override IHost CreateHost(IHostBuilder builder)
            {
                builder.ConfigureContainer<ContainerBuilder>(containerBuilder =>
                    {

                    });

                return base.CreateHost(builder);
            }
        }

The ConfigureContainer registered inside WebApplicationFactory is called after ConfigureContainer by the generic host builder inside Program.cs.

The resolution I am using is below.

          public class TestApplicationFactory : WebApplicationFactory<Startup>
        {
            protected override IHost CreateHost(IHostBuilder builder)
            {
                builder.ConfigureContainer<ContainerBuilder>(containerBuilder =>
                    {

                    });

                return base.CreateHost(builder);
            }
        }

The ConfigureContainer registered inside WebApplicationFactory is called after ConfigureContainer by the generic host builder inside Program.cs.

I tried this. Seemed to face the same problem in my implementation... What am i missing?

Using 3.1, we're using autofac and calling ConfigureContainer(ContainerBuilder builder) from startup. This seems to execute in the same order...

All due respect, I am sorry but the provided answers to this issues are simply not satisfactory.

When we moved to generic host, we changed that behavior and now the callbacks are queued in the order in which you register them, so when you do UseStartup the callback gets immediately queued. For that reason, if you are using generic host you shouldn't need the ConfigureTestContainer overload, you can simply call hostBuilder.ConfigureContainer after the call to UseStartup to tweak the container configuration.

This does not work, as demonstrated in Tratcher's post here: https://github.com/aspnet/AspNetCore/issues/14907#issuecomment-542388201

@javiercn 's description in https://github.com/aspnet/AspNetCore/issues/14907#issuecomment-541011786 implies to be the intended behaviour is that Startup.ConfigureContainer should be called after Program.ConfigureContainer if the later is called after UseStarup. This is not the case which means it is a plain bug.

None of the technique above are working, meaning that there is no apparent nor easy workaround. I'm excluding @cdibbs 's techniques which prevents testing in parallel.

This issue prevents from having a proper way for tests to override dependencies, which is a huge issue for us (and I suspect many other). We have tons of tests doing exactly that and this bug prevents us from moving from 2.1 to 3.1

This is a big show-stopper for anyone who wants to properly test his application.

I have investigated a fix but unfortunately, as well explained by @Tratcher , to fix this would have potential side effects so I parked my work.
@anurse would a PR be considered or it is to risky to do change this behavior as 3.1 has already been released?
Should the effort instead be in documenting a working hack?
Thank you!

I agree with @Pvlerick that my workaround doesn't work when you run the tests in parallel (which is the norm). So, is my workaround really "viable?" Maybe not.

It sounds like any fix would have side effects, but perhaps that just builds a case for doubling up on the normal amount of testing done for a patch like this.

@cdibbs exactly. It's an ugly fix to try to make things work temporarily, this is not a solution that will be implemented across projects; I don't see myself explaining to other developers that this is how they should inject theirs mocks from now on, moving from a super-clean solution in 2.1 to a hack in 3.1.

We need this addressed badly :-(

I got it working by implementing custom factory for my container setup. In my case its Autofac. I have tweaked the IServiceProviderFacotry implementation of Autofac library.

Code

public class CustomAutofacServiceProviderFactory : IServiceProviderFactory<ContainerBuilder>
{
    private readonly Action<ContainerBuilder> _configurationOverride;
    private readonly Action<ContainerBuilder> _configurationAction;
    /// <summary>
    /// Initializes a new instance of the <see cref="AutofacServiceProviderFactory"/> class.
    /// </summary>
    /// <param name="testStartup"></param>
    /// <param name="configurationAction">Action on a <see cref="ContainerBuilder"/> that adds component registrations to the conatiner.</param>
    public CustomAutofacServiceProviderFactory(Action<ContainerBuilder> configurationAction = null, Action<ContainerBuilder> configurationOverride = null)
    {
        _configurationOverride = configurationOverride;
        _configurationAction = configurationAction ?? (builder => { });
    }



    /// <summary>
    /// Creates a container builder from an <see cref="IServiceCollection" />.
    /// </summary>
    /// <param name="services">The collection of services.</param>
    /// <returns>A container builder that can be used to create an <see cref="IServiceProvider" />.</returns>
    public ContainerBuilder CreateBuilder(IServiceCollection services)
    {
        var builder = new ContainerBuilder();

        builder.Populate(services);

        _configurationAction(builder);

        return builder;
    }

    /// <summary>
    /// Creates an <see cref="IServiceProvider" /> from the container builder.
    /// </summary>
    /// <param name="containerBuilder">The container builder.</param>
    /// <returns>An <see cref="IServiceProvider" />.</returns>
    public IServiceProvider CreateServiceProvider(ContainerBuilder containerBuilder)
    {
        if (containerBuilder == null) throw new ArgumentNullException(nameof(containerBuilder));

        _configurationOverride(containerBuilder); // Added this to override container overrides
        var container = containerBuilder.Build();

        return new AutofacServiceProvider(container);
    }
}

Test Setup

public class CustomWebApplicationFactory : WebApplicationFactory where
TStartup:class
{

    protected override IHost CreateHost(IHostBuilder builder)
    {
        builder.ConfigureContainer<ContainerBuilder>(cb =>
        {
        }).UseServiceProviderFactory(
            new CustomAutofacServiceProviderFactory(
                b => { },
                OverrideContainer));


        return base.CreateHost(builder);
    }

}
Refer to Autofac docs https://autofaccn.readthedocs.io/en/latest/integration/aspnetcore.html for service registration

@ssunkari I haven't tried this yet, but again I don't see this as a viable workaround.

@anurse @davidfowl @DamianEdwards any views on this, do you think this can/will be patched?

@Pvlerick This has enough of a breaking impact (by changing the ordering) that it's generally not suitable for patching. It could break existing apps that were dependent on the ordering. We'll be looking at ordering changes for 5.0, but I don't expect this is something we could patch.

@Pvlerick This has enough of a breaking impact (by changing the ordering) that it's generally not suitable for patching. It could break existing apps that were dependent on the ordering. We'll be looking at ordering changes for 5.0, but I don't expect this is something we could patch.

Wouldn't that imply that someone has actually got this to work for it be be broken by a patch? Looking at the comments it seems like people aren't able to do their jobs, as the workaround just don't work.

@anurse this is really unfortunate... We have a lot of narrow integration tests that are redefining some of the dependencies and swapping them with mocks - calls to services. This bug prevents us from migrating as-is and implies a lot of refactoring, starting with something clean and ending with something ugly. I'm puzzled that something like that was overlooked, after all DI and testing are supposed to be an integral part of this product.

This is a pickle, I agree with @forktrucka that nobody seems to have this working. On the other hand I can see why you don't want to patch and possible break hypothetical implementations, but here we are with all the 2.x implementations irremediably breaking when going to 3.x

This workaround* of creating a derived TestStartup from @RehanSaeed is working for us: https://rehansaeed.com/asp-net-core-integration-testing-mocking-using-moq/

*I describe it as a workaround as it would be nicer not to have to make Configure and ConfigureServices on Startup virtual.

Agreed with @Pvlerick and unfortunately we have already migrate, and now looking for a solution to fix our tests. All suggested workarounds will not work for us, as we override services per test case. Any way to solve this in nearest future?

OK waking up and re-reading this issue. IT does seem like a bug that should be fixed and potentially patched though it is risky (maybe it'll need to be quirked). I will follow up with some people.

Is everyone using ConfigureTestContainer here? ConfigureTestServices works fine right?

@davidfowl yes, the issue is when using a 3rd party container, e.g. Autofac
I've been busy moving moving many services to the Microsoft DI, but we still have some using Autofac, so I would be happy to look at this again if now there is a chance of this change to be considered for a patch release

@davidfowl my original issue that forwarded me here (#19404) is how to handle ConfigureServices getting called twice during integration tests.

As @javiercn suggested in #12360, I am able to do something like the below, but this is obviously not ideal, so I wanted to see if there a better solution established for this.

For example:
Integration Test
````
public class WeatherForecastIntegTest : IClassFixture>
{

    [Fact]
    public async Task PostForecastReturnsSuccessCodeAndResourceWithAccurateFields() 
    {
        var appFactory = new ServerFactory<Startup> { };
        var client = appFactory.CreateClient();
        var fakeWeatherForecast = new WeatherForecast { Id = 1 };

        // Act
        var httpResponse = await client.PostAsJsonAsync("/weatherforecast", fakeWeatherForecast)
            .ConfigureAwait(false);
        httpResponse.EnsureSuccessStatusCode();

        var resultDto = JsonConvert.DeserializeObject<WeatherForecast>(await httpResponse.Content.ReadAsStringAsync()
            .ConfigureAwait(false));

        // Assert
        httpResponse.StatusCode.Should().Be(201);
    }
}

````

ServerFactory (simple POC)
````
public class ServerFactory : WebApplicationFactory
where TStartup : class
{
public ServerFactory()
{
ClientOptions.AllowAutoRedirect = false;
ClientOptions.BaseAddress = new Uri("https://localhost");
}

    protected override IHostBuilder CreateHostBuilder()
    {
        return Program.CreateHostBuilder(new[] { "--use-startup=false" });
    }

    protected override void ConfigureWebHost(IWebHostBuilder builder)
    {
        base.ConfigureWebHost(builder);
        builder.UseStartup<TStartup>();
    }
}

````

Program.cs
.ConfigureWebHostDefaults(webBuilder => { if (!args.Contains("--use-startup=false")) { webBuilder.UseStartup(typeof(Startup).GetTypeInfo().Assembly.FullName) .UseContentRoot(Directory.GetCurrentDirectory()) .UseKestrel() .UseNLog(); } });

Got hit by this very problem while migrating a 2.2 codebase to 3.x

Here is a workaround for Autofac that will call any ConfigureTestContainer(...) method, also in .WithWebHostBuilder(...) calls.

It builds on @ssunkari's workaround

public class CustomWebApplicationFactory<TStartup> : WebApplicationFactory<TStartup>
        where TStartup : class
{
    protected override void ConfigureWebHost(IWebHostBuilder webHostBuilder)
    {
        webHostBuilder.ConfigureTestContainer<Autofac.ContainerBuilder>(builder =>
        {
            // called after Startup.ConfigureContainer
        });
    }

    protected override IHost CreateHost(IHostBuilder builder)
    {
        builder.UseServiceProviderFactory(new CustomServiceProviderFactory());
        return base.CreateHost(builder);
    }
}

public class CustomServiceProviderFactory : IServiceProviderFactory<CustomContainerBuilder>
{
    public CustomContainerBuilder CreateBuilder(IServiceCollection services) => new CustomContainerBuilder(services);

    public IServiceProvider CreateServiceProvider(CustomContainerBuilder containerBuilder) =>
        new AutofacServiceProvider(containerBuilder.CustomBuild());
}

public class CustomContainerBuilder : Autofac.ContainerBuilder
{
    private readonly IServiceCollection services;

    public CustomContainerBuilder(IServiceCollection services)
    {
        this.services = services;
        this.Populate(services);
    }

    public Autofac.IContainer CustomBuild()
    {
        var sp = this.services.BuildServiceProvider();
#pragma warning disable CS0612 // Type or member is obsolete
        var filters = sp.GetRequiredService<IEnumerable<IStartupConfigureContainerFilter<Autofac.ContainerBuilder>>>();
#pragma warning restore CS0612 // Type or member is obsolete

        foreach (var filter in filters)
        {
            filter.ConfigureContainer(b => { })(this);
        }

        return this.Build();
    }
}

Usage

var factory = new CustomWebApplicationFactory<Startup>();

var client1 = factory.CreateClient();


var client2 = factory.WithWebHostBuilder(b =>
{
    b.ConfigureTestContainer<Autofac.ContainerBuilder>(builder =>
    {
        // Called after Startup.ConfigureContainer and after CustomWebApplicationFactory's ConfigureTestContainer
    });
}).CreateClient();

Thanks @jr01 - from one JR to another 馃槈

I do hope this gets resolved through changes to ASP.Net Core. I was starting to consider if it was worth attempting to remove Autofac from my (not small) application. That would have been a lot of work, so I'm glad there's a workaround that will allow me to still face myself in the mirror. 鉂わ笍

It's been twice in three weeks that I've found myself coming back to this post to try and remember the workaround for this issue. I'll try and turn it into a blog post so people can have a reference for how to remedy the situation until it's fixed. I wouldn't want people to not write tests 馃槈

This issue always makes me facepalm... love ASP.NET Core but I can't figure out why this is such a painful experience. Feel like we're so close to being the number one web framework. Especially with Blazor RTM.

One blog post that I hope to be irrelevant one day 馃

https://blog.johnnyreilly.com/2020/05/autofac-webapplicationfactory-and.html

Just one more vote to fix the issue from my side.
After a full day of work, I have not yet been able to set up a workaround.
EDIT: After updating Autofac and Autofac.Extensions.DependencyInjection the workaround worked.

@jr01's workaround prevents update to Autofac 6.0.0 because they sealed their ContainerBuilder. Therefore a fix would still be appreciated here.

@matthias-schuchardt Did you open an issue with Autofac? They asked people to speak up and offer reasons not to do this.

@matthias-schuchardt Did you open an issue with Autofac? They asked people to speak up and offer reasons not to do this.

Personally I think their reasoning is valid. And I wouldn't want them to keep open this source of unintended usage just to work around an issue with the WebApplicationFactory that @davidfowl will hopefully tackle.

Yeah, but, we've been waiting for a fix for this for a year. Seems much easier to just ask Autofac to compromise (or help thinking of another workaround, but Travis is pretty busy so probably reverting is easier).

I've put a comment on the issue @matthias-schuchardt linked appealing to @tillig to unseal Autofac's ContainerBuilder. Here's hoping 馃

https://github.com/autofac/Autofac/issues/1120#issuecomment-701550921

This is the first I'm hearing of any of this. I'll likely not chime in here too much on the Autofac-specific side of things since we'll handle it in issues over there, but my first thought is to _not_ unseal ContainerBuilder to work around something like this if it can be avoided. I'd like to gather some options and determine what's the most supportable thing we might be able to do going forward.

For example, I see the custom service provider factory addresses a lot, maybe that's a better answer. I also saw a blog article earlier about using a TestStartup that drives from Startup and uses a virtual on ConfigureContainer to handle test registration. That seems like a pretty reasonable workaround to me and doesn't even require Autofac changes.

I will say, I'm not super interested in doing things to Autofac that will specifically work around trying to get a method called ConfigureTestContainer to be called due to a change in the base framework. If we can find something that will work to allow test overrides to be provided - even if it's not literally "it'll still call ConfigureTestContainer!" - then that'll be good enough on the Autofac end.

@tillig Thanks, wasn't expecting you to say yes, but thought it was worth people asking.

To wrap this up, Alistair tweaked the workaround provided by @jr01 to also work with the sealed ContainerBuilder of Autofac >= 6.0.0. So we can await .NET 5.0 without having to worry that it would break our integration tests.

It's worth checking out the issue below if you're an Autofac user for a suggestion by @alistairjevans which supports a way to work with ConfigureTestContainer which will work with Autofac 6:

https://github.com/autofac/Autofac/issues/1207#issuecomment-701961371

However, as he pointed out, this depends upon the deprecated IStartupConfigureContainerFilter and so this may not represent a long-term solution

See also: https://blog.johnnyreilly.com/2020/10/autofac-6-integration-tests-and-generic-hosting.html

Haha @matthias-schuchardt you had the same thought as I did! Do you happen to know if IStartupConfigureContainerFilter is part of .NET 5? I don't see it in the docs and so actually there may still be an issue.

https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.hosting.istartupconfigurecontainerfilter-1.configurecontainer?view=aspnetcore-3.1

Good point, @johnnyreilly, I missed that. Then let's hope that this issue will be fixed in .NET 5.

.NET 5.0 is effectively complete at this point, it's unlikely we'll be able to address this.

Please try your workarounds with the RC1 build to make sure they still work.

Thanks for contacting us.
We're moving this issue to the Next sprint planning milestone for future evaluation / consideration. We will evaluate the request when we are planning the work for the next milestone. To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.

Was this page helpful?
0 / 5 - 0 ratings