Skip to content

Add support to use externally provided HttpClient/HttpClientHandler #2400

Closed
@mconnew

Description

API's involved

There are 2 existing API mechanisms which could be used to achieve this.

BindingParameterCollection

A developer could create a class which implements IEndpointBehavior. In the AddBindingParameters method, they would add the relevant instance to the BindingParameterCollection. This would look like this:

    public class UseMyHttpClientEndpointBehavior : IEndpointBehavior
    {
        public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
        {
            HttpClientHandler httpClientHandler = new HttpClientHandler();
            // Set any properties on httpClientHandler
            bindingParameters.Add(new HttpClient(httpClientHandler));
        }
        public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) { }
        public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) { }
        public void Validate(ServiceEndpoint endpoint) { }
    }

This is a naïve implementation, e.g. HttpClient needs to have timeouts disabled to prevent contention on the global TimerManager, but it shows the general pattern.

MessageProperties

A developer could add an outgoing message property for the relevant instance to the OutgoingMessageProperties of an OperationContext. This could be done either with a class which implements IClientMessageInspector or with the use of OperationContextScope. The latter would look like this:

    HttpClientHandler httpClientHandler = new HttpClientHandler();
    // Set any properties on httpClientHandler
    HttpClient httpClient = new HttpClient();
    using(new OperationContextScope((IContextChannel)myClient))
    {
        OperationContext.Current.OutgoingMessageProperties.Add("System.Net.Http.HttpClient", httpClient);
        myClient.DoWork();
    }

Which class(es) to support

We have multiple options about which class(es) we could potentially support being added to a BindingParameterCollection or OutgoingMessageProperties, each having their own limitations. We would be unable to modify any parameters on any passed in objects for 2 reasons. 1) Any property we might set could potentially be something which is intended to be overridden. 2) There are use cases where the passed in object might have already been used so is now immutable.

System.Net.Http.HttpClient

WCF sets HttpClient.Timeout to infinite to prevent a timer being registered for each request. We have logic to coalesce CancellationToken timers to prevent high contention on the global timer queue. Without setting this value, HttpClient will cause a lot of contention.

System.Net.Http.HttpMessageInvoker

This is the base class to HttpClient. It lacks a lot of the helper api's that HttpClient provides such as the verb specific request api's, e.g. GetAsync and PostAsync. WCF only needs to use SendAsync so this shouldn't be an issue. Although we don't currently do this, WCF could make use of HttpClient.DefaultRequestHeaders for the headers which will always be the same for all requests from the same HttpChannelFactory. If we decide to support the use of a single instance of HttpClient with multiple ChannelFactory instances, then we can't use DefaultRequestHeaders.

System.Net.Http.HttpClientHandler

There are many properties on this class which WCF sets. One of the more important ones is Credentials. A developer would need to set the credentials on HttpClientHandler themselves. We would still be able to set any properties on the HttpClient instance we would create to wrap the HttpClientHandler. Supporting allowing this class to be provided would limit developers to using client implementations which ship with the framework.

System.Net.Http.HttpMessageHandler

This is the base class for HttpClientHandler and is the type that the constructor for HttpClient accepts. This has none of the properties that HttpClientHandler exposes, but as we can't modify any properties as explained earlier, this does not present any additional problems. This would enable developers to provide any implementation of Http which works with HttpClient.

System.Net.Http.DelegatingHandler

This is a special class which allows to provide an existing HttpMessageHandler to be wrapped and potentially provide custom behavior. There is a property InnerHandler which would allow WCF to set the HttpClientHandler that we create on the DelegatingHandler. Presuming the constraint of only being able to give WCF a delegating handler which has not been used yet, we would be able to provide an unused HttpClientHandler to the delegating handler which would be able to modify any properties before first usage. This would allow WCF to set credentials etc on an HttpClientHandler while also allowing a developer to modify everything as much as they wish.

Decisions to be made

  • Which of the extensibility methods do we want to support?
  • Which class types do we want to support being provided?
  • What constraints are acceptable? E.g. can instances be shared with multiple ChannelFactory's?

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions