Implementing pooling for .NET Core and .NET 5

Note

The instructions in this topic apply primarily to pooling with .NET Core and .NET 5 or 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:

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);
}