【发布时间】:2010-07-13 02:31:39
【问题描述】:
更新:我现在已经正确实施了。有关更多信息,请参阅我的blog post。
我正在尝试使用带有 NHibernate 的 AppFabric 作为我的二级缓存提供程序,但我收到以下错误:ErrorCode:Initialization: 无法联系缓存服务。联系管理员并参考产品帮助文档了解可能的原因。
我认为问题在于我在 web.config 中的配置:
<section name="dcacheClient"
type="Microsoft.ApplicationServer.Caching.DataCacheClientSection, Microsoft.ApplicationServer.Caching.Core"
allowLocation="true"
allowDefinition="Everywhere"/>
...
<dcacheClient deployment="routing" localCache="False">
<localCache isEnabled="false" sync="TimeoutBased" ttlValue="300" />
<hosts>
<host name="localhost" cachePort="22233" cacheHostName="AppFabricCachingService" />
</hosts>
</dcacheClient>
我已经下载了 NHibernate.Caches 源代码来尝试找出问题所在以及调用 GetCache 方法时 VelocityClient 构造函数中抛出的异常:
public VelocityClient(string regionName, IDictionary<string, string> properties)
{
region = regionName.GetHashCode().ToString(); //because the region name length is limited
var cacheCluster = new CacheFactory();
cache = cacheCluster.GetCache(CacheName);
try
{
cache.CreateRegion(region, true);
}
catch (CacheException) {}
}
如果我向 cacheCluster 变量添加一个监视,我可以找到一个 _servers 私有变量,它有一个 System.Data.Caching.EndpointID,它的 MyURI 属性设置为 net.tcp://localhost:22234/AppFabricCachingServive假设来自 web.config 中的配置。
如果您不知道问题的确切原因,但对如何解决此问题有一些想法,那也将不胜感激。
其他信息
我从命令Get-CacheHostConfig -HostName tn-staylor-02 -CachePort 22233得到以下结果:
HostName : tn-staylor-02
ClusterPort : 22234
CachePort : 22233
ArbitrationPort : 22235
ReplicationPort : 22236
Size : 3001 MB
ServiceName : AppFabricCachingService
HighWatermark : 90%
LowWatermark : 70%
IsLeadHost : True
所以我认为我在 web.config 中配置的值是可以的。
谷歌搜索这个问题并首先研究如何设置 AppFabric,我遇到了两种稍微不同的方式来配置 web.config 中的缓存。我在上面描述的方式以及 Hanselman 在他的AppFabric blog post中的方式
我实际上是这样开始的,但是我得到了以下错误,这就是我如何配置它现在的方式:
ErrorCode:应用程序配置文件中未指定“dcacheClient”标签。在配置文件中指定有效的标签。
VelocityClient 中抛出的异常的完整堆栈跟踪:
发生 System.Data.Caching.CacheException Message="ErrorCode:\"dcacheClient\" 标签未在应用程序配置文件中指定。请在配置文件中指定有效标签。" 来源="CacheBaseLibrary" 错误代码="ERRCMC0004" 堆栈跟踪: 在 System.Data.Caching.ClientConfigFile.ThrowException(字符串错误代码,字符串参数) 在 System.Data.Caching.ClientConfigReader.GetDeployementMode() 在 System.Data.Caching.ClientConfigurationManager.InitializeDepMode(ClientConfigReader cfr) 在 System.Data.Caching.ClientConfigurationManager.Initialize(字符串路径) 在 System.Data.Caching.ClientConfigurationManager..ctor() 在 System.Data.Caching.CacheFactory.InitCacheFactory() 在 System.Data.Caching.CacheFactory.GetCache(字符串缓存名称) 在 C:\Source\Projects\NHibernate.contrib\trunk\src\NHibernate.Caches\Velocity\NHibernate.Caches.Velocity\VelocityClient 中的 NHibernate.Caches.Velocity.VelocityClient..ctor(字符串 regionName,IDictionary`2 属性)。 CS:第 67 行 内部异常:
编辑:根据@PhilPursglove 的要求添加了来自get-cachehost 的输出
get-cachehost 的输出:
HostName : CachePort Service Name Service Status Version Info
-------------------- ------------ -------------- ------------
tn-staylor-02:22233 AppFabricCachingService UP 1 [1,1][1,1]
解决方案:@PhilPursglove 是正确的。 NHibernate 速度提供程序使用旧的 dll,因此升级它们并进行一些代码更改解决了我的问题。我想我会在这里包含我的完整解决方案。
- 从https://nhcontrib.svn.sourceforge.net/svnroot/nhcontrib/trunk 的 SVN 存储库下载了 NHibernate.contrib 源代码
- 打开了 NHibernate.Caches.Everything 解决方案并从 NHibernate.Caches.Velocity 项目中删除了对旧速度 dll 的引用。
- 添加了对我安装 App Fabric 时安装的 App Fabric dll 的引用。这不是在 GAC 中添加对程序集的引用的正常情况,而是 this article describes how to do it。
- 添加新引用意味着 VelocityClient 类不再编译。在this 的一点帮助下,我想出了下面的 VelocityClient.cs 版本。
- 我在我的项目中添加了对新版本 NHibernate.Caches.Velocity 的引用,对我的配置进行了以下更改,一切正常。
VelocityClient.cs
using System;
using System.Collections.Generic;
using Microsoft.ApplicationServer.Caching;
using log4net;
using NHibernate.Cache;
using CacheException = Microsoft.ApplicationServer.Caching.DataCacheException;
using CacheFactory = Microsoft.ApplicationServer.Caching.DataCacheFactory;
namespace NHibernate.Caches.Velocity
{
public class VelocityClient : ICache
{
private const string CacheName = "nhibernate";
private static readonly ILog log;
private readonly DataCache cache;
private readonly string region;
private Dictionary<string, DataCacheLockHandle> locks = new Dictionary<string, DataCacheLockHandle>();
static VelocityClient()
{
log = LogManager.GetLogger(typeof (VelocityClient));
}
public VelocityClient() : this("nhibernate", null) {}
public VelocityClient(string regionName) : this(regionName, null) {}
public VelocityClient(string regionName, IDictionary<string, string> properties)
{
region = regionName.GetHashCode().ToString(); //because the region name length is limited
var cacheCluster = new CacheFactory();
cache = cacheCluster.GetCache(CacheName);
try
{
cache.CreateRegion(region);
}
catch (CacheException) {}
}
#region ICache Members
public object Get(object key)
{
if (key == null)
{
return null;
}
if (log.IsDebugEnabled)
{
log.DebugFormat("fetching object {0} from the cache", key);
}
DataCacheItemVersion version = null;
return cache.Get(key.ToString(), out version, region);
}
public void Put(object key, object value)
{
if (key == null)
{
throw new ArgumentNullException("key", "null key not allowed");
}
if (value == null)
{
throw new ArgumentNullException("value", "null value not allowed");
}
if (log.IsDebugEnabled)
{
log.DebugFormat("setting value for item {0}", key);
}
cache.Put(key.ToString(), value, region);
}
public void Remove(object key)
{
if (key == null)
{
throw new ArgumentNullException("key");
}
if (log.IsDebugEnabled)
{
log.DebugFormat("removing item {0}", key);
}
if (Get(key.ToString()) != null)
{
cache.Remove(region, key.ToString());
}
}
public void Clear()
{
cache.ClearRegion(region);
}
public void Destroy()
{
Clear();
}
public void Lock(object key)
{
DataCacheLockHandle lockHandle = null;
if (Get(key.ToString()) != null)
{
try
{
cache.GetAndLock(key.ToString(), TimeSpan.FromMilliseconds(Timeout), out lockHandle, region);
locks.Add(key.ToString(), lockHandle);
}
catch (CacheException) {}
}
}
public void Unlock(object key)
{
DataCacheLockHandle lockHandle = null;
if (Get(key.ToString()) != null)
{
try
{
if (locks.ContainsKey(key.ToString()))
{
cache.Unlock(key.ToString(), locks[key.ToString()], region);
locks.Remove(key.ToString());
}
}
catch (CacheException) {}
}
}
public long NextTimestamp()
{
return Timestamper.Next();
}
public int Timeout
{
get { return Timestamper.OneMs * 60000; } // 60 seconds
}
public string RegionName
{
get { return region; }
}
#endregion
}
}
NHibernate.config:
...
<property name="cache.provider_class">NHibernate.Caches.Velocity.VelocityProvider, NHibernate.Caches.Velocity</property>
<property name="cache.use_second_level_cache">true</property>
<property name="cache.use_query_cache">true</property>
...
web.config
...
<section name="dataCacheClient"
type="Microsoft.ApplicationServer.Caching.DataCacheClientSection, Microsoft.ApplicationServer.Caching.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
allowLocation="true"
allowDefinition="Everywhere"/>
...
<dataCacheClient>
<!-- cache host(s) -->
<hosts>
<host
name="localhost"
cachePort="22233"/>
</hosts>
</dataCacheClient>
...
我没有对我的 App Fabric 配置或任何其他内容进行任何进一步的更改。
【问题讨论】:
-
您的缓存是否在运行?
get-cachehost的输出是什么? -
@PhilPursglove,是的,缓存正在运行,我已将 get-cachehost 的输出添加到原始问题中。感谢您抽出宝贵时间发表评论
-
很高兴你修好了!您应该将这些 NHibernate 更改提交回主干,以免其他人遇到此问题。
-
@s1mm0t 我正在考虑使用 AppFabric 作为二级缓存。这对你来说效果好吗?
-
是的,它运行良好。我一直想写一篇关于我的经历的博文
标签: nhibernate appfabric