Error while adding second level cache in Nhibernate configuration .Net Core 6

306 Views Asked by At

I have migrated my legacy Asp.Net project to a Asp.Net Core 6 solution. I try to build the NHibernate session factory by adding a second level cache provider ('CoreDistributedCacheProvider') but I am getting the following error:

InvalidOperationException: CacheFactory is null, cannot build a distributed cache without a cache factory. Please provide coredistributedcache configuration section with a factory-class attribute or setCacheFactory before building a session factory.

I used to have a 'Web.Config' file containing the related configuration section mentioned in the error above but after the migration there is only 'appsettings.json' file. I am new to .Net Core concepts and I would like to give me a hint on how to define the appropriate config.

There is an option to set the config programmatically according to documentation(https://nhibernate.info/doc/nhibernate-reference/caches.html#NHibernate.Caches.ConfigurationProvider) using something like this:

ConfigurationProvider.SetConfiguration(yourConfig);

but how can I define and read the xml formatted settings config on a .Net Core 6 app?

Nhibernate configuation:

FluentConfiguration fluentConfiguration = Fluently.Configure()
                            .Database(PostgreSQLConfiguration.Standard.Dialect<MySQL5Dialect>().ConnectionString(x => 
                            x.Host("**")
                            .Port(5432)
                            .Database("**")
                            .Username("**")
                            .Password("**")
                            ))
                            .Mappings(m => m.FluentMappings.AddFromAssembly(assembly).Conventions.Add(new DatabaseConvention())).Cache(o => o.UseSecondLevelCache().UseQueryCache().ProviderClass<CoreDistributedCacheProvider>());

Web.config legacy config:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="coredistributedcache"
      type="NHibernate.Caches.CoreDistributedCache.CoreDistributedCacheSectionHandler,
            NHibernate.Caches.CoreDistributedCache" />
  </configSections>

  <coredistributedcache
    factory-class="NHibernate.Caches.CoreDistributedCache.Memory.MemoryFactory,
                   NHibernate.Caches.CoreDistributedCache.Memory">
    <properties>
      <property name="expiration-scan-frequency">00:10:00</property>
      <property name="size-limit">1048576</property>
      <property name="cache.serializer"
        >NHibernate.Caches.Util.JsonSerializer.JsonCacheSerializer, NHibernate.Caches.Util.JsonSerializer</property>
    </properties>
    <cache region="foo" expiration="500" sliding="true" />
    <cache region="noExplicitExpiration" sliding="true" />
    <cache region="specificSerializer"
      serializer="NHibernate.Caches.Common.BinaryCacheSerializer, NHibernate.Caches.Common" />
  </coredistributedcache>
</configuration>
1

There are 1 best solutions below

0
Roman Artiukhin On

You can keep it in xml (as embedded resource or as file copied to output dir or your choice) and load it with the following custom ConfigurationProvider:

//Call it before session factory is created
ConfigurationProvider.Current = new CoreDistributedCacheXmlConfiguration(xmlCacheConfig);


public class CoreDistributedCacheXmlConfiguration : ConfigurationProvider
{
    private readonly string _xmlCacheConfig;

    public CoreDistributedCacheXmlConfiguration(string xmlCacheConfig)
    {
        _xmlCacheConfig = xmlCacheConfig;
    }

    public override CacheConfig GetConfiguration()
    {
        var xmlDocument = new XmlDocument();
        xmlDocument.LoadXml(_xmlCacheConfig);
        return (CacheConfig)new CoreDistributedCacheSectionHandler().Create(null, null, xmlDocument.DocumentElement);
    }
}

Where xmlCacheConfig is xml loaded as string. Only coredistributedcache xml element is required:

//Example with hardcoded C# 11 Raw string literal
string xmlCacheConfig =
    """
        <?xml version="1.0" encoding="utf-8" ?>
        <coredistributedcache
            factory-class="NHibernate.Caches.CoreDistributedCache.Memory.MemoryFactory,
                           NHibernate.Caches.CoreDistributedCache.Memory">
            <properties>
              <property name="expiration-scan-frequency">00:10:00</property>
              <property name="size-limit">1048576</property>
              <property name="cache.serializer"
                >NHibernate.Caches.Util.JsonSerializer.JsonCacheSerializer, NHibernate.Caches.Util.JsonSerializer</property>
            </properties>
            <cache region="foo" expiration="500" sliding="true" />
            <cache region="noExplicitExpiration" sliding="true" />
            <cache region="specificSerializer"
              serializer="NHibernate.Caches.Common.BinaryCacheSerializer, NHibernate.Caches.Common" />
          </coredistributedcache>
        """;