mirror of
https://github.com/wiremock/WireMock.Net.git
synced 2026-01-11 22:30:41 +01:00
HttpClient extension methods causes ambiguous invocations in .NET 7 #532
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @siewers on GitHub (Jul 19, 2023).
Originally assigned to: @StefH on GitHub.
Describe the bug
When adding WireMock to a .NET 7 project, it breaks the usage of certain HttpClient extension methods by causing ambiguous invocations.
Expected behavior:
There should be no ambiguous invocations/conflicts when using WireMock.
Test to reproduce
PostAsJsonAsync.Other related info
There might be other extension methods that cause the same issue.

Removing the cancellation token from the
PostAsJsonAsynccall will resolve the extension method located in the seemingly deprecatedSystem.Net.Http.Formattingassembly, which seems to originate from theMicrosoft.AspNet.WebApi.Clientpackage according to Visual Studio.This resolves to
System.Net.Http.HttpClientExtensions(System.Net.Http.Formatting.dll):This resolves to
System.Net.Http.Json.HttpClientJsonExtensions(System.Net.Http.Json.dll):Potential workaround
To resolve the ambiguity, it is possible to invoke the extension method as a static method instead, but this is not ideal and will require you to remember this issue in order to not end up in this situation again.
Another solution is to give the
System.Net.Http.Formattingassembly a different alias (see this StackOverflow answer)This is probably the nicest way to solve it, but it's still something that's less than ideal.
@StefH commented on GitHub (Jul 20, 2023):
@siewers
I applied your last suggestion.
Can you review PR https://github.com/WireMock-Net/WireMock.Net/pull/977 ?
@StefH commented on GitHub (Jul 21, 2023):
Can you try preview version 1.5.32-ci-17648 ?
https://github.com/WireMock-Net/WireMock.Net/wiki/MyGet-preview-versions
@siewers commented on GitHub (Jul 21, 2023):
Unfortunately, that won't work.
The reason is that the package is transitively available to all consumers of WireMock.Net. What this change does is only aliasing it within the WireMock.Net project, but not for consumers.
Since you aren't referencing the package directly in WireMock.Net, it's not possible to hide that one directly from consumers, but perhaps there is a trick to mark it with
PrivateAssets="compile;build;analyzers"somehow, so it won't be accessible to consumers.It might even be possible to hide the
Microsoft.AspNet.WebApi.Clientpackage reference like so:I believe (but I'm not sure) that hiding a package reference like this also hides all its transitive dependencies, but I would need to test it.
In general, I think WireMock exposes too many of its internal dependencies, resulting in IntelliSense becoming extremely bloated with all kinds of references not included in the consuming project itself.
I believe it's good practice to hide the library dependencies to consumers to not unnecessarily bloat the IntelliSense and accidentally start relying on a dependency not directly referenced (e.g. the GraphQL package that exposes a lot of extension methods as well).
If you ever decide to remove or upgrade such a dependency, you might inadvertently break consumers of WireMock.Net, because they in turn relied on some random extension method from a package you included, which is now removed or has changed.
I know there are probably a lot of opinions in this area, but it's risky exposing dependencies not intended to be used by consumers.
On the other hand, there's also the risk of package version mismatch, if the consumer directly references a package that WireMock.Net depends on, but hides. In this case, one way to solve it could be to add a version range in the package reference, allowing consumers to depend on e.g.
Newtonsoft.Jsonversion 12 through 18 or something like that. If the consumer upgrades the package to version 19, the project won't build because WireMock.Net isn't tested or guaranteed compatible with that version.It's a lot of complexity for such a seemingly tiny problem, but it's definitely worth considering for future maintainability.
Oh, one more thing, if you decide to hide all internal dependencies, it's most likely a major breaking change, as nobody knows what packages are being used transitively by consumers.
@StefH commented on GitHub (Jul 21, 2023):
Thank you for your detailed explanation and suggestions.
I think that marking the dependencies as PrivateAssets is the best solution in the long term which indeed could mean a breaking change.
(https://learn.microsoft.com/en-us/answers/questions/702182/how-to-hide-dependent-nuget-dlls-from-consuming-pa)
For now I've deleted the PR.
Another approach which I was trying to build for this specific issue is removing the dependency on Microsoft.AspNet.WebApi.Client (which I use for creating a httpclient by using a httpclientfactory) for .NET 6 and higher. I did build a work-around using code like this:
This worked, however the current code uses:
And the handlers are not supported in that same way....
I need to think on that some more...
@siewers commented on GitHub (Jul 22, 2023):
You may want to have a look at the documentation here https://learn.microsoft.com/en-us/dotnet/core/extensions/httpclient-factory#configure-the-httpmessagehandler
The pattern is to inject a typed, configured, client into
Xand then use that one instead of the factory directly. You can add handlers when you configure an HttpClient usingAddHttpClient<TService, TImplementation>.When you then resolve
Xyou would have to do so as either transitive or scoped. This approach is not suited for singletons.I don’t know how important that is, but your instance property could technically be changed into something like a factory instead, where you then resolve a new instance each time.
I haven’t checked for .NET 6 and above, but at some point there was also a static factory method on the ‘HttpClientFactory` class, I’m just not sure if that exists anymore.
@siewers commented on GitHub (Jul 25, 2023):
What I was thinking was something along these lines could work as well:
One concern I have with this approach is the fact that the HttpClient never gets disposed and the ServiceProvider lives on and might leak somehow. I'm not familiar with how this class would be used, so I'm not sure this is the best approach.
It is possible to make the class disposable and then simply dispose the service collection at some point, but again, I don't know the exact use-case for this.
@StefH commented on GitHub (Jul 25, 2023):
I was also checking this
https://github.com/myarichuk/Simple.HttpClientFactory
@siewers commented on GitHub (Jul 25, 2023):
Well, it's an option, although I'm having a hard time finding it justifiable today.
Sure, you save a few lines of internal implementation code, but the project seems stale and haven't had an update for three years and only 8 stars. The rationale behind the project seems to be a bit of a stretch IMHO :)
I'd suggest sticking with the framework and not pull in other third-party packages to solve this problem :)
@siewers commented on GitHub (Jul 25, 2023):
I found this implementation of a framework "agnostic" HttpClientFactory that might be useful.
I've never worked with HTTP handler pipelines like this, so I'm not sure exactly how it should work, but from the looks of it, it seems pretty straight-forward.
@siewers commented on GitHub (Aug 23, 2023):
I had a look at the implementation in the
HttpClientFactoryand I believe this should be able to do the same without the need for the package dependency:@StefH commented on GitHub (Aug 25, 2023):
https://github.com/WireMock-Net/WireMock.Net/pull/996
@StefH commented on GitHub (Aug 26, 2023):
Can you try preview: 1.5.32-ci-17765
https://github.com/WireMock-Net/WireMock.Net/wiki/MyGet-preview-versions
@siewers commented on GitHub (Aug 28, 2023):
I can't find the build on MyGet. The only prerelease versions available are 1.5.34 and 1.5.35.
@StefH commented on GitHub (Aug 28, 2023):
Did you select the preview select box in visual studio?
@siewers commented on GitHub (Aug 28, 2023):
Yes, I am using the preview feed. The preview versions I see are not 1.5.32.
@StefH commented on GitHub (Aug 29, 2023):
Version 1.5.32-ci-17775 should be visible on MyGet now.
@siewers commented on GitHub (Aug 29, 2023):
Yes, the preview version works without the workaround 👍