Wcf: ChannelFactory Channels leaving connections open.

Created on 7 Aug 2017  路  2Comments  路  Source: dotnet/wcf

While converting an ASP.NET Framework project to ASP.NET Core I believe I may have found an issue. It could be similar to #1504. To test, I created two console apps with the following code.

    public void CallIt(int x)
    {
        BasicHttpBinding myBinding = new BasicHttpBinding();
        EndpointAddress myEndpoint = new EndpointAddress("webServiceURL");
        using (ChannelFactory<IService1> myChannelFactory = new ChannelFactory<IService1>(myBinding, myEndpoint))
        {
            IService1 instance = myChannelFactory.CreateChannel();
            myChannelFactory.Closed += ChannelFactory_Closed;
            ((IClientChannel)instance).Closed += Channel_Closed;
            Console.WriteLine(instance.GetData(x));
            ((IClientChannel)instance).Close();
        }
    }

    private void ChannelFactory_Closed(object sender, EventArgs e)
    {
        Console.WriteLine("Factory closed.");
    }

    private void Channel_Closed(object sender, EventArgs e)
    {
        Console.WriteLine("Channel closed.");
    }

One console app uses ASP.NET Framework and the other uses ASP.NET Core.
The code is called 5 times in a loop. The output of the ASP.NET Framework is:

You entered: 0
Channel closed.
Factory closed.
TCP [::1]:51681 Studio:63566 ESTABLISHED 6776
You entered: 1
Channel closed.
Factory closed.
TCP [::1]:51681 Studio:63566 ESTABLISHED 6776
You entered: 2
Channel closed.
Factory closed.
TCP [::1]:51681 Studio:63566 ESTABLISHED 6776
You entered: 3
Channel closed.
Factory closed.
TCP [::1]:51681 Studio:63566 ESTABLISHED 6776
You entered: 4
Channel closed.
Factory closed.
TCP [::1]:51681 Studio:63566 ESTABLISHED 6776

The output of the ASP.NET Core is:

You entered: 0
Channel closed.
Factory closed.
TCP [::1]:51674 Studio:63566 ESTABLISHED 7328
You entered: 1
Channel closed.
Factory closed.
TCP [::1]:51674 Studio:63566 ESTABLISHED 7328
TCP [::1]:51676 Studio:63566 ESTABLISHED 7328
You entered: 2
Channel closed.
Factory closed.
TCP [::1]:51674 Studio:63566 ESTABLISHED 7328
TCP [::1]:51676 Studio:63566 ESTABLISHED 7328
TCP [::1]:51677 Studio:63566 ESTABLISHED 7328
You entered: 3
Channel closed.
Factory closed.
TCP [::1]:51674 Studio:63566 ESTABLISHED 7328
TCP [::1]:51676 Studio:63566 ESTABLISHED 7328
TCP [::1]:51677 Studio:63566 ESTABLISHED 7328
TCP [::1]:51678 Studio:63566 ESTABLISHED 7328
You entered: 4
Channel closed.
Factory closed.
TCP [::1]:51674 Studio:63566 ESTABLISHED 7328
TCP [::1]:51676 Studio:63566 ESTABLISHED 7328
TCP [::1]:51677 Studio:63566 ESTABLISHED 7328
TCP [::1]:51678 Studio:63566 ESTABLISHED 7328
TCP [::1]:51679 Studio:63566 ESTABLISHED 7328

As you can see the ASP.NET Core version seems to keep the connections open.
Is this an issue or am doing something silly?

Most helpful comment

The difference is because on the full framework we use HttpWebRequest and on .Net Core, we use HttpClient. HttpWebRequest uses ServicePointManager to manage connection pooling. WCF creates a connection group name based on the endpoint and the credentials being used and sets this name on the HttpWebRequest. ServicePointManager handles the connection pooling at the app domain level. This means when a second ChannelFactory is created and makes a request, if the endpoint and credentials are identical, it will use the same connection pool as the previous instance. On .Net Core, HttpClient pools connections for each instance of HttpClient, which is created and owned by the ChannelFactory. When you create a second ChannelFactory, it gets a new connection pool. Whether you are running on the full framework or on .Net Core, you shouldn't be creating a new ChannelFactory for each request. A ChannelFactory can be quite large with all the contract description objects it creates.

All 2 comments

The difference is because on the full framework we use HttpWebRequest and on .Net Core, we use HttpClient. HttpWebRequest uses ServicePointManager to manage connection pooling. WCF creates a connection group name based on the endpoint and the credentials being used and sets this name on the HttpWebRequest. ServicePointManager handles the connection pooling at the app domain level. This means when a second ChannelFactory is created and makes a request, if the endpoint and credentials are identical, it will use the same connection pool as the previous instance. On .Net Core, HttpClient pools connections for each instance of HttpClient, which is created and owned by the ChannelFactory. When you create a second ChannelFactory, it gets a new connection pool. Whether you are running on the full framework or on .Net Core, you shouldn't be creating a new ChannelFactory for each request. A ChannelFactory can be quite large with all the contract description objects it creates.

Many thanks for the explanation @mconnew. I've successfully amended my code.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

weitzhandler picture weitzhandler  路  6Comments

Petermarcu picture Petermarcu  路  4Comments

hongdai picture hongdai  路  5Comments

apdirexyon picture apdirexyon  路  5Comments

martinspasovski picture martinspasovski  路  3Comments