One big goal of CacheManager is to make it easy to work with different cache systems, but at the same time it should be flexible to adopt to different needs. Therefore, the configuration is a pretty important part of CacheManager.

You can choose from three different ways to configure CacheManager:

  • By code, using the CacheFactory or ConfigurationBuilder
  • By using Microsoft.Extensions.Configuration
  • Via web/app.config using the CacheManager's configuration section

CacheFactory

To create a Cache Manager instance, you can use the CacheFactory class which has two different methods:

Build can be used to create a new cache configuration using a fluent configuration builder.

var cache = CacheFactory.Build(settings => settings
       .WithUpdateMode(CacheUpdateMode.Up)
       .WithSystemRuntimeCacheHandle()
	       .WithExpiration(ExpirationMode.Sliding, TimeSpan.FromSeconds(10)));

FromConfiguration takes either the CacheManagerConfiguration object or a nameed CacheManager configured in the app/web.config file of the application.

var cache = CacheFactory.FromConfiguration<string>("cacheName")

Optionally, the name of the CacheManager instance and the name of the configured cache can be defined separated, to create multiple instances from the same configuration. The cache or cache handle name in general is optional. It can be used for debugging/logging purposes though.

var cache = CacheFactory.FromConfiguration<int>("cacheInstanceName", "configuredCacheName")

If you want to separate the creation of the configuration object and the creation of the Cache Manager instance, use the ConfigurationBuilder to create the configuration.

var cfg = ConfigurationBuilder.BuildConfiguration(settings =>
	{
		settings.WithUpdateMode(CacheUpdateMode.Up)
               .WithSystemRuntimeCacheHandle("handleName")
				.WithExpiration(ExpirationMode.Sliding, TimeSpan.FromSeconds(10));
	});

var cache = CacheFactory.FromConfiguration<string>("cacheName", cfg);
cache.Add("key", "value");

Then, you can reuse the configuration and create another Cache Manager instance for a different type for example:

var cache = CacheFactory.FromConfiguration<int>("numbers", cfg);

ConfigurationBuilder

The ConfigurationBuilder has several static methods to initialize a CacheManagerConfiguration, to build a new one or load one from App.config. But it can also be instantiated to create new configurations or edit existing ones.

The same extension methods will be available as usual, the difference to the static method is, that you have to call Build at some point to exit the configuration context and return the new configuration object.

var config = new ConfigurationBuilder()
    .WithSystemRuntimeCacheHandle()
        .EnableStatistics()
    .Build();

// An existing configuration can be modified, too
var changedConfig = new ConfigurationBuilder(config)
    .WithMicrosoftLogging(f => f.AddConsole())
    .Build();

The CacheManagerConfiguration also has a new property Builder. Calling config.Builder is the same as if you would call new ConfigurationBuilder(config).

var config = new ConfigurationBuilder()
    .WithSystemRuntimeCacheHandle()
        .EnableStatistics()
    .Build();

// An existing configuration can be modified, too
var changedConfig = config
    .Builder
    .WithMicrosoftLogging(f => f.AddConsole())
    .Build();

Instantiate BaseCacheManager

Instead of using the CacheFactory to create a cache instance, you can also create a new CacheManager instance by instantiating the BaseCacheManager class directly and pass in a CacheManagerConfiguration.

var config = new ConfigurationBuilder()
    .WithSystemRuntimeCacheHandle()
    .Build();

var cache = new BaseCacheManager<string>(config);

Microsoft.Extensions.Configuration

With the new Microsoft.Extensions.Configuration framework, Microsoft introduced a great way to handle custom configurations from many different sources, a plain JSON file for example.

JSON Schema

To making configuration via JSON files really easy, CacheManager now also has a JSON schema file, located at http://cachemanager.michaco.net/schemas/cachemanager.json.

With this schema, it is very easy and convenient if you create new configuration files in Visual Studio, because it gives full auto completion and validation on each element.

Just add a new JSON file to your project and add the "$schema" directive to it:

{
  "$schema": "http://cachemanager.michaco.net/schemas/cachemanager.json#"
}

from there on, you should see validation messages in the error window of Visual Studio. First one will be Missing required property cacheManagers, which means that you have to have a cacheManagers property of type array... and so on. Here is a complete example:

{
  "$schema": "http://cachemanager.michaco.net/schemas/cachemanager.json#",
  "redis": [
    {
      "key": "redisConnection",
      "connectionString": "localhost:6379,allowAdmin=true"
    }
  ],
  "cacheManagers": [
    {
      "maxRetries": 1000,
      "name": "cachename",
      "retryTimeout": 100,
      "updateMode": "Full",
      "backplane": {
        "key": "redisConnection",
        "knownType": "Redis",
        "channelName": "test"
      },
      "loggerFactory": {
        "knownType": "Microsoft"
      },
      "serializer": {
        "knownType": "Json"
      },
      "handles": [
        {
          "knownType": "SystemRuntime",
          "enablePerformanceCounters": true,
          "enableStatistics": true,
          "expirationMode": "Absolute",
          "expirationTimeout": "0:0:23",
          "isBackplaneSource": false,
          "name": "sys cache"
        },
        {
          "knownType": "Redis",
          "key": "redisConnection",
          "isBackplaneSource": true
        }
      ]
    }
  ]
}

Known Types

As you might have noticed in the example above, there are a lot of knownType properties. Known types are there to make configuration in text files easier and less error prone. Usually, you would have to declare the fully qualified type of a cache handle, logger factory or serializer.

With knownType you can select from a predefined set of types which are known to CacheManager. For example, instead of defining the type of a Redis cache handle and writing CacheManager.Redis.RedisCacheHandle`1, CacheManager.StackExchange.Redis just define knownType: Redis which gets evaluated to the full type name.

Hint: If you specify any type or knownType but didn't install the corresponding NuGet package which contains that type, you'll get an error at the point you instantiate a CacheManager.

Loading Configuration from JSON file

Loading a configuration via Microsoft's API works slightly different than the regular ConfigurationBuilder/Factory approach. You will have to build an IConfiguration first, and then call the new extension method GetCacheConfiguration to retrieve a CacheManagerConfiguration.

First create the Microsoft.Extensions.Configuration.IConfiguration

var builder = new Microsoft.Extensions.Configuration.ConfigurationBuilder()
    .AddJsonFile("cache.json");

this.Configuration = builder.Build();

and then call

var cacheConfiguration = 
    this.Configuration.GetCacheConfiguration();

The default overload without parameters assumes that there is only one CacheManagerConfiguration defined in the cacheManagers section of the JSON file.

If you have multiple managers defined, specify the name of the manager you want to load:

var cacheConfiguration = 
    this.Configuration.GetCacheConfiguration("cachename")
        .Builder
        .WithMicrosoftLogging(f =>
        {
            f.AddDebug(LogLevel.Information);
        })
        .Build();

You can also get all CacheManagerConfigurations by calling .GetCacheConfigurations().

Configuration Section

The CacheManager configuration section is only available in full .NET framework projects where System.Configuration.ConfigurationManager is available.

The section has two main parts, the managers collection which is used to configure one or more CacheManagers identified by name (this name can be used in conjunction with CacheFactory.FromConfiguration).

And the cacheHandles collection which lists the available (installed) cache handle types. Those will be used by referencing (via ref) the id to form a cache in the managers collection.

<cacheManager xmlns="http://cachemanager.michaco.net/schemas/CacheManagerCfg.xsd">
  <managers>
    <cache name="cacheName" updateMode="Up" enableStatistics="false" enablePerformanceCounters="false">
      <handle name="handleName" ref="systemRuntimeHandle" expirationMode="Absolute" timeout="50s"/>
    </cache>
  </managers>
  <cacheHandles>
    <handleDef  id="systemRuntimeHandle" type="CacheManager.SystemRuntimeCaching.MemoryCacheHandle`1, CacheManager.SystemRuntimeCaching"
        defaultExpirationMode="Sliding" defaultTimeout="5m"/>
  </cacheHandles>
</cacheManager>

The cacheHandles' elements can be defined with default values for expiration mode and timeout. It can be overridden by the handle element though. The type must a Type extending from BaseCacheHandle, it also has to be configured as open generic xyzHandle`1 at this point.

Hint To make configuration via .config file easier, enable intellisense by adding the xmlns attribute to he cacheManagers section and add the CacheManagerCfg.xsd file to your solution. See also this answer on stackoverflow

The CacheManager and Redis configuration xml schema files can be found here: