Skip to content

React to WebHostBuilderFactory changes #6585

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Jan 15, 2019
Merged

React to WebHostBuilderFactory changes #6585

merged 7 commits into from
Jan 15, 2019

Conversation

Tratcher
Copy link
Member

#6460, #5960 The shared sources packages was moved to Extensions and refactored to support the new generic host templates pattern. This change:

  • Removes the old shared sources package
  • Updates TestHost
  • Updates MVC's WebApplicationFactory

Note to make WebApplicationFactory work I needed to skip calling two protected methods: CreateWebHostBuilder and CreateTestServer. Also, ConfigureTestServices isn't needed anymore since there's only one container.

@Tratcher Tratcher added this to the 3.0.0-preview2 milestone Jan 11, 2019
@Tratcher Tratcher self-assigned this Jan 11, 2019
@Tratcher Tratcher requested review from davidfowl, natemcmaster and javiercn and removed request for natemcmaster January 11, 2019 00:14
webHostBuilder.ConfigureServices(
s => s.AddSingleton<IStartupConfigureServicesFilter>(
new ConfigureTestServicesStartupConfigureServicesFilter(servicesConfiguration)));
if (webHostBuilder.GetType().Name.Equals("GenericWebHostBuilder"))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hacky, I like it 😄

Copy link
Member

@javiercn javiercn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall the PR looks good, but there are some changes we need to address before we move forward to ensure backwards compat and that the same user experience is preserved.

Copy link
Contributor

@natemcmaster natemcmaster left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few minor project-file things.

@Tratcher
Copy link
Member Author

@javiercn I added a protected method for CreateHostBuilder. CreateTestServer wasn't salvageable. I tried changing it to void Build() as discussed but that broke the DelegatedWebApplicationFactory model.

@Tratcher
Copy link
Member Author

Tratcher commented Jan 14, 2019

@javiercn I suggest we merge this for preview2 and follow up on further improvements. Ack?

@javiercn
Copy link
Member

@Tratcher let me take a look first

@javiercn
Copy link
Member

CreateTestServer wasn't salvageable. I tried changing it to void Build() as discussed but that broke the DelegatedWebApplicationFactory model.

@Tratcher I imagine that's because of the side effect of assigning the host. Is that the case?

@javiercn I suggest we merge this for preview2 and follow up on further improvements. Ack?

How much of the DelegatedWebApplicationFactoryModel broke? Everything, or only the CreateServer part?

You could fix the Build() part by passing the WAF as a parameter and adding a protected method to set it that check is null or throws before setting it. That way if someone customizes it, we can still call their implementation and they can set it in a safe way.

public virtual void CreateServer(WebApplicationFactory<TEntryPoint>waf, IHostBuilder builder)

On our implementation

CreateServer(this, builder);

On a derived implementation

...something,
waf.SetInitializedHost(host);
...

or

...something,
base.CreateServer(this,builder);
...something
...

Another alternative is to break it into two

public virtual IHost CreateHost(IHostBuilder builder)

and IServer {get;} be a shortcut for _host.Services.GetRequiredService();

We can clean it up after preview2, but I rather keep this working.

Copy link
Member

@javiercn javiercn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall looks good, just the feedback about CreateServer. If we change it to CreateHost(hostBuilder) and get rid of _server so that we can preserve the delegation model, we should be fine.

@natemcmaster
Copy link
Contributor

Approving from a project file/targets perspective only. I'll let others review the c# changes more carefully.

@Tratcher
Copy link
Member Author

Tratcher commented Jan 14, 2019

Hmm, what if I split CreateServer like I did for CreateWebHostBuilder? E.g. I add a new IHost CreateHost(IHostBuilder) that's called for the generic host code path and you keep TestServer CreateServer(IWebHostBuilder) for the web host code path.

@Tratcher
Copy link
Member Author

Updated. CreateHost got everything working.

@javiercn
Copy link
Member

Looks great!

@Tratcher Tratcher merged commit 6a44aca into master Jan 15, 2019
@Tratcher Tratcher deleted the tratcher/factory branch January 15, 2019 16:09
@BlacKCaT27
Copy link

BlacKCaT27 commented Aug 12, 2019

Question: are there plans to update the documentation for this here (https://docs.microsoft.com/en-us/aspnet/core/test/integration-tests?view=aspnetcore-3.0)? Or is the change supposed to be backwards compatible such that there shouldn't be any changes to the docs?

I'm on the latest preview build of .net core 3.0 and while converting our app from 2.2 to 3.0, all of our component tests which rely on WebApplicationFactory are now failing. It appears they're not honoring the mock services we try to inject into the TestServer before creating the client.

Setup:

        public void Init()
        {
            _factory = new WebApplicationFactory<Startup>();
        
        }

Usage in failed test:

            var mockCacheService = new Mock<ICacheService>();
            mockScheduleClient
                .Setup()
                .ReturnsAsync(page);
            using var client = _factory.WithWebHostBuilder(builder =>
                 {
                     builder.ConfigureTestServices(services =>
                     {
                         services.AddScoped(serviceProvider => mockScheduleClient.Object);
                         services.AddSingleton(mockCacheService.Object);
                     });
                 })
                .CreateClient();

Results in:

    System.AggregateException : Some services are not able to be constructed (Error while validating the service descriptor 'ServiceType: #####.ICacheService Lifetime: Scoped ImplementationType: #####.RedisCacheService': Unable to resolve service for type '#####.IJsonConverter' while attempting to activate '#####.RedisCacheService'.)
      ----> System.InvalidOperationException : Error while validating the service descriptor 'ServiceType: #####.ICacheService Lifetime: Scoped ImplementationType: #####.RedisCacheService': Unable to resolve service for type '#####.IJsonConverter' while attempting to activate '#####.RedisCacheService'.
      ----> System.InvalidOperationException : Unable to resolve service for type '#####.IJsonConverter' while attempting to activate '#####.RedisCacheService'.
  Stack Trace: 
    at ServiceProvider.ctor(IEnumerable`1 serviceDescriptors, ServiceProviderOptions options)
    at ServiceCollectionContainerBuilderExtensions.BuildServiceProvider(IServiceCollection services, ServiceProviderOptions options)
    at DefaultServiceProviderFactory.CreateServiceProvider(IServiceCollection containerBuilder)
    at ServiceFactoryAdapter`1.CreateServiceProvider(Object containerBuilder)
    at HostBuilder.CreateServiceProvider()
    at HostBuilder.Build()
    at WebApplicationFactory`1.CreateHost(IHostBuilder builder)
    at DelegatedWebApplicationFactory.CreateHost(IHostBuilder builder)
    at WebApplicationFactory`1.EnsureServer()
    at WebApplicationFactory`1.CreateDefaultClient(DelegatingHandler[] handlers)
    at WebApplicationFactory`1.CreateDefaultClient(Uri baseAddress, DelegatingHandler[] handlers)
    at WebApplicationFactory`1.CreateClient(WebApplicationFactoryClientOptions options)
    at WebApplicationFactory`1.CreateClient()

(##### replaces company-specific non-relevant namespace names).

Please let me know if I should open a new issue but this seems directly related to the refactoring done on this ticket.

@javiercn
Copy link
Member

@BlacKCaT27 Hi,

thanks for contacting us. Could you file a new issue with your problem so that we can track this separately?

We most likely will have to update the documentation for this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants