From ecb2e8e125c099b4b3a8868629505f92dd7b3162 Mon Sep 17 00:00:00 2001 From: Abdelwahab Afifi Date: Wed, 8 Nov 2023 17:00:54 +0200 Subject: [PATCH] Update WCF sample Instance Pooling code to conditionally support .NET framework / Core --- .../Instancing/Pooling/CS/client/App.config | 2 +- .../Instancing/Pooling/CS/client/Client.cs | 17 ++- .../Pooling/CS/client/Client.csproj | 110 +++--------------- .../CS/client/Properties/AssemblyInfo.cs | 35 ------ .../Pooling/CS/extensions/Extensions.csproj | 52 +-------- .../extensions/ObjectPoolBehaviorAttribute.cs | 52 ++++----- .../extensions/ObjectPoolInstanceProvider.cs | 101 ++++++++-------- .../CS/extensions/Properties/AssemblyInfo.cs | 1 - .../Pooling/CS/extensions/ResourceHelper.cs | 7 +- .../Instancing/Pooling/CS/service/App.config | 2 +- .../Instancing/Pooling/CS/service/Service.cs | 1 - .../Pooling/CS/service/Service.csproj | 52 +-------- 12 files changed, 118 insertions(+), 314 deletions(-) delete mode 100644 framework/wcf/Extensibility/Instancing/Pooling/CS/client/Properties/AssemblyInfo.cs diff --git a/framework/wcf/Extensibility/Instancing/Pooling/CS/client/App.config b/framework/wcf/Extensibility/Instancing/Pooling/CS/client/App.config index b9504df4a75..79cb62ab59b 100644 --- a/framework/wcf/Extensibility/Instancing/Pooling/CS/client/App.config +++ b/framework/wcf/Extensibility/Instancing/Pooling/CS/client/App.config @@ -7,4 +7,4 @@ - + diff --git a/framework/wcf/Extensibility/Instancing/Pooling/CS/client/Client.cs b/framework/wcf/Extensibility/Instancing/Pooling/CS/client/Client.cs index c4ed344b2e7..34d86da8b25 100644 --- a/framework/wcf/Extensibility/Instancing/Pooling/CS/client/Client.cs +++ b/framework/wcf/Extensibility/Instancing/Pooling/CS/client/Client.cs @@ -1,7 +1,6 @@ // Copyright (c) Microsoft Corporation. All Rights Reserved. using System; -using System.ServiceModel.Channels; using System.ServiceModel; using System.Diagnostics; @@ -29,8 +28,14 @@ static void Main(string[] args) } static void CallWorkService() - { + { +#if NET6_0_OR_GREATER + NetTcpBinding binding = new NetTcpBinding(); + EndpointAddress endpointAddress = new EndpointAddress(new Uri("net.tcp://localhost:8000/")); + ChannelFactory channelFactory = new ChannelFactory(binding, endpointAddress); +#else ChannelFactory channelFactory = new ChannelFactory("WorkService"); +#endif IDoWork channel = channelFactory.CreateChannel(); @@ -53,8 +58,14 @@ static void CallWorkService() } static void CallObjectPooledWorkService() - { + { +#if NET6_0_OR_GREATER + NetTcpBinding binding = new NetTcpBinding(); + EndpointAddress endpointAddress = new EndpointAddress(new Uri("net.tcp://localhost:8001/")); + ChannelFactory channelFactory = new ChannelFactory(binding, endpointAddress); +#else ChannelFactory channelFactory = new ChannelFactory("ObjectPooledWorkService"); +#endif IDoWork channel = channelFactory.CreateChannel(); diff --git a/framework/wcf/Extensibility/Instancing/Pooling/CS/client/Client.csproj b/framework/wcf/Extensibility/Instancing/Pooling/CS/client/Client.csproj index bda015f414b..550df9ca805 100644 --- a/framework/wcf/Extensibility/Instancing/Pooling/CS/client/Client.csproj +++ b/framework/wcf/Extensibility/Instancing/Pooling/CS/client/Client.csproj @@ -1,98 +1,24 @@ - - + - Debug - AnyCPU - 8.0.50727 - 2.0 - {A14DAFDF-2D84-4DC3-A8CE-F81D36FC912F} + net462;net6.0 Exe - Properties - Microsoft.ServiceModel.Samples - Client - v4.0 - - - - - 2.0 - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - false - true - + Client + Pooling Sample + Microsoft Corporation + Windows Communication Foundation and Windows Workflow Foundation SDK + Copyright (c) Microsoft Corporation - - true - full - false - bin\ - DEBUG;TRACE - prompt - 4 - AllRules.ruleset - - - pdbonly - true - bin\ - TRACE - prompt - 4 - AllRules.ruleset - - - - - - + + + - - - - - - + + + - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 3.5 SP1 - true - - - False - Microsoft Visual Basic PowerPacks 10.0 - true - - - False - Windows Installer 3.1 - true - + + + + - - - \ No newline at end of file + diff --git a/framework/wcf/Extensibility/Instancing/Pooling/CS/client/Properties/AssemblyInfo.cs b/framework/wcf/Extensibility/Instancing/Pooling/CS/client/Properties/AssemblyInfo.cs deleted file mode 100644 index 3b1e9e97afe..00000000000 --- a/framework/wcf/Extensibility/Instancing/Pooling/CS/client/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System; -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("Client")] -[assembly: AssemblyDescription("Pooling Sample")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Microsoft")] -[assembly: AssemblyProduct("Client")] -[assembly: AssemblyCopyright("Copyright © Microsoft 2006")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] -[assembly: CLSCompliant(true)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("2cf2fc78-167d-4646-8da8-f01ec03a66d6")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/framework/wcf/Extensibility/Instancing/Pooling/CS/extensions/Extensions.csproj b/framework/wcf/Extensibility/Instancing/Pooling/CS/extensions/Extensions.csproj index a1b2921114d..849a3ae6dd7 100644 --- a/framework/wcf/Extensibility/Instancing/Pooling/CS/extensions/Extensions.csproj +++ b/framework/wcf/Extensibility/Instancing/Pooling/CS/extensions/Extensions.csproj @@ -1,37 +1,17 @@  - + + Debug AnyCPU 8.0.50727 - 2.0 {24F59702-9923-4D05-BD39-F4A6D9F0ED78} Library Properties Microsoft.ServiceModel.Samples InstancePoolingExtension - v4.0 - - - - - 2.0 + v4.6.2 publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - false - true - true @@ -76,29 +56,7 @@ Resources.Designer.cs - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 3.5 SP1 - true - - - False - Microsoft Visual Basic PowerPacks 10.0 - true - - - False - Windows Installer 3.1 - true - - - + - \ No newline at end of file + diff --git a/framework/wcf/Extensibility/Instancing/Pooling/CS/extensions/ObjectPoolBehaviorAttribute.cs b/framework/wcf/Extensibility/Instancing/Pooling/CS/extensions/ObjectPoolBehaviorAttribute.cs index 59199ff7f2d..2f47096349b 100644 --- a/framework/wcf/Extensibility/Instancing/Pooling/CS/extensions/ObjectPoolBehaviorAttribute.cs +++ b/framework/wcf/Extensibility/Instancing/Pooling/CS/extensions/ObjectPoolBehaviorAttribute.cs @@ -13,20 +13,20 @@ namespace Microsoft.ServiceModel.Samples // used to add pooling behavior to the service instance. public sealed class ObjectPoolingAttribute : Attribute, IServiceBehavior { - const int defaultMaxPoolSize = 32; - const int defaultMinPoolSize = 0; - int maxPoolSize = defaultMaxPoolSize; - int minPoolSize = defaultMinPoolSize; + private const int DefaultMaxPoolSize = 32; + private const int DefaultMinPoolSize = 0; + private int _maxPoolSize = DefaultMaxPoolSize; + private int _minPoolSize = DefaultMinPoolSize; // If the service does not already have a ServiceThrottlingBehavior, we will create // one and forward all IServiceBehavior calls to it. This is used to implement // MaxPoolSize. - ServiceThrottlingBehavior throttlingBehavior = null; + private ServiceThrottlingBehavior throttlingBehavior = null; // Gets or sets the maximum number of objects that can be created in the pool public int MaxPoolSize { - get { return maxPoolSize; } + get => _maxPoolSize; set { if (value < 0) @@ -34,14 +34,14 @@ public int MaxPoolSize throw new ArgumentException(ResourceHelper.GetString("ExNegativePoolSize")); } - this.maxPoolSize = value; + _maxPoolSize = value; } } // Gets or sets the minimum number of objects that can be created in the pool public int MinPoolSize { - get { return minPoolSize; } + get => _minPoolSize; set { if (value < 0) @@ -49,7 +49,7 @@ public int MinPoolSize throw new ArgumentException(ResourceHelper.GetString("ExNegativePoolSize")); } - this.minPoolSize = value; + _minPoolSize = value; } } @@ -58,9 +58,9 @@ public int MinPoolSize void IServiceBehavior.AddBindingParameters(ServiceDescription description, ServiceHostBase serviceHostBase, Collection endpoints, BindingParameterCollection parameters) { // Forward the call if we created a ServiceThrottlingBehavior. - if (this.throttlingBehavior != null) + if (throttlingBehavior != null) { - ((IServiceBehavior)this.throttlingBehavior).AddBindingParameters(description, serviceHostBase, endpoints, parameters); + ((IServiceBehavior)throttlingBehavior).AddBindingParameters(description, serviceHostBase, endpoints, parameters); } } @@ -68,15 +68,15 @@ void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription description, Serv { // Create an instance of the ObjectPoolInstanceProvider. ObjectPoolingInstanceProvider instanceProvider = new ObjectPoolingInstanceProvider(description.ServiceType, - minPoolSize); + _minPoolSize); // Forward the call if we created a ServiceThrottlingBehavior. - if (this.throttlingBehavior != null) + if (throttlingBehavior != null) { - ((IServiceBehavior)this.throttlingBehavior).ApplyDispatchBehavior(description, serviceHostBase); + ((IServiceBehavior)throttlingBehavior).ApplyDispatchBehavior(description, serviceHostBase); } - // In case there was already a ServiceThrottlingBehavior (this.throttlingBehavior==null), + // In case there was already a ServiceThrottlingBehavior (throttlingBehavior==null), // it should have initialized a single ServiceThrottle on all ChannelDispatchers. As // we loop through the ChannelDispatchers, we verify that and modify the ServiceThrottle // to guard MaxPoolSize. @@ -89,7 +89,7 @@ void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription description, Serv { // Make sure there is exactly one throttle used by all endpoints. // If there were others, we could not enforce MaxPoolSize. - if ((this.throttlingBehavior == null) && (this.maxPoolSize != Int32.MaxValue)) + if ((throttlingBehavior == null) && (_maxPoolSize != int.MaxValue)) { if (throttle == null) { @@ -115,15 +115,15 @@ void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription description, Serv // Set the MaxConcurrentInstances to limit the number of items that will // ever be requested from the pool. - if ((throttle != null) && (throttle.MaxConcurrentInstances > this.maxPoolSize)) + if ((throttle != null) && (throttle.MaxConcurrentInstances > _maxPoolSize)) { - throttle.MaxConcurrentInstances = this.maxPoolSize; + throttle.MaxConcurrentInstances = _maxPoolSize; } } void IServiceBehavior.Validate(ServiceDescription description, ServiceHostBase serviceHostBase) { - if (this.maxPoolSize < this.minPoolSize) + if (_maxPoolSize < _minPoolSize) { throw new InvalidOperationException(ResourceHelper.GetString("ExMinLargerThanMax")); } @@ -141,18 +141,18 @@ void IServiceBehavior.Validate(ServiceDescription description, ServiceHostBase s // initializes the ServiceThrottle property of the endpoints. If there is // no ServiceThrottlingBehavior, we will create one and run it ourselves. // If there is one, we validate that it comes before us. - int throttlingIndex = this.GetBehaviorIndex(description, typeof(ServiceThrottlingBehavior)); + int throttlingIndex = GetBehaviorIndex(description, typeof(ServiceThrottlingBehavior)); if (throttlingIndex == -1) { - this.throttlingBehavior = new ServiceThrottlingBehavior(); - this.throttlingBehavior.MaxConcurrentInstances = this.MaxPoolSize; + throttlingBehavior = new ServiceThrottlingBehavior(); + throttlingBehavior.MaxConcurrentInstances = MaxPoolSize; // Forward the call if we created a ServiceThrottlingBehavior. - ((IServiceBehavior)this.throttlingBehavior).Validate(description, serviceHostBase); + ((IServiceBehavior)throttlingBehavior).Validate(description, serviceHostBase); } else { - int poolingIndex = this.GetBehaviorIndex(description, typeof(ObjectPoolingAttribute)); + int poolingIndex = GetBehaviorIndex(description, typeof(ObjectPoolingAttribute)); if (poolingIndex < throttlingIndex) { throw new InvalidOperationException(ResourceHelper.GetString("ExThrottleBeforePool")); @@ -162,9 +162,9 @@ void IServiceBehavior.Validate(ServiceDescription description, ServiceHostBase s #endregion - int GetBehaviorIndex(ServiceDescription description, Type behaviorType) + private int GetBehaviorIndex(ServiceDescription description, Type behaviorType) { - for (int i=0; i pool; - + private readonly Stack _pool; + // Lock should acquired before accessing the pool stack - object poolLock = new object(); - + private readonly object _poolLock = new object(); + // Keeps track of the number of objects returned from the pool. - int activeObjectsCount; + private int _activeObjectsCount; // Timer object used to trigger the clean up process // after a given period of idle time. - Timer idleTimer; - + private readonly Timer _idleTimer; + #endregion public ObjectPoolingInstanceProvider(Type instanceType, int minPoolSize) - { - this.minPoolSize = minPoolSize; - this.instanceType = instanceType; + { + _minPoolSize = minPoolSize; + _instanceType = instanceType; - pool = new Stack(); - activeObjectsCount = 0; + _pool = new Stack(); + _activeObjectsCount = 0; // Initialize the timer and subscribe to the "Elapsed" event - idleTimer = new Timer(idleTimeout); - idleTimer.Elapsed += new System.Timers.ElapsedEventHandler(idleTimer_Elapsed); + _idleTimer = new Timer(IdleTimeout); + _idleTimer.Elapsed += new System.Timers.ElapsedEventHandler(idleTimer_Elapsed); // Initialize the minimum number of objects if possible Initialize(); @@ -60,94 +57,88 @@ public ObjectPoolingInstanceProvider(Type instanceType, int minPoolSize) #region IInstanceProvider Members - object IInstanceProvider.GetInstance(InstanceContext instanceContext) - { - return ((IInstanceProvider)this).GetInstance(instanceContext, null); - } + object IInstanceProvider.GetInstance(InstanceContext instanceContext) => ((IInstanceProvider)this).GetInstance(instanceContext, null); object IInstanceProvider.GetInstance(InstanceContext instanceContext, Message message) { object obj = null; - lock (poolLock) + lock (_poolLock) { - if (pool.Count > 0) + if (_pool.Count > 0) { - obj = pool.Pop(); + obj = _pool.Pop(); } else { obj = CreateNewPoolObject(); } - activeObjectsCount++; + _activeObjectsCount++; } WritePoolMessage(ResourceHelper.GetString("MsgNewObject")); - idleTimer.Stop(); + _idleTimer.Stop(); - return obj; + return obj; } void IInstanceProvider.ReleaseInstance(InstanceContext instanceContext, object instance) { - lock (poolLock) + lock (_poolLock) { - pool.Push(instance); - activeObjectsCount--; + _pool.Push(instance); + _activeObjectsCount--; WritePoolMessage(ResourceHelper.GetString("MsgObjectPooled")); // When the service goes completely idle (no requests are being processed), // the idle timer is started - if (activeObjectsCount == 0) - idleTimer.Start(); + if (_activeObjectsCount == 0) + _idleTimer.Start(); } } - + #endregion // Initialize the pool with minimum number of instances - void Initialize() + private void Initialize() { - for (int i = 0; i < minPoolSize; i++) + for (int i = 0; i < _minPoolSize; i++) { - pool.Push(CreateNewPoolObject()); + _pool.Push(CreateNewPoolObject()); } } // Handles the instantiation of the types created by this instance - private object CreateNewPoolObject() - { - return Activator.CreateInstance(instanceType); - } + private object CreateNewPoolObject() => Activator.CreateInstance(_instanceType); // Clean up procedure - void idleTimer_Elapsed(object sender, ElapsedEventArgs args) + private void idleTimer_Elapsed(object sender, ElapsedEventArgs args) { - idleTimer.Stop(); + _idleTimer.Stop(); - lock (poolLock) + lock (_poolLock) { - if (activeObjectsCount == 0) + if (_activeObjectsCount == 0) { - while (pool.Count > minPoolSize) + while (_pool.Count > _minPoolSize) { WritePoolMessage(ResourceHelper.GetString("MsgObjectRemoving")); - - object removedItem = pool.Pop(); - + + object removedItem = _pool.Pop(); + if (removedItem is IDisposable) { ((IDisposable)removedItem).Dispose(); } } - } + } } } // Writes a given message to the console in red color - void WritePoolMessage(string message) + private void WritePoolMessage(string message) { ConsoleColor currentForegroundColor = Console.ForegroundColor; Console.ForegroundColor = ConsoleColor.Red; diff --git a/framework/wcf/Extensibility/Instancing/Pooling/CS/extensions/Properties/AssemblyInfo.cs b/framework/wcf/Extensibility/Instancing/Pooling/CS/extensions/Properties/AssemblyInfo.cs index 09e6096fdc1..fe0516f2192 100644 --- a/framework/wcf/Extensibility/Instancing/Pooling/CS/extensions/Properties/AssemblyInfo.cs +++ b/framework/wcf/Extensibility/Instancing/Pooling/CS/extensions/Properties/AssemblyInfo.cs @@ -1,6 +1,5 @@ using System; using System.Reflection; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following diff --git a/framework/wcf/Extensibility/Instancing/Pooling/CS/extensions/ResourceHelper.cs b/framework/wcf/Extensibility/Instancing/Pooling/CS/extensions/ResourceHelper.cs index 706f8d6e6b1..5efe9d7d2bc 100644 --- a/framework/wcf/Extensibility/Instancing/Pooling/CS/extensions/ResourceHelper.cs +++ b/framework/wcf/Extensibility/Instancing/Pooling/CS/extensions/ResourceHelper.cs @@ -1,14 +1,11 @@ // Copyright (c) Microsoft Corporation. All Rights Reserved. -using System; -using System.Globalization; -using System.Resources; using System.Reflection; -using System.Threading; +using System.Resources; namespace Microsoft.ServiceModel.Samples { - class ResourceHelper + internal class ResourceHelper { // Gets the string associated with the specified key from the resource file public static string GetString(string key) diff --git a/framework/wcf/Extensibility/Instancing/Pooling/CS/service/App.config b/framework/wcf/Extensibility/Instancing/Pooling/CS/service/App.config index 9c09fa32fb7..dcbfbd490f8 100644 --- a/framework/wcf/Extensibility/Instancing/Pooling/CS/service/App.config +++ b/framework/wcf/Extensibility/Instancing/Pooling/CS/service/App.config @@ -19,4 +19,4 @@ - + diff --git a/framework/wcf/Extensibility/Instancing/Pooling/CS/service/Service.cs b/framework/wcf/Extensibility/Instancing/Pooling/CS/service/Service.cs index 7daf96dd3b6..8cddcb41510 100644 --- a/framework/wcf/Extensibility/Instancing/Pooling/CS/service/Service.cs +++ b/framework/wcf/Extensibility/Instancing/Pooling/CS/service/Service.cs @@ -1,7 +1,6 @@ // Copyright (c) Microsoft Corporation. All Rights Reserved. using System; -using System.ServiceModel.Channels; using System.ServiceModel; using System.Threading; diff --git a/framework/wcf/Extensibility/Instancing/Pooling/CS/service/Service.csproj b/framework/wcf/Extensibility/Instancing/Pooling/CS/service/Service.csproj index 86940dc8291..d35b83b80fb 100644 --- a/framework/wcf/Extensibility/Instancing/Pooling/CS/service/Service.csproj +++ b/framework/wcf/Extensibility/Instancing/Pooling/CS/service/Service.csproj @@ -1,37 +1,17 @@  - + + Debug AnyCPU 8.0.50727 - 2.0 {AE58B0A0-F124-4ABE-8543-42110CFA8959} Exe Properties Microsoft.ServiceModel.Samples Service - v4.0 - - - - - 2.0 + v4.6.2 publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - false - true - true @@ -71,29 +51,7 @@ Extensions - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 3.5 SP1 - true - - - False - Microsoft Visual Basic PowerPacks 10.0 - true - - - False - Windows Installer 3.1 - true - - - + - \ No newline at end of file +