-
-
Notifications
You must be signed in to change notification settings - Fork 393
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
Named Clients + Configuration Overhaul #770
Comments
UPDATE: the changes described here were released in prerelease 5 but are superceded by those in the next comment, to be released in pre6. #769 exposed a problem with removing factories: If your project targets .NET 6 or higher, you'll get a
For all other target platforms, you'll get an
I want the above method to be as easy and safe to use as possible, which is why I opted against some generic form of |
Per the previous comment, #769 was addressed in prerelease 5 via platform-sniffing and defaulting to So there will be a prerelease 6 with the following updates:
The original description of this issue has been updated to reflect the most recent changes. |
GetOrAdd should be used to add clients on demand
Update: |
Update: |
The era of .NET 8 has come, and there are not many systems/software using the old version of .NET anymore. I think SocketsHttpHandler should still be added as an additional option for those using the latest version of .NET |
@ngoquoctoandev Agreed, that's why |
@tmenier - I'm using Flurl library in more than 30+ microservices and the way I had implemented was having a thin rest service which abstracts some cross cutting concerns for all of them. Within this rest service I have been using the IFlurlClientFactory to either get a new instance or a cached instance of HttpClient for the given url. OldCode
As per the new implementation I understand the recommended approach is to use the IFlurlClient from the DI container. At this stage I'm not in a position to make this change on all of them since they are all in production now and it would require lot of effort to make this change. I was trying to see a way to upgrade the library without the recommended DI method using the FlurlHttp implementation. My plan was to use the FlurlClientBuilder within my rest service as follows. New Code
In the new implementation I'm using FlurlHttp to get a client for a given url. However when I call the FlurlHttp the second time with the same url, I'm getting the following error. Please let me know if there is a way to get it working or if we can have any changes on the FlurlCache to avoid throwing the error and ensure only one HttpClient is returned for a given url. |
@satishviswanathan I think you have 2 options to get this working:
|
Small update. As (previously) described above,
A sub-thread here made me realize a few things:
So, the first overload above will be dropped, and all but the first arg of the second one will be optional. |
Is there a reason why |
[This should be the last major enhancement for 4.0. 🎉 Feedback is strongly encouraged. Description may go though a few iterations, so anyone interested in these changes is also encouraged to subscribe to this issue via the link to the right.]
Motivation
Flurl has long supported a "clientless" usage pattern, where developers can literally type a URL string and simply "call" it, without ever worrying about creating or managing client instances. To be clear, Flurl will continue to support this model forever, but as the .NET world (especially ASP.NET Core) has shifted more and more a DI-centric paradigms, the "explicit" client pattern has gained more traction, and there have been many requests to make Flurl more DI-friendly and generally work a little more like .NET's IHttpClientFactory.
Meet the New Interfaces
IFlurClientCache
A container for named
IFlurlClient
s. Recommended DI usage is to bind as a singleton toFlurlClientCache
(the default implementation) and inject into service classes, where it can be used in much the same way as IHttpClientFactory's named clients pattern.Methods:
(see update)IFlurlClientBuilder Add(string name, string baseUrl = null)
- Returns a builder to fluently configure the new client.IFlurlClientCache Add(string name, string baseUrl = null, Action<IFlurlClientBuilder> configure = null)
- Adds a newIFlurlClient
to the cache, with optional base URL and config action. Throws if named client already exists. Ideal for use during DI registration.IFlurlClient GetOrAdd(string name, string url = null, Action<IFlurlClientBuilder> configure = null)
- Gets a named client, creating and (optionally) configuring one if it doesn't exist. Ideal for use inside service classes, when lazy initialization is desired.IFlurlClient Get(string name)
- Gets a named client. Throws if it doesn't exist.IFlurClientCache WithDefaults(Action<IFlurlClientBuilder> configure)
- Executes for each new client added to the cache, before any client-specific configuration.void Remove(string name)
void Clear()
IFlurlClientBuilder
A builder for fluently configuring
IFlurlClient
s.Methods:
IFlurlClientBuilder ConfigureHttpClient(Action<HttpClient> configure)
IFlurlClientBuilder ConfigureInnerHandler(Action<HttpClientHandler> configure)
IFlurlClientBuilder UseSocketsHttpHandler(Action<SocketsHttpHandler> configure)
- Alternative to above. Available only on supported platforms. See Request for the use of SocketsHttpHandler #769.IFlurlClientBuilder AddMiddleware(Func<DelegatingHandler> create)
IFlurlClient Build()
- Called byIFlurlClientCache
exactly once per cached client; you will not likely ever need to call this directly.Settings
andHeaders
properties are also defined (the default implementation applies them directly to the client being built), and all related fluent extension methods available onIFlurlClient
(WithSettings
,WithHeaders
, etc.) are also available on the builder.An Overhauled
FlurlHttp
While most responsibilities for "global" configuration and caching are moving to
IFlurlClientCache
, which can be more easily managed by a DI container, the clientless model still needs to reference some implicit global/static context in order to function. This is nowFlurlHttp
's sole responsibility.Methods:
IFlurlClientBuilder ConfigureClientForUrl(string url)
- Similar toIFlurlClientFactory.Add
, but first builds a client name based on the URL.IFlurlClient GetClientForRequest(IFlurlRequest req)
- Mainly for internal use when a client must be selected for sending the given request.void UseClientCachingStrategy(Func<IFlurlRequest, string> buildClientName)
- Allows overriding the default client-per-host caching strategy. Perhaps you want a different client depending on whether an Authentication header is present, for example.void UseClientPerHostStrategy()
- In case you need to revert back to the default strategy (probably rare).string BuildClientNameByHost(IFlurlRequest req)
- The default caching strategy. Potentially useful as a starting point when customizing withUseClientCachingStrategy
.Properties:
IFlurlClientCache Clients { get; }
- A default client container mainly in support of clientless usage, but can also be used explicitly as an alternative to a DI-managed singleton.Breaking Changes to 3.x
[Concept-focused and not necessarily comprehensive. A more detailed list will be provided in the release notes.]
HttpClient
andHttpMessageHandler
(viaConfigureHttCLient
andConfigureInnerHandler
) is a safer approach and should cover virtually all use cases that made those necessary. Caching strategies are purely a clientless concern now and are covered byFlurlHttp
methods described above.IFlurlClientCache.WithDefaults
to specify settings that should apply too all clients by default.The text was updated successfully, but these errors were encountered: