Implementing pooling for .NET 6 and higher
The instructions in this topic apply primarily to pooling with .NET 6 and higher. If you are using .NET Framework, you can either use these instructions or implement COM+ pooling. For the latter, see Implementing COM+ pooling for .NET Framework. |
This topic offers an example of how to create and configure a pool on the client machine and how to use the pooling support methods using an ASP.NET application.
Implementation overview
Follow these steps:
1. | (optional, but recommended) Write pooling support methods (Activate, Initialize, etc.) and add them to the SMC. See Using the pooling support methods. |
2. | Create your assembly. If you wrote pooling support methods, include the interface that contains them in the assembly. See Building an assembly with MSBuild. |
3. | Write your client-side code. See Writing code that uses pooled objects. |
4. | Define the pool characteristics. This is where you specify such things as the xfServerPlus host name and port and is usually done with an appsettings.json file. See Defining pool characteristics. |
5. | Define a pool policy, a class that defines the overall configuration of the pool, including the information from the appsettings.json file and whether the pool environment uses any of the pooling support methods. See Defining a pool policy. |
6. | Create a pool service (i.e., start the pool). See Creating a pool service. |
7. | Use pooled objects. See Using pooled objects. |
Defining pool characteristics
You will need to define the following information for your object pool:
- xfServerPlus host system (name or IP address)
- xfServerPlus port (2356 or some other custom value)
- Maximum pool size
- Maximum idle pool size (This defines how small the pool will be allowed to get once it’s started. With this type of pooling there is not an initial minimum pool size like there is with COM+ pooling.)
For an ASP.NET application, we recommend that you specify these settings in an appsettings.json file. In the following example, the four settings xfServerPlusHost, xfServerPlusPort, PoolMaxSize, and PoolMaxIdle represent the pool characteristics.
{ "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" } }, "AllowedHosts": "*", "xfServerPlusHost": "localhost", "xfServerPlusPort": 2356, "PoolMaxSize": 4, "PoolMaxIdle": 2 }
Defining a pool policy
A pool policy determines the xfServerPlus instance that objects in the pool will connect to, as well as which (if any) pooling support methods will be used. We recommend that you implement a helper method that can be called to create and return an instance of the pool policy object.
An example for ASP.NET is below. In this example, SynergyMethods represents the name of the class in your assembly that you wish to pool. Notice how default values for the pool characteristics are provided, but can be overridden by passing in different values via parameters.
using Synergex.xfnlnet; using SynergyClient; namespace WebClientApp { internal class SynergyMethodsPoolPolicyHelper { public static BlockingPooledObjectPolicy<SynergyMethods> CreatePolicy( string host = "localhost", int port = 2356, int poolMaxSize = 4, int poolMaxIdle = 2) { // SynergyMethods interface has all 5 pooling support methods return new BlockingPooledObjectPolicy<SynergyMethods>(poolMaxSize, poolMaxIdle) { //The Initialize action should ALWAYS be declared Initialize = (poolObject) => { poolObject.connect(host, port); //TODO: Comment out the next line if there is no Initialize method in the interface poolObject.Initialize(); }, //The Cleanup action should ALWAYS be declared Cleanup = (poolObject) => { //TODO: Comment out the next line if there is no Cleanup method in the interface poolObject.Cleanup(); poolObject.disconnect(); }, //TODO: Remove if there is no Activate method in the interface Activate = (poolObject) => { poolObject.Activate(); }, //TODO: Remove if there is no Deactivate method in the interface Deactivate = (poolObject) => { poolObject.Deactivate(); }, //TODO: Remove if there is no CanBePooled method in the interface CanBePooled = (poolObject) => { return poolObject.CanBePooled(); } }; } } }
Creating a pool service
The next step is to create an instance of a pool of your client objects and to register it with the Dependency Injection environment as a service that other (Controller) classes can request. In ASP.NET Core applications, this type of configuration generally takes place in the ConfigureServices method of the Startup class. You will need to add code to that method, as shown in the example below.
In this example, SynergyMethods represents the name of the class in your xfNetLink .NET assembly that is being pooled, and DefaultObjectPool is the name of the pool you create. Notice that the code is calling the pooling policy helper method that you created earlier, and the values for the pool configuration settings are obtained via Configuration.GetValue which reads them from the appsettings.json file.
//Create an object pool and make it available via Dependency Injection services.AddSingleton<ObjectPool<SynergyMethods>>( new DefaultObjectPool<SynergyMethods>( SynergyMethodsPoolPolicyHelper.CreatePolicy( Configuration.GetValue<string>("xfServerPlusHost"), Configuration.GetValue<int>("xfServerPlusPort"), Configuration.GetValue<int>("PoolMaxSize"), Configuration.GetValue<int>("PoolMaxIdle") ) ) );
Using pooled objects
Now that you have a pool of your client objects available for use in your application, all that remains is to obtain a copy of the pool and use it to obtain pooled instances of your client objects whenever your application needs to interact with the xfServerPlus methods. Here is an example of doing that in an ASP.NET MVC Controller class.
1. | The first step is to define a class variable to represent an instance of your pool: |
private ObjectPool<SynergyMethods> _pool;
2. | Next, in the Controller’s constructor method, add a parameter to receive an instance of the pool and save the object reference to the class variable you defined earlier. For example: |
public HomeController(ILogger<HomeController> logger, ObjectPool<SynergyMethods> pool)
{
_logger = logger;
_pool = pool; //Instance of pool from Dependency Injection
}
3. | Now that you have an instance of the pool, you can use it to obtain a client object from the pool whenever you need to make a call to an xfServerPlus method. Note how the try/finally construct is used to guarantee that the client object is always returned to the pool, regardless of the outcome of any particular method call. Once it’s returned, if there is a CanBePooled method, it is used to determine whether the object remains in the pool or is discarded. |
//Get a client object from the pool
SynergyMethods client = _pool.Get();
try
{ //Use the object to make an xfServerPlus method call
ArrayList customers;
client.GetAllCustomers(out customers);
//Use the object to make a second xfServerPlus method call
Customer c = (Customer)customers[1];
ArrayList contacts;
client.GetCustomerContacts(c.Customer_id, out contacts);
}
finally
{
//When done, return the object to the pool
_pool.Return(client);
}