[英]Dynamics CRM Online Object caching not caching correctly
我有一个要求,我们需要一个插件来从外部系统检索会话ID并将其缓存一段时间。 我在实体上使用一个字段来测试会话是否实际被缓存。 当我刷新CRM表单几次时,从输出中可以看出,同一个键有四个版本(在任何时候一致)。 我已经尝试清除缓存并再次测试,但结果仍然相同。
任何帮助表示感谢,提前谢谢。
每次刷新页面时的输出:
20170511_125342:1:55a4f7e6-a1d7-e611-8100-c4346bc582c0
20170511_125358:1:55a4f7e6-a1d7-e611-8100-c4346bc582c0
20170511_125410:1:55a4f7e6-a1d7-e611-8100-c4346bc582c0
20170511_125342:1:55a4f7e6-a1d7-e611-8100-c4346bc582c0
20170511_125437:1:55a4f7e6-a1d7-e611-8100-c4346bc582c0
20170511_125358:1:55a4f7e6-a1d7-e611-8100-c4346bc582c0
20170511_125358:1:55a4f7e6-a1d7-e611-8100-c4346bc582c0
20170511_125437:1:55a4f7e6-a1d7-e611-8100-c4346bc582c0
为此,我实现了以下代码:
public class SessionPlugin : IPlugin
{
public static readonly ObjectCache Cache = MemoryCache.Default;
private static readonly string _sessionField = "new_sessionid";
#endregion
public void Execute(IServiceProvider serviceProvider)
{
var context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
try
{
if (context.MessageName.ToLower() != "retrieve" && context.Stage != 40)
return;
var userId = context.InitiatingUserId.ToString();
// Use the userid as key for the cache
var sessionId = CacheSessionId(userId, GetSessionId(userId));
sessionId = $"{sessionId}:{Cache.Select(kvp => kvp.Key == userId).ToList().Count}:{userId}";
// Assign session id to entity
var entity = (Entity)context.OutputParameters["BusinessEntity"];
if (entity.Contains(_sessionField))
entity[_sessionField] = sessionId;
else
entity.Attributes.Add(new KeyValuePair<string, object>(_sessionField, sessionId));
}
catch (Exception e)
{
throw new InvalidPluginExecutionException(e.Message);
}
}
private string CacheSessionId(string key, string sessionId)
{
// If value is in cache, return it
if (Cache.Contains(key))
return Cache.Get(key).ToString();
var cacheItemPolicy = new CacheItemPolicy()
{
AbsoluteExpiration = ObjectCache.InfiniteAbsoluteExpiration,
Priority = CacheItemPriority.Default
};
Cache.Add(key, sessionId, cacheItemPolicy);
return sessionId;
}
private string GetSessionId(string user)
{
// this will be replaced with the actual call to the external service for the session id
return DateTime.Now.ToString("yyyyMMdd_hhmmss");
}
}
Daryl在这里对此进行了很大的解释: https : //stackoverflow.com/a/35643860/7708157
基本上你不是每个CRM系统都有一个MemoryCache实例,你的代码只是证明每个插件都有多个app域,所以即使存储在这个插件中的静态变量也可以有多个值,你不能依赖它们。 在MSDN上没有可以解释sanboxing如何工作的文档(特别是在这种情况下的app域),但肯定使用静态变量并不是一个好主意。当然,如果你在线处理,你不能确定是否只有单个前端服务器或其中许多服务器(这也会导致此类行为)
类级变量应限于配置信息。 不支持使用您正在执行的类级变量。 在CRM Online中,由于多个Web前端,可以通过插件类的不同实例在不同服务器上执行特定请求而不是另一个请求。 总的来说,假设CRM是无状态的,除非持久化和检索,否则在插件执行之间不应该假设是连续的。
根据SDK:
应该将插件的Execute方法编写为无状态,因为每次调用插件时都不会调用构造函数。 此外,多个系统线程可以同时执行插件。 所有每个调用状态信息都存储在上下文中,因此您不应使用全局变量或尝试将任何数据存储在成员变量中,以便在下一个插件调用期间使用,除非该数据是从提供给构造函数的配置参数中获取的。
参考: https : //msdn.microsoft.com/en-us/library/gg328263.aspx
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.