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?
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.
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.