Skip to content

Conversation

@Niksson
Copy link
Contributor

@Niksson Niksson commented Oct 21, 2024

Fixes #2178

This fixes the issue with DI service resolution for Consul provider mentioned in #2178

Proposed Changes

  • ConsulProviderFactory - resolve the IConsulServiceBuilder from the HttpContext.RequestServices
  • Provide a unit test that detects a scope validation error for ConsulProviderFactory

Some notes:

  1. I'm not sure if the test that detects a scope validation error is strictly required. By enabling scope validation in service provider all code that tries to resolve scoped services from singletons should make the tests red.
  2. This PR's scope is Consul provider only. In acceptance tests I made the scope validation option opt-in, to not break other tests. It may be good to force it when the other providers are also fixed
  3. ConsulProviderFactory.Get creates both Consul and PollConsul providers, so the fix should cover both of them

If there is anything that can be changed to improve quality - do not hesitate to propose changes

Docs

@raman-m raman-m requested review from ggnaegi and raman-m October 21, 2024 15:20
@raman-m raman-m added Service Discovery Ocelot feature: Service Discovery hotfix Gitflow: Hotfix issue, PR related to hotfix branch Consul Service discovery by Consul Jan'24 January 2024 release Oct'24 October 2024 release and removed Jan'24 January 2024 release labels Oct 21, 2024
@raman-m raman-m added this to the October'24 milestone Oct 21, 2024
Copy link
Member

@raman-m raman-m left a comment

Choose a reason for hiding this comment

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

Thank you for the high-quality PR. I suggest writing acceptance tests, if applicable.

contextAccessor.HttpContext.Items[nameof(ConsulRegistryConfiguration)] = configuration; // initialize data
var serviceBuilder = provider.GetService<IConsulServiceBuilder>(); // consume data in default/custom builder
context.Items[nameof(ConsulRegistryConfiguration)] = configuration; // initialize data
var serviceBuilder = context.RequestServices.GetService<IConsulServiceBuilder>(); // consume data in default/custom builder
Copy link
Member

Choose a reason for hiding this comment

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

Does reading context services implicitly create a scope? I'll demonstrate the difference in the following code:

- var scope = provider.CreateScope();
- var serviceBuilder = scope.ServiceProvider.GetService<IConsulServiceBuilder>(); // consume data in default/custom builder
+ var context = contextAccessor.HttpContext;
+ var serviceBuilder = context.RequestServices.GetService<IConsulServiceBuilder>(); // consume data in default/custom builder

Thus, are the two solutions equivalent?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

AFAIK ASP.NET creates a DI scope for HttpContext of each HTTP request (see this link for more info).
Technically, the solutions are equivalent, but I thought that since we already access HttpContext via IHttpContextAccessor, it would be logical to access the scope of the HTTP request instead of creating a new one.

Copy link
Member

Choose a reason for hiding this comment

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

see this link for more info

Yep, good to know!
Bu gaga, Tom should read these best DI practices in 2017-2020 when designing everything as singletons and delegates → Design services for dependency injection


🆗 Not an issue. Your solution should function properly.

@raman-m raman-m changed the title Fix DI service resolution for IConsulServiceBuilder (#2178) #2178 DI service resolution from scoped HttpContext request services for the IConsulServiceBuilder service Oct 21, 2024
@raman-m
Copy link
Member

raman-m commented Oct 21, 2024

Trigger pipeline 🤣

Please ask me to initiate new builds. Are you not able to click the buttons in the Checks? 🤔

@Niksson
Copy link
Contributor Author

Niksson commented Oct 21, 2024

Please ask me to initiate new builds.

Okay, will do. There was a test that was flaky, so I just triggered another run by the only way I know ;)
Unfortunately, there were no other buttons that allow me to retry checks.

@Niksson
Copy link
Contributor Author

Niksson commented Oct 21, 2024

IMO new acceptance tests are not required here:

  • The existing ones and the future ones should detect invalid service resolution if the scope validation is turned on in helpers. I didn't do it for every acceptance test since the scope of this PR is limited.
  • More technical reason: I don't know of a way to have a non-scoped (aka root) service provider in HttpContext while using TestHost 😅

@raman-m
Copy link
Member

raman-m commented Oct 21, 2024

  1. This PR's scope is Consul provider only. In acceptance tests I made the scope validation option opt-in, to not break other tests. It may be good to force it when the other providers are also fixed

Fair enough, but how many tests would break if we bypass the parameter and enforce scope validation for all tests? It would be logically preferable to resolve all issues with scoped services in one PR, but that seems to be beyond the current PR's scope.

Tomorrow, I plan to conduct research to determine how to comprehensively address all issues with scoped services...

@raman-m
Copy link
Member

raman-m commented Oct 22, 2024

I've identified numerous instances where scope validation is disabled in unit tests: specifically, a search for ".BuildServiceProvider(" reveals about 25 files with manual construction of service collections without validation. Unfortunately, we cannot address these in the current PR. 😢 But the final number of items ~50+ 🤯

@raman-m
Copy link
Member

raman-m commented Oct 22, 2024

Regrettably, the search for "WebHostBuilder" revealed a significant issue with disabled scopes validation in tests and the core library 🤯 This wasn't an issue when services were primarily designed as singletons by Tom and contributors. However, as we began to introduce more scoped services, it became apparent that our testing projects were not equipped to handle them. The subsequent task will be to enable scope validation across all areas: unit tests, acceptance tests, and the core library. At this time, it is not feasible to tackle this extensive problem within this PR.

During refactoring, it is sensible to:

  • Relocate the creation of the IWebHostBuilder objects in tests to the Ocelot.Testing project to enable the reuse of the helper across all testing projects. It is crucial to focus on C# statements containing new WebHostBuilder() expressions, necessitating the implementation of a wrapper.

Copy link
Member

@raman-m raman-m left a comment

Choose a reason for hiding this comment

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

Development Complete❕

@raman-m raman-m merged commit 1cf5597 into ThreeMammals:develop Oct 23, 2024
1 check passed
@raman-m
Copy link
Member

raman-m commented Oct 23, 2024

@Niksson This PR has been merged.
Thank you for your contribution! 👍

@Niksson Niksson deleted the fix/consul-service-builder-resolve-issue branch October 23, 2024 10:39
raman-m added a commit that referenced this pull request Oct 25, 2024
* OcelotBuilderExtensionsTests for Eureka SD

* BuildServiceProvider(true)
#2179 (comment)

* Add TestHostBuilder with enabled scopes validation by default across all testing projects
#2179 (comment)

* Update Sample projects with force scopes validation.
Add Ocelot.Samples.Web project.
Add OcelotHostBuilder and DownstreamHostBuilder helpers.
Add Ocelot.Samples.Web project reference to all samples projects.
TargetFramework is `net8.0` only.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Consul Service discovery by Consul hotfix Gitflow: Hotfix issue, PR related to hotfix branch Oct'24 October 2024 release Service Discovery Ocelot feature: Service Discovery

Projects

None yet

Development

Successfully merging this pull request may close these issues.

In v23.3.4 ConsulProviderFactory can't resolve IConsulServiceBuilder via IServiceProvider

2 participants